* [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE()
@ 2025-11-18 15:48 Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 01/18] file: add FD_PREPARE() Christian Brauner
` (17 more replies)
0 siblings, 18 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Hey,
I've been playing with an idea to allow for some flexible usage of the
get_unused_fd_flags() + create file + fd_install() pattern that's used
quite extensively.
How callers allocate files is really heterogenous so it's not really
convenient to fold them into a single class. It's possibe to split them
into subclasses like for anon inodes. I think that's not necessarily
nice as well so my take is:
FD_PREPARE(fdprep, open_flag, file_open_handle(&path, open_flag));
if (fd_prepare_failed(fdprep))
return fd_prepare_error(fdprep);
return fd_publish(fdprep);
or
FD_PREPARE(fdprep, 0, dentry_open(&path, hreq->oflags, cred));
dput(dentry);
if (fd_prepare_failed(fdprep))
return fd_prepare_error(fdprep);
if (S_ISREG(inode->i_mode)) {
struct file *filp = fd_prepare_file(fdprep);
filp->f_flags |= O_NOATIME;
filp->f_mode |= FMODE_NOCMTIME;
}
return fd_publish(fdprep);
That's somewhat akin to how we use wait_event() to allow for arbitrary
things to be used as a condition in it. Here we obviously expect the
function to return a struct file.
It's centered around struct fd_prepare { int fd; struct file *file; }.
FD_PREPARE() encapsulates all of allocation and cleanup logic and must
be followed by a call to fd_publish() which consumes the fd and file
otherwise they're deallocated.
It mandates a specific order for fd and file allocation which should be
fine I think.
We won't be able to convert everything to it but most cases can be made
to work with this pattern allowing to shed a bunch of cleanup code on
the way. To me it looks like it simplifies a bunch of code but it
obviously has assumptions, e.g., that it may freely consume the
reference by the file passed to it. I didn't see this as a big issue
though.
There's room for extending this in a way that you'd have subclasses for
some particularly often use patterns but as I said I'm not even sure
that's worth it.
I've converted a about 17 callers to see that they can be folded into
this pattern.
I'd like to gather early feedback. It's a draft, haven't compiled it or
tested it. Just played around with this today and thought I'd better get
yelled at early.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
Christian Brauner (18):
file: add FD_PREPARE()
fs: anon_inodes
fs: eventfd
fs: fhandle
fs: open_tree()
fs: namespace
fs: fanotify
fs: nsfs
fs: autofs
fs: eventpoll
fs: open_tree_attr()
fs: nsfs2
fs: open
fs: signalfd64
fs: timerfd
fs: userfaultfd
fs: xfs
drivers: drm_lease
drivers/gpu/drm/drm_lease.c | 44 ++++--------
fs/anon_inodes.c | 26 ++-----
fs/autofs/dev-ioctl.c | 32 +++------
fs/eventfd.c | 32 ++++-----
fs/eventpoll.c | 33 +++------
fs/fhandle.c | 30 ++++----
fs/namespace.c | 87 ++++++++---------------
fs/notify/fanotify/fanotify_user.c | 19 ++---
fs/nsfs.c | 48 +++++--------
fs/open.c | 18 ++---
fs/signalfd.c | 28 +++-----
fs/timerfd.c | 28 +++-----
fs/userfaultfd.c | 29 +++-----
fs/xfs/xfs_handle.c | 22 ++----
include/linux/cleanup.h | 22 ++++++
include/linux/file.h | 137 +++++++++++++++++++++++++++++++++++++
16 files changed, 321 insertions(+), 314 deletions(-)
---
base-commit: a71e4f103aed69e7a11ea913312726bb194c76ee
change-id: 20251118-work-fd-prepare-f415a3bf5fda
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 01/18] file: add FD_PREPARE()
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 02/18] fs: anon_inodes Christian Brauner
` (16 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
include/linux/cleanup.h | 22 ++++++++
include/linux/file.h | 137 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 159 insertions(+)
diff --git a/include/linux/cleanup.h b/include/linux/cleanup.h
index 2573585b7f06..b35b9a1da026 100644
--- a/include/linux/cleanup.h
+++ b/include/linux/cleanup.h
@@ -255,12 +255,20 @@ const volatile void * __must_check_fn(const volatile void *val)
* @exit is an expression using '_T' -- similar to FREE above.
* @init is an expression in @init_args resulting in @type
*
+ * DEFINE_CLASS_TYPE(name, type, exit):
+ * Like DEFINE_CLASS but without a constructor. Use with CLASS_INIT()
+ * for classes that need custom initialization expressions per usage.
+ *
* EXTEND_CLASS(name, ext, init, init_args...):
* extends class @name to @name@ext with the new constructor
*
* CLASS(name, var)(args...):
* declare the variable @var as an instance of the named class
*
+ * CLASS_INIT(name, var, init_expr):
+ * declare the variable @var as an instance of the named class with
+ * custom initialization expression. Use with DEFINE_CLASS_TYPE().
+ *
* Ex.
*
* DEFINE_CLASS(fdget, struct fd, fdput(_T), fdget(fd), int fd)
@@ -270,6 +278,12 @@ const volatile void * __must_check_fn(const volatile void *val)
* return -EBADF;
*
* // use 'f' without concern
+ *
+ * DEFINE_CLASS_TYPE(fd_file, struct { int fd; struct file *file; }, ...)
+ *
+ * CLASS_INIT(fd_file, ff, custom_init_expression);
+ * if (ff.fd < 0)
+ * return ff.fd;
*/
#define DEFINE_CLASS(_name, _type, _exit, _init, _init_args...) \
@@ -279,6 +293,11 @@ static inline void class_##_name##_destructor(_type *p) \
static inline _type class_##_name##_constructor(_init_args) \
{ _type t = _init; return t; }
+#define DEFINE_CLASS_TYPE(_name, _type, _exit) \
+typedef _type class_##_name##_t; \
+static inline void class_##_name##_destructor(_type *p) \
+{ _type _T = *p; _exit; }
+
#define EXTEND_CLASS(_name, ext, _init, _init_args...) \
typedef class_##_name##_t class_##_name##ext##_t; \
static inline void class_##_name##ext##_destructor(class_##_name##_t *p)\
@@ -290,6 +309,9 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
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); \
diff --git a/include/linux/file.h b/include/linux/file.h
index af1768d934a0..331b07f9a6fd 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/cleanup.h>
#include <linux/err.h>
+#include <linux/vfsdebug.h>
struct file;
@@ -127,4 +128,140 @@ extern void __fput_sync(struct file *);
extern unsigned int sysctl_nr_open_min, sysctl_nr_open_max;
+/*
+ * fd_prepare class: Combined fd + file allocation with automatic cleanup.
+ *
+ * Allocates an fd and a file together. On error paths, automatically cleans
+ * up whichever resource was successfully allocated. Allows flexible file
+ * allocation with different functions per usage.
+ */
+
+struct fd_prepare {
+ int fd;
+ struct file *file;
+};
+
+/*
+ * fd_prepare_fd() - Get fd from fd_prepare structure
+ * @fd_prepare: struct fd_prepare to extract fd from
+ *
+ * Returns the file descriptor from an fd_prepare structure.
+ *
+ * Return: The file descriptor
+ */
+static inline int fd_prepare_fd(struct fd_prepare fdp)
+{
+ return fdp.fd;
+}
+
+/*
+ * fd_prepare_file() - Get file from fd_prepare structure
+ * @fd_prepare: struct fd_prepare to extract file from
+ *
+ * Returns the file pointer from an fd_prepare structure.
+ *
+ * Return: The file pointer
+ */
+static inline struct file *fd_prepare_file(struct fd_prepare fdp)
+{
+ return fdp.file;
+}
+
+/*
+ * fd_prepare_failed() - Check if fd_prepare allocation failed
+ * @fd_prepare: struct fd_prepare to check
+ *
+ * Checks whether either the fd allocation or file allocation failed.
+ *
+ * Return: true if either allocation failed, false otherwise
+ */
+static inline bool fd_prepare_failed(struct fd_prepare fdp)
+{
+ VFS_WARN_ON_ONCE(fdp.fd < 0 && IS_ERR(fdp.file));
+ return fdp.fd < 0 || IS_ERR(fdp.file);
+}
+
+/*
+ * fd_prepare_error() - Get error from failed fd_prepare
+ * @fd_prepare: struct fd_prepare to extract error from
+ *
+ * Returns the error code from the first allocation that failed.
+ * Should only be called after fd_prepare_failed() returns true.
+ *
+ * Return: Negative error code
+ */
+static inline int fd_prepare_error(struct fd_prepare fdp)
+{
+ if (fdp.fd < 0) {
+ VFS_WARN_ON_ONCE(fdp.file);
+ return fdp.fd;
+ }
+ if (!fdp.file)
+ return -ENOMEM;
+ return PTR_ERR(fdp.file);
+}
+
+static inline void __fd_prepare_put(struct fd_prepare fdp)
+{
+ if (fdp.fd >= 0)
+ put_unused_fd(fdp.fd);
+ if (!IS_ERR_OR_NULL(fdp.file))
+ fput(fdp.file);
+}
+
+DEFINE_CLASS_TYPE(fd_prepare, struct fd_prepare, __fd_prepare_put(_T))
+
+/*
+ * __FD_PREPARE_INIT(fd_flags, file_init_expr):
+ * Helper to initialize fd_prepare class.
+ * @fd_flags: flags for get_unused_fd_flags()
+ * @file_init_expr: expression that returns struct file *
+ *
+ * Returns a struct fd_prepare with fd and file set.
+ * If fd allocation fails, file will be NULL.
+ * If fd succeeds but file_init_expr fails, fd will be cleaned up.
+ */
+#define __FD_PREPARE_INIT(_fd_flags, _file_init) \
+ ({ \
+ struct fd_prepare _fd_prepare = { \
+ .fd = get_unused_fd_flags(_fd_flags), \
+ }; \
+ if (_fd_prepare.fd >= 0) \
+ _fd_prepare.file = (_file_init); \
+ _fd_prepare; \
+ })
+
+/*
+ * FD_PREPARE(var, fd_flags, file_init_expr):
+ * Convenience wrapper for CLASS_INIT(fd_prepare, ...).
+ *
+ * Ex.
+ * FD_PREPARE(ff, O_RDWR | O_CLOEXEC,
+ * anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep, O_RDWR));
+ * if (fd_prepare_failed(ff))
+ * return fd_prepare_error(ff);
+ *
+ * ep->file = fd_prepare_file(ff);
+ * return fd_publish(ff);
+ *
+ * Or with different file init function:
+ *
+ * FD_PREPARE(ff, flags,
+ * anon_inode_getfile_fmode("[eventfd]", &eventfd_fops, ctx, flags, FMODE_NOWAIT));
+ * if (fd_prepare_failed(ff))
+ * return fd_prepare_error(ff);
+ *
+ * return fd_publish(ff);
+ */
+#define FD_PREPARE(_var, _fd_flags, _file_init) \
+ CLASS_INIT(fd_prepare, _var, __FD_PREPARE_INIT(_fd_flags, _file_init))
+
+#define fd_publish(_fd_prepare) \
+ ({ \
+ struct fd_prepare *__p = &(_fd_prepare); \
+ fd_install(__p->fd, __p->file); \
+ retain_and_null_ptr(__p->file); \
+ take_fd(__p->fd); \
+ })
+
#endif /* __LINUX_FILE_H */
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 02/18] fs: anon_inodes
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 01/18] file: add FD_PREPARE() Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 03/18] fs: eventfd Christian Brauner
` (15 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/anon_inodes.c | 26 ++++++--------------------
1 file changed, 6 insertions(+), 20 deletions(-)
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 180a458fc4f7..ab891cc84d2c 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -280,27 +280,13 @@ static int __anon_inode_getfd(const char *name,
const struct inode *context_inode,
bool make_inode)
{
- int error, fd;
- struct file *file;
-
- error = get_unused_fd_flags(flags);
- if (error < 0)
- return error;
- fd = error;
-
- file = __anon_inode_getfile(name, fops, priv, flags, context_inode,
- make_inode);
- if (IS_ERR(file)) {
- error = PTR_ERR(file);
- goto err_put_unused_fd;
- }
- fd_install(fd, file);
-
- return fd;
+ FD_PREPARE(fdprep, flags,
+ __anon_inode_getfile(name, fops, priv, flags,
+ context_inode, make_inode));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
-err_put_unused_fd:
- put_unused_fd(fd);
- return error;
+ return fd_publish(fdprep);
}
/**
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 03/18] fs: eventfd
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 01/18] file: add FD_PREPARE() Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 02/18] fs: anon_inodes Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 04/18] fs: fhandle Christian Brauner
` (14 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/eventfd.c | 32 ++++++++++++--------------------
1 file changed, 12 insertions(+), 20 deletions(-)
diff --git a/fs/eventfd.c b/fs/eventfd.c
index af42b2c7d235..ae672255215d 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -378,9 +378,7 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
static int do_eventfd(unsigned int count, int flags)
{
- struct eventfd_ctx *ctx;
- struct file *file;
- int fd;
+ struct eventfd_ctx *ctx __free(kfree) = NULL;
/* Check the EFD_* constants for consistency. */
BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
@@ -398,26 +396,20 @@ static int do_eventfd(unsigned int count, int flags)
init_waitqueue_head(&ctx->wqh);
ctx->count = count;
ctx->flags = flags;
- ctx->id = ida_alloc(&eventfd_ida, GFP_KERNEL);
flags &= EFD_SHARED_FCNTL_FLAGS;
flags |= O_RDWR;
- fd = get_unused_fd_flags(flags);
- if (fd < 0)
- goto err;
-
- file = anon_inode_getfile_fmode("[eventfd]", &eventfd_fops,
- ctx, flags, FMODE_NOWAIT);
- if (IS_ERR(file)) {
- put_unused_fd(fd);
- fd = PTR_ERR(file);
- goto err;
- }
- fd_install(fd, file);
- return fd;
-err:
- eventfd_free_ctx(ctx);
- return fd;
+
+ FD_PREPARE(fdprep, flags,
+ anon_inode_getfile_fmode("[eventfd]", &eventfd_fops, ctx,
+ flags, FMODE_NOWAIT));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
+
+ ctx->id = ida_alloc(&eventfd_ida, GFP_KERNEL);
+ retain_and_null_ptr(ctx);
+
+ return fd_publish(fdprep);
}
SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 04/18] fs: fhandle
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (2 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 03/18] fs: eventfd Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 05/18] fs: open_tree() Christian Brauner
` (13 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/fhandle.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/fs/fhandle.c b/fs/fhandle.c
index 052f9c9368fb..fd46ecb014ea 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -404,32 +404,32 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
return retval;
}
+static struct file *file_open_handle(struct path *path, int open_flag)
+{
+ const struct export_operations *eops;
+
+ eops = path->mnt->mnt_sb->s_export_op;
+ if (eops->open)
+ return eops->open(path, open_flag);
+
+ return file_open_root(path, "", open_flag, 0);
+}
+
static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
int open_flag)
{
long retval = 0;
struct path path __free(path_put) = {};
- struct file *file;
- const struct export_operations *eops;
retval = handle_to_path(mountdirfd, ufh, &path, open_flag);
if (retval)
return retval;
- CLASS(get_unused_fd, fd)(open_flag);
- if (fd < 0)
- return fd;
-
- eops = path.mnt->mnt_sb->s_export_op;
- if (eops->open)
- file = eops->open(&path, open_flag);
- else
- file = file_open_root(&path, "", open_flag, 0);
- if (IS_ERR(file))
- return PTR_ERR(file);
+ FD_PREPARE(fdprep, open_flag, file_open_handle(&path, open_flag));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
- fd_install(fd, file);
- return take_fd(fd);
+ return fd_publish(fdprep);
}
/**
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 05/18] fs: open_tree()
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (3 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 04/18] fs: fhandle Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 06/18] fs: namespace Christian Brauner
` (12 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/namespace.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 25289b869be1..a6e170d6692d 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3103,19 +3103,11 @@ static struct file *vfs_open_tree(int dfd, const char __user *filename, unsigned
SYSCALL_DEFINE3(open_tree, int, dfd, const char __user *, filename, unsigned, flags)
{
- int fd;
- struct file *file __free(fput) = NULL;
-
- file = vfs_open_tree(dfd, filename, flags);
- if (IS_ERR(file))
- return PTR_ERR(file);
+ FD_PREPARE(fdprep, flags, vfs_open_tree(dfd, filename, flags));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
- fd = get_unused_fd_flags(flags & O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- fd_install(fd, no_free_ptr(file));
- return fd;
+ return fd_publish(fdprep);
}
/*
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 06/18] fs: namespace
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (4 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 05/18] fs: open_tree() Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 07/18] fs: fanotify Christian Brauner
` (11 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/namespace.c | 54 +++++++++++++++++++++---------------------------------
1 file changed, 21 insertions(+), 33 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index a6e170d6692d..55921ab2f2d3 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4279,7 +4279,7 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
struct mnt_namespace *ns;
struct fs_context *fc;
struct file *file;
- struct path newmount;
+ struct path newmount __free(path_put) = {};
struct mount *mnt;
unsigned int mnt_flags = 0;
long ret;
@@ -4317,33 +4317,32 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
fc = fd_file(f)->private_data;
- ret = mutex_lock_interruptible(&fc->uapi_mutex);
- if (ret < 0)
+ ACQUIRE(mutex_intr, uapi_mutex)(&fc->uapi_mutex);
+ ret = ACQUIRE_ERR(mutex_intr, &uapi_mutex);
+ if (ret)
return ret;
/* There must be a valid superblock or we can't mount it */
ret = -EINVAL;
if (!fc->root)
- goto err_unlock;
+ return ret;
ret = -EPERM;
if (mount_too_revealing(fc->root->d_sb, &mnt_flags)) {
errorfcp(fc, "VFS", "Mount too revealing");
- goto err_unlock;
+ return ret;
}
ret = -EBUSY;
if (fc->phase != FS_CONTEXT_AWAITING_MOUNT)
- goto err_unlock;
+ return ret;
if (fc->sb_flags & SB_MANDLOCK)
warn_mandlock();
newmount.mnt = vfs_create_mount(fc);
- if (IS_ERR(newmount.mnt)) {
- ret = PTR_ERR(newmount.mnt);
- goto err_unlock;
- }
+ if (IS_ERR(newmount.mnt))
+ return PTR_ERR(newmount.mnt);
newmount.dentry = dget(fc->root);
newmount.mnt->mnt_flags = mnt_flags;
@@ -4355,38 +4354,27 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
vfs_clean_context(fc);
ns = alloc_mnt_ns(current->nsproxy->mnt_ns->user_ns, true);
- if (IS_ERR(ns)) {
- ret = PTR_ERR(ns);
- goto err_path;
- }
+ if (IS_ERR(ns))
+ return PTR_ERR(ns);
mnt = real_mount(newmount.mnt);
ns->root = mnt;
ns->nr_mounts = 1;
mnt_add_to_ns(ns, mnt);
mntget(newmount.mnt);
- /* Attach to an apparent O_PATH fd with a note that we need to unmount
- * it, not just simply put it.
- */
- file = dentry_open(&newmount, O_PATH, fc->cred);
- if (IS_ERR(file)) {
+ FD_PREPARE(fdprep, (flags & FSMOUNT_CLOEXEC) ? O_CLOEXEC : 0,
+ dentry_open(&newmount, O_PATH, fc->cred));
+ if (fd_prepare_failed(fdprep)) {
dissolve_on_fput(newmount.mnt);
- ret = PTR_ERR(file);
- goto err_path;
+ return fd_prepare_error(fdprep);
}
- file->f_mode |= FMODE_NEED_UNMOUNT;
- ret = get_unused_fd_flags((flags & FSMOUNT_CLOEXEC) ? O_CLOEXEC : 0);
- if (ret >= 0)
- fd_install(ret, file);
- else
- fput(file);
-
-err_path:
- path_put(&newmount);
-err_unlock:
- mutex_unlock(&fc->uapi_mutex);
- return ret;
+ /*
+ * Attach to an apparent O_PATH fd with a note that we
+ * need to unmount it, not just simply put it.
+ */
+ file->f_mode |= FMODE_NEED_UNMOUNT;
+ return fd_publish(fdprep);
}
static inline int vfs_move_mount(const struct path *from_path,
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 07/18] fs: fanotify
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (5 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 06/18] fs: namespace Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 08/18] fs: nsfs Christian Brauner
` (10 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/notify/fanotify/fanotify_user.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 1dadda82cae5..4f818b0ce3be 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -1606,7 +1606,6 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
unsigned int fid_mode = flags & FANOTIFY_FID_BITS;
unsigned int class = flags & FANOTIFY_CLASS_BITS;
unsigned int internal_flags = 0;
- struct file *file;
pr_debug("%s: flags=%x event_f_flags=%x\n",
__func__, flags, event_f_flags);
@@ -1755,19 +1754,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
goto out_destroy_group;
}
- fd = get_unused_fd_flags(f_flags);
- if (fd < 0)
- goto out_destroy_group;
+ FD_PREPARE(fdprep, f_flags,
+ anon_inode_getfile_fmode("[fanotify]", &fanotify_fops, group,
+ f_flags, FMODE_NONOTIFY));
+ if (!fd_prepare_failed(fdprep))
+ return fd_publish(fdprep);
- file = anon_inode_getfile_fmode("[fanotify]", &fanotify_fops, group,
- f_flags, FMODE_NONOTIFY);
- if (IS_ERR(file)) {
- put_unused_fd(fd);
- fd = PTR_ERR(file);
- goto out_destroy_group;
- }
- fd_install(fd, file);
- return fd;
+ fd = fd_prepare_error(fdprep);
out_destroy_group:
fsnotify_destroy_group(group);
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 08/18] fs: nsfs
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (6 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 07/18] fs: fanotify Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 09/18] fs: autofs Christian Brauner
` (9 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/nsfs.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/fs/nsfs.c b/fs/nsfs.c
index a80f8d2a4122..cf20fba0ecd2 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -110,7 +110,6 @@ int ns_get_path(struct path *path, struct task_struct *task,
int open_namespace(struct ns_common *ns)
{
struct path path __free(path_put) = {};
- struct file *f;
int err;
/* call first to consume reference */
@@ -118,16 +117,12 @@ int open_namespace(struct ns_common *ns)
if (err < 0)
return err;
- CLASS(get_unused_fd, fd)(O_CLOEXEC);
- if (fd < 0)
- return fd;
+ FD_PREPARE(fdprep, O_CLOEXEC,
+ dentry_open(&path, O_RDONLY, current_cred()));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
- f = dentry_open(&path, O_RDONLY, current_cred());
- if (IS_ERR(f))
- return PTR_ERR(f);
-
- fd_install(fd, f);
- return take_fd(fd);
+ return fd_publish(fdprep);
}
int open_related_ns(struct ns_common *ns,
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 09/18] fs: autofs
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (7 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 08/18] fs: nsfs Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 10/18] fs: eventpoll Christian Brauner
` (8 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/autofs/dev-ioctl.c | 32 +++++++++-----------------------
1 file changed, 9 insertions(+), 23 deletions(-)
diff --git a/fs/autofs/dev-ioctl.c b/fs/autofs/dev-ioctl.c
index d8dd150cbd74..c93f0f5c537a 100644
--- a/fs/autofs/dev-ioctl.c
+++ b/fs/autofs/dev-ioctl.c
@@ -231,32 +231,18 @@ static int test_by_type(const struct path *path, void *p)
*/
static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid)
{
- int err, fd;
-
- fd = get_unused_fd_flags(O_CLOEXEC);
- if (likely(fd >= 0)) {
- struct file *filp;
- struct path path;
-
- err = find_autofs_mount(name, &path, test_by_dev, &devid);
- if (err)
- goto out;
-
- filp = dentry_open(&path, O_RDONLY, current_cred());
- path_put(&path);
- if (IS_ERR(filp)) {
- err = PTR_ERR(filp);
- goto out;
- }
+ struct path path __free(path_put) = {};
+ int err;
- fd_install(fd, filp);
- }
+ err = find_autofs_mount(name, &path, test_by_dev, &devid);
+ if (err)
+ return err;
- return fd;
+ FD_PREPARE(fdprep, O_CLOEXEC, dentry_open(&path, O_RDONLY, current_cred()));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
-out:
- put_unused_fd(fd);
- return err;
+ return fd_publish(fdprep);
}
/* Open a file descriptor on an autofs mount point */
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 10/18] fs: eventpoll
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (8 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 09/18] fs: autofs Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 11/18] fs: open_tree_attr() Christian Brauner
` (7 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/eventpoll.c | 33 +++++++++++----------------------
1 file changed, 11 insertions(+), 22 deletions(-)
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index ee7c4b683ec3..d707e96f3685 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -2165,9 +2165,8 @@ static void clear_tfile_check_list(void)
*/
static int do_epoll_create(int flags)
{
- int error, fd;
- struct eventpoll *ep = NULL;
- struct file *file;
+ int error;
+ struct eventpoll *ep;
/* Check the EPOLL_* constant for consistency. */
BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
@@ -2184,26 +2183,16 @@ static int do_epoll_create(int flags)
* Creates all the items needed to setup an eventpoll file. That is,
* a file structure and a free file descriptor.
*/
- fd = get_unused_fd_flags(O_RDWR | (flags & O_CLOEXEC));
- if (fd < 0) {
- error = fd;
- goto out_free_ep;
- }
- file = anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep,
- O_RDWR | (flags & O_CLOEXEC));
- if (IS_ERR(file)) {
- error = PTR_ERR(file);
- goto out_free_fd;
+ FD_PREPARE(fdprep, O_RDWR | (flags & O_CLOEXEC),
+ anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep,
+ O_RDWR | (flags & O_CLOEXEC)));
+ if (fd_prepare_failed(fdprep)) {
+ ep_clear_and_put(ep);
+ return fd_prepare_error(fdprep);
}
- ep->file = file;
- fd_install(fd, file);
- return fd;
-
-out_free_fd:
- put_unused_fd(fd);
-out_free_ep:
- ep_clear_and_put(ep);
- return error;
+
+ ep->file = fd_prepare_file(fdprep);
+ return fd_publish(fdprep);
}
SYSCALL_DEFINE1(epoll_create1, int, flags)
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 11/18] fs: open_tree_attr()
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (9 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 10/18] fs: eventpoll Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 12/18] fs: nsfs2 Christian Brauner
` (6 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/namespace.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 55921ab2f2d3..58a720adde3a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -5016,19 +5016,17 @@ SYSCALL_DEFINE5(open_tree_attr, int, dfd, const char __user *, filename,
unsigned, flags, struct mount_attr __user *, uattr,
size_t, usize)
{
- struct file __free(fput) *file = NULL;
- int fd;
-
if (!uattr && usize)
return -EINVAL;
- file = vfs_open_tree(dfd, filename, flags);
- if (IS_ERR(file))
- return PTR_ERR(file);
+ FD_PREPARE(fdprep, flags, vfs_open_tree(dfd, filename, flags));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
if (uattr) {
int ret;
struct mount_kattr kattr = {};
+ struct file *file = fd_prepare_file(fdprep);
if (flags & OPEN_TREE_CLONE)
kattr.kflags = MOUNT_KATTR_IDMAP_REPLACE;
@@ -5044,12 +5042,7 @@ SYSCALL_DEFINE5(open_tree_attr, int, dfd, const char __user *, filename,
return ret;
}
- fd = get_unused_fd_flags(flags & O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- fd_install(fd, no_free_ptr(file));
- return fd;
+ return fd_publish(fdprep);
}
int show_path(struct seq_file *m, struct dentry *root)
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 12/18] fs: nsfs2
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (10 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 11/18] fs: open_tree_attr() Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 13/18] fs: open Christian Brauner
` (5 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/nsfs.c | 33 ++++++++++++---------------------
1 file changed, 12 insertions(+), 21 deletions(-)
diff --git a/fs/nsfs.c b/fs/nsfs.c
index cf20fba0ecd2..b725fd152afb 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -327,28 +327,19 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
if (ret)
return ret;
- CLASS(get_unused_fd, fd)(O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- f = dentry_open(&path, O_RDONLY, current_cred());
- if (IS_ERR(f))
- return PTR_ERR(f);
-
- if (uinfo) {
- /*
- * If @uinfo is passed return all information about the
- * mount namespace as well.
- */
- ret = copy_ns_info_to_user(to_mnt_ns(ns), uinfo, usize, &kinfo);
- if (ret)
- return ret;
- }
+ FD_PREPARE(fdprep, O_CLOEXEC, dentry_open(&path, O_RDONLY, current_cred()));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
+
+ /*
+ * If @uinfo is passed return all information about the
+ * mount namespace as well.
+ */
+ ret = copy_ns_info_to_user(to_mnt_ns(ns), uinfo, usize, &kinfo);
+ if (ret)
+ return ret;
- /* Transfer reference of @f to caller's fdtable. */
- fd_install(fd, no_free_ptr(f));
- /* File descriptor is live so hand it off to the caller. */
- return take_fd(fd);
+ return fd_publish(fdprep);
}
default:
ret = -ENOTTY;
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 13/18] fs: open
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (11 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 12/18] fs: nsfs2 Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 14/18] fs: signalfd64 Christian Brauner
` (4 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/open.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..56f6b485483b 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1422,7 +1422,7 @@ static int do_sys_openat2(int dfd, const char __user *filename,
{
struct open_flags op;
struct filename *tmp;
- int err, fd;
+ int err;
err = build_open_flags(how, &op);
if (unlikely(err))
@@ -1432,18 +1432,12 @@ static int do_sys_openat2(int dfd, const char __user *filename,
if (IS_ERR(tmp))
return PTR_ERR(tmp);
- fd = get_unused_fd_flags(how->flags);
- if (likely(fd >= 0)) {
- struct file *f = do_filp_open(dfd, tmp, &op);
- if (IS_ERR(f)) {
- put_unused_fd(fd);
- fd = PTR_ERR(f);
- } else {
- fd_install(fd, f);
- }
- }
+ FD_PREPARE(fdprep, how->flags, do_filp_open(dfd, tmp, &op));
putname(tmp);
- return fd;
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
+
+ return fd_publish(fdprep);
}
int do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 14/18] fs: signalfd64
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (12 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 13/18] fs: open Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 15/18] fs: timerfd Christian Brauner
` (3 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/signalfd.c | 28 +++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/fs/signalfd.c b/fs/signalfd.c
index d469782f97f4..45ba6000e9a9 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -250,8 +250,6 @@ static const struct file_operations signalfd_fops = {
static int do_signalfd4(int ufd, sigset_t *mask, int flags)
{
- struct signalfd_ctx *ctx;
-
/* Check the SFD_* constants for consistency. */
BUILD_BUG_ON(SFD_CLOEXEC != O_CLOEXEC);
BUILD_BUG_ON(SFD_NONBLOCK != O_NONBLOCK);
@@ -263,7 +261,7 @@ static int do_signalfd4(int ufd, sigset_t *mask, int flags)
signotset(mask);
if (ufd == -1) {
- struct file *file;
+ struct signalfd_ctx *ctx __free(kfree) = NULL;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -271,22 +269,18 @@ static int do_signalfd4(int ufd, sigset_t *mask, int flags)
ctx->sigmask = *mask;
- ufd = get_unused_fd_flags(flags & O_CLOEXEC);
- if (ufd < 0) {
- kfree(ctx);
- return ufd;
- }
+ FD_PREPARE(fdprep, flags & O_CLOEXEC,
+ anon_inode_getfile_fmode("[signalfd]", &signalfd_fops, ctx,
+ O_RDWR | (flags & O_NONBLOCK),
+ FMODE_NOWAIT));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
- file = anon_inode_getfile_fmode("[signalfd]", &signalfd_fops,
- ctx, O_RDWR | (flags & O_NONBLOCK),
- FMODE_NOWAIT);
- if (IS_ERR(file)) {
- put_unused_fd(ufd);
- kfree(ctx);
- return PTR_ERR(file);
- }
- fd_install(ufd, file);
+ retain_and_null_ptr(ctx);
+ return fd_publish(fdprep);
} else {
+ struct signalfd_ctx *ctx;
+
CLASS(fd, f)(ufd);
if (fd_empty(f))
return -EBADF;
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 15/18] fs: timerfd
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (13 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 14/18] fs: signalfd64 Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 16/18] fs: userfaultfd Christian Brauner
` (2 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/timerfd.c | 28 +++++++++-------------------
1 file changed, 9 insertions(+), 19 deletions(-)
diff --git a/fs/timerfd.c b/fs/timerfd.c
index c68f28d9c426..acaad0a086b1 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -393,9 +393,7 @@ static const struct file_operations timerfd_fops = {
SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
{
- int ufd;
- struct timerfd_ctx *ctx;
- struct file *file;
+ struct timerfd_ctx *ctx __free(kfree) = NULL;
/* Check the TFD_* constants for consistency. */
BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
@@ -432,23 +430,15 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
ctx->moffs = ktime_mono_to_real(0);
- ufd = get_unused_fd_flags(flags & TFD_SHARED_FCNTL_FLAGS);
- if (ufd < 0) {
- kfree(ctx);
- return ufd;
- }
-
- file = anon_inode_getfile_fmode("[timerfd]", &timerfd_fops, ctx,
- O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS),
- FMODE_NOWAIT);
- if (IS_ERR(file)) {
- put_unused_fd(ufd);
- kfree(ctx);
- return PTR_ERR(file);
- }
+ FD_PREPARE(fdprep, flags & TFD_SHARED_FCNTL_FLAGS,
+ anon_inode_getfile_fmode("[timerfd]", &timerfd_fops, ctx,
+ O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS),
+ FMODE_NOWAIT));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
- fd_install(ufd, file);
- return ufd;
+ retain_and_null_ptr(ctx);
+ return fd_publish(fdprep);
}
static int do_timerfd_settime(int ufd, int flags,
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 16/18] fs: userfaultfd
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (14 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 15/18] fs: timerfd Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 17/18] fs: xfs Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 18/18] drivers: drm_lease Christian Brauner
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/userfaultfd.c | 29 +++++++++--------------------
1 file changed, 9 insertions(+), 20 deletions(-)
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 54c6cc7fe9c6..77048b86d781 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -2111,9 +2111,7 @@ static void init_once_userfaultfd_ctx(void *mem)
static int new_userfaultfd(int flags)
{
- struct userfaultfd_ctx *ctx;
- struct file *file;
- int fd;
+ struct userfaultfd_ctx *ctx __free(kfree) = NULL;
VM_WARN_ON_ONCE(!current->mm);
@@ -2135,26 +2133,17 @@ static int new_userfaultfd(int flags)
atomic_set(&ctx->mmap_changing, 0);
ctx->mm = current->mm;
- fd = get_unused_fd_flags(flags & UFFD_SHARED_FCNTL_FLAGS);
- if (fd < 0)
- goto err_out;
+ FD_PREPARE(fdprep, flags & UFFD_SHARED_FCNTL_FLAGS,
+ anon_inode_create_getfile("[userfaultfd]", &userfaultfd_fops, ctx,
+ O_RDONLY | (flags & UFFD_SHARED_FCNTL_FLAGS), NULL));
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
- /* Create a new inode so that the LSM can block the creation. */
- file = anon_inode_create_getfile("[userfaultfd]", &userfaultfd_fops, ctx,
- O_RDONLY | (flags & UFFD_SHARED_FCNTL_FLAGS), NULL);
- if (IS_ERR(file)) {
- put_unused_fd(fd);
- fd = PTR_ERR(file);
- goto err_out;
- }
/* prevent the mm struct to be freed */
mmgrab(ctx->mm);
- file->f_mode |= FMODE_NOWAIT;
- fd_install(fd, file);
- return fd;
-err_out:
- kmem_cache_free(userfaultfd_ctx_cachep, ctx);
- return fd;
+ fd_prepare_file(fdprep)->f_mode |= FMODE_NOWAIT;
+ retain_and_null_ptr(ctx);
+ return fd_publish(fdprep);
}
static inline bool userfaultfd_syscall_allowed(int flags)
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 17/18] fs: xfs
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (15 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 16/18] fs: userfaultfd Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 18/18] drivers: drm_lease Christian Brauner
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/xfs/xfs_handle.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/fs/xfs/xfs_handle.c b/fs/xfs/xfs_handle.c
index f19fce557354..a507944fe022 100644
--- a/fs/xfs/xfs_handle.c
+++ b/fs/xfs/xfs_handle.c
@@ -234,9 +234,7 @@ xfs_open_by_handle(
{
const struct cred *cred = current_cred();
int error;
- int fd;
int permflag;
- struct file *filp;
struct inode *inode;
struct dentry *dentry;
fmode_t fmode;
@@ -279,28 +277,22 @@ xfs_open_by_handle(
goto out_dput;
}
- fd = get_unused_fd_flags(0);
- if (fd < 0) {
- error = fd;
- goto out_dput;
- }
-
path.mnt = parfilp->f_path.mnt;
path.dentry = dentry;
- filp = dentry_open(&path, hreq->oflags, cred);
+
+ FD_PREPARE(fdprep, 0, dentry_open(&path, hreq->oflags, cred));
dput(dentry);
- if (IS_ERR(filp)) {
- put_unused_fd(fd);
- return PTR_ERR(filp);
- }
+ if (fd_prepare_failed(fdprep))
+ return fd_prepare_error(fdprep);
if (S_ISREG(inode->i_mode)) {
+ struct file *filp = fd_prepare_file(fdprep);
+
filp->f_flags |= O_NOATIME;
filp->f_mode |= FMODE_NOCMTIME;
}
- fd_install(fd, filp);
- return fd;
+ return fd_publish(fdprep);
out_dput:
dput(dentry);
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH DRAFT RFC UNTESTED 18/18] drivers: drm_lease
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
` (16 preceding siblings ...)
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 17/18] fs: xfs Christian Brauner
@ 2025-11-18 15:48 ` Christian Brauner
17 siblings, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2025-11-18 15:48 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Alexander Viro, Jan Kara, linux-fsdevel, Christian Brauner
Placeholder commit message.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
drivers/gpu/drm/drm_lease.c | 44 ++++++++++++++------------------------------
1 file changed, 14 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
index 94375c6a5425..3feee39e464b 100644
--- a/drivers/gpu/drm/drm_lease.c
+++ b/drivers/gpu/drm/drm_lease.c
@@ -514,8 +514,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
object_count, sizeof(__u32));
if (IS_ERR(object_ids)) {
ret = PTR_ERR(object_ids);
- idr_destroy(&leases);
- goto out_lessor;
+ goto out_idr;
}
/* fill and validate the object idr */
@@ -524,35 +523,26 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
kfree(object_ids);
if (ret) {
drm_dbg_lease(dev, "lease object lookup failed: %i\n", ret);
- idr_destroy(&leases);
- goto out_lessor;
+ goto out_idr;
}
}
- /* Allocate a file descriptor for the lease */
- fd = get_unused_fd_flags(cl->flags & (O_CLOEXEC | O_NONBLOCK));
- if (fd < 0) {
- idr_destroy(&leases);
- ret = fd;
- goto out_lessor;
+ drm_dbg_lease(dev, "Allocating lease file\n");
+ FD_PREPARE(fdprep, cl->flags & (O_CLOEXEC | O_NONBLOCK),
+ file_clone_open(lessor_file));
+ if (fd_prepare_failed(fdprep)) {
+ ret = fd_prepare_error(fdprep);
+ goto out_idr;
}
+ lessee_file = fd_prepare_file(fdprep);
+
drm_dbg_lease(dev, "Creating lease\n");
/* lessee will take the ownership of leases */
lessee = drm_lease_create(lessor, &leases);
-
if (IS_ERR(lessee)) {
ret = PTR_ERR(lessee);
- idr_destroy(&leases);
- goto out_leases;
- }
-
- /* Clone the lessor file to create a new file for us */
- drm_dbg_lease(dev, "Allocating lease file\n");
- lessee_file = file_clone_open(lessor_file);
- if (IS_ERR(lessee_file)) {
- ret = PTR_ERR(lessee_file);
- goto out_lessee;
+ goto out_idr;
}
lessee_priv = lessee_file->private_data;
@@ -564,21 +554,15 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
/* Pass fd back to userspace */
drm_dbg_lease(dev, "Returning fd %d id %d\n", fd, lessee->lessee_id);
- cl->fd = fd;
cl->lessee_id = lessee->lessee_id;
-
- /* Hook up the fd */
- fd_install(fd, lessee_file);
+ cl->fd = fd_publish(fdprep);
drm_master_put(&lessor);
drm_dbg_lease(dev, "drm_mode_create_lease_ioctl succeeded\n");
return 0;
-out_lessee:
- drm_master_put(&lessee);
-
-out_leases:
- put_unused_fd(fd);
+out_idr:
+ idr_destroy(&leases);
out_lessor:
drm_master_put(&lessor);
--
2.47.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
end of thread, other threads:[~2025-11-18 15:50 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-18 15:48 [PATCH DRAFT RFC UNTESTED 00/18] file: FD_PREPARE() Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 01/18] file: add FD_PREPARE() Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 02/18] fs: anon_inodes Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 03/18] fs: eventfd Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 04/18] fs: fhandle Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 05/18] fs: open_tree() Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 06/18] fs: namespace Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 07/18] fs: fanotify Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 08/18] fs: nsfs Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 09/18] fs: autofs Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 10/18] fs: eventpoll Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 11/18] fs: open_tree_attr() Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 12/18] fs: nsfs2 Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 13/18] fs: open Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 14/18] fs: signalfd64 Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 15/18] fs: timerfd Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 16/18] fs: userfaultfd Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 17/18] fs: xfs Christian Brauner
2025-11-18 15:48 ` [PATCH DRAFT RFC UNTESTED 18/18] drivers: drm_lease Christian Brauner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).