linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).