From: Linus Torvalds Date: Tue, 2 Dec 2025 01:32:07 +0000 (-0800) Subject: Merge tag 'vfs-6.19-rc1.fd_prepare.fs' of git://git.kernel.org/pub/scm/linux/kernel... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1b5dd29869b1e63f7e5c37d7552e2dcf22de3c26;p=thirdparty%2Flinux.git Merge tag 'vfs-6.19-rc1.fd_prepare.fs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs 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() ... --- 1b5dd29869b1e63f7e5c37d7552e2dcf22de3c26 diff --cc include/linux/cleanup.h index 19c7e475d3a4d,361104bcfe925..b8bd2f15f91f6 --- a/include/linux/cleanup.h +++ b/include/linux/cleanup.h @@@ -290,16 -294,18 +294,19 @@@ static inline class_##_name##_t class_# class_##_name##_t var __cleanup(class_##_name##_destructor) = \ class_##_name##_constructor + #define CLASS_INIT(_name, _var, _init_expr) \ + class_##_name##_t _var __cleanup(class_##_name##_destructor) = (_init_expr) + -#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 __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 83d9466710d69,d3a588d0dcf61..56e811f9e5fa3 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@@ -892,15 -892,36 +892,35 @@@ static int prepare_open(struct dentry * return inode_permission(&nop_mnt_idmap, d_inode(dentry), acc); } + static struct file *mqueue_file_open(struct filename *name, + struct vfsmount *mnt, int oflag, bool ro, + umode_t mode, struct mq_attr *attr) + { - struct path path __free(path_put) = {}; + struct dentry *dentry; ++ struct file *file; + int ret; + - dentry = lookup_noperm(&QSTR(name->name), mnt->mnt_root); ++ dentry = start_creating_noperm(mnt->mnt_root, &QSTR(name->name)); + if (IS_ERR(dentry)) + return ERR_CAST(dentry); + - path.dentry = dentry; - path.mnt = mntget(mnt); - - ret = prepare_open(path.dentry, oflag, ro, mode, name, attr); - if (ret) - return ERR_PTR(ret); ++ 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()); ++ } + - return 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); @@@ -908,35 -929,12 +928,10 @@@ 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; }