]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Merge tag 'vfs-6.19-rc1.fd_prepare.fs' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 2 Dec 2025 01:32:07 +0000 (17:32 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 2 Dec 2025 01:32:07 +0000 (17:32 -0800)
Pull fd prepare updates from Christian Brauner:
 "This adds the FD_ADD() and FD_PREPARE() primitive. They simplify the
  common pattern of get_unused_fd_flags() + create file + fd_install()
  that is used extensively throughout the kernel and currently requires
  cumbersome cleanup paths.

  FD_ADD() - For simple cases where a file is installed immediately:

      fd = FD_ADD(O_CLOEXEC, vfio_device_open_file(device));
      if (fd < 0)
          vfio_device_put_registration(device);
      return fd;

  FD_PREPARE() - For cases requiring access to the fd or file, or
  additional work before publishing:

      FD_PREPARE(fdf, O_CLOEXEC, sync_file->file);
      if (fdf.err) {
          fput(sync_file->file);
          return fdf.err;
      }

      data.fence = fd_prepare_fd(fdf);
      if (copy_to_user((void __user *)arg, &data, sizeof(data)))
          return -EFAULT;

      return fd_publish(fdf);

  The primitives are centered around struct fd_prepare. FD_PREPARE()
  encapsulates all allocation and cleanup logic and must be followed by
  a call to fd_publish() which associates the fd with the file and
  installs it into the caller's fdtable. If fd_publish() isn't called,
  both are deallocated automatically. FD_ADD() is a shorthand that does
  fd_publish() immediately and never exposes the struct to the caller.

  I've implemented this in a way that it's compatible with the cleanup
  infrastructure while also being usable separately. IOW, it's centered
  around struct fd_prepare which is aliased to class_fd_prepare_t and so
  we can make use of all the basica guard infrastructure"

* tag 'vfs-6.19-rc1.fd_prepare.fs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (42 commits)
  io_uring: convert io_create_mock_file() to FD_PREPARE()
  file: convert replace_fd() to FD_PREPARE()
  vfio: convert vfio_group_ioctl_get_device_fd() to FD_ADD()
  tty: convert ptm_open_peer() to FD_ADD()
  ntsync: convert ntsync_obj_get_fd() to FD_PREPARE()
  media: convert media_request_alloc() to FD_PREPARE()
  hv: convert mshv_ioctl_create_partition() to FD_ADD()
  gpio: convert linehandle_create() to FD_PREPARE()
  pseries: port papr_rtas_setup_file_interface() to FD_ADD()
  pseries: convert papr_platform_dump_create_handle() to FD_ADD()
  spufs: convert spufs_gang_open() to FD_PREPARE()
  papr-hvpipe: convert papr_hvpipe_dev_create_handle() to FD_PREPARE()
  spufs: convert spufs_context_open() to FD_PREPARE()
  net/socket: convert __sys_accept4_file() to FD_ADD()
  net/socket: convert sock_map_fd() to FD_ADD()
  net/kcm: convert kcm_ioctl() to FD_PREPARE()
  net/handshake: convert handshake_nl_accept_doit() to FD_PREPARE()
  secretmem: convert memfd_secret() to FD_ADD()
  memfd: convert memfd_create() to FD_ADD()
  bpf: convert bpf_token_create() to FD_PREPARE()
  ...

12 files changed:
1  2 
drivers/gpio/gpiolib-cdev.c
fs/autofs/dev-ioctl.c
fs/exec.c
fs/file.c
fs/namespace.c
fs/nsfs.c
fs/open.c
include/linux/cleanup.h
ipc/mqueue.c
mm/memfd.c
mm/secretmem.c
net/unix/af_unix.c

Simple merge
Simple merge
diff --cc fs/exec.c
Simple merge
diff --cc fs/file.c
Simple merge
diff --cc fs/namespace.c
Simple merge
diff --cc fs/nsfs.c
Simple merge
diff --cc fs/open.c
Simple merge
index 19c7e475d3a4d9618dd2897256b2f2f211ce5af2,361104bcfe9250d85d0e0325f6d7592af89fea11..b8bd2f15f91f6633b83cbbc53d137328781a832a
@@@ -290,16 -294,18 +294,19 @@@ static inline class_##_name##_t class_#
        class_##_name##_t var __cleanup(class_##_name##_destructor) =   \
                class_##_name##_constructor
  
 -#define scoped_class(_name, var, args)                          \
 -      for (CLASS(_name, var)(args);                           \
 -           __guard_ptr(_name)(&var) || !__is_cond_ptr(_name); \
 -           ({ goto _label; }))                                \
 -              if (0) {                                        \
 -_label:                                                         \
 -                      break;                                  \
+ #define CLASS_INIT(_name, _var, _init_expr)                             \
+         class_##_name##_t _var __cleanup(class_##_name##_destructor) = (_init_expr)
 +#define __scoped_class(_name, var, _label, args...)        \
 +      for (CLASS(_name, var)(args); ; ({ goto _label; })) \
 +              if (0) {                                   \
 +_label:                                                    \
 +                      break;                             \
                } else
  
 +#define scoped_class(_name, var, args...) \
 +      __scoped_class(_name, var, __UNIQUE_ID(label), args)
 +
  /*
   * DEFINE_GUARD(name, type, lock, unlock):
   *    trivial wrapper around DEFINE_CLASS() above specifically
diff --cc ipc/mqueue.c
index 83d9466710d6931e116b7475b0b6fb54ba618d79,d3a588d0dcf618ee3aa4b232cad16c8d1955076e..56e811f9e5fa30d32d92df5a20ebe6feaebcf2a6
@@@ -892,15 -892,36 +892,35 @@@ static int prepare_open(struct dentry *
        return inode_permission(&nop_mnt_idmap, d_inode(dentry), acc);
  }
  
 -      struct path path __free(path_put) = {};
+ static struct file *mqueue_file_open(struct filename *name,
+                                    struct vfsmount *mnt, int oflag, bool ro,
+                                    umode_t mode, struct mq_attr *attr)
+ {
 -      dentry = lookup_noperm(&QSTR(name->name), mnt->mnt_root);
+       struct dentry *dentry;
++      struct file *file;
+       int ret;
 -      path.dentry = dentry;
 -      path.mnt = mntget(mnt);
 -
 -      ret = prepare_open(path.dentry, oflag, ro, mode, name, attr);
 -      if (ret)
 -              return ERR_PTR(ret);
++      dentry = start_creating_noperm(mnt->mnt_root, &QSTR(name->name));
+       if (IS_ERR(dentry))
+               return ERR_CAST(dentry);
 -      return dentry_open(&path, oflag, current_cred());
++      ret = prepare_open(dentry, oflag, ro, mode, name, attr);
++      file = ERR_PTR(ret);
++      if (!ret) {
++              const struct path path = { .mnt = mnt, .dentry = dentry };
++              file = dentry_open(&path, oflag, current_cred());
++      }
++      end_creating(dentry);
++      return file;
+ }
  static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
                      struct mq_attr *attr)
  {
+       struct filename *name __free(putname) = NULL;;
        struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
--      struct dentry *root = mnt->mnt_root;
-       struct filename *name;
-       struct path path;
-       int fd, error;
 -      int fd;
--      int ro;
++      int fd, ro;
  
        audit_mq_open(oflag, mode, attr);
  
        if (IS_ERR(name))
                return PTR_ERR(name);
  
-       fd = get_unused_fd_flags(O_CLOEXEC);
-       if (fd < 0)
-               goto out_putname;
        ro = mnt_want_write(mnt);       /* we'll drop it in any case */
-       path.dentry = start_creating_noperm(root, &QSTR(name->name));
-       if (IS_ERR(path.dentry)) {
-               error = PTR_ERR(path.dentry);
-               goto out_putfd;
-       }
-       path.mnt = mnt;
-       error = prepare_open(path.dentry, oflag, ro, mode, name, attr);
-       if (!error) {
-               struct file *file = dentry_open(&path, oflag, current_cred());
-               if (!IS_ERR(file))
-                       fd_install(fd, file);
-               else
-                       error = PTR_ERR(file);
-       }
- out_putfd:
-       if (error) {
-               put_unused_fd(fd);
-               fd = error;
-       }
-       end_creating(path.dentry);
 -      inode_lock(d_inode(root));
+       fd = FD_ADD(O_CLOEXEC, mqueue_file_open(name, mnt, oflag, ro, mode, attr));
 -      inode_unlock(d_inode(root));
        if (!ro)
                mnt_drop_write(mnt);
- out_putname:
-       putname(name);
        return fd;
  }
  
diff --cc mm/memfd.c
Simple merge
diff --cc mm/secretmem.c
Simple merge
Simple merge