public inbox for io-uring@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring
@ 2025-09-10 21:49 Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 01/10] fhandle: create helper for name_to_handle_at(2) Thomas Bertschinger
                   ` (9 more replies)
  0 siblings, 10 replies; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger, linux-xfs, cem, chuck.lever, jlayton

This series adds support for name_to_handle_at() and open_by_handle_at()
to io_uring. The idea is for these opcodes to be useful for userspace
NFS servers that want to use io_uring.

The biggest change since [v1] is that this adds support for attempting
non-blocking open_by_handle_at(). When io_uring calls handle_to_path(),
it will set a flag to request that the call return -EAGAIN if it cannot
complete using cached data.

The same holds for the call to do_filp_path_open().

Supporting this for handle_to_path() requires a way to communicate to
the filesystem that it should not block in its fh_to_dentry()
implementation. This is done with a new flag FILEID_CACHED which is set
in the file handle by the VFS. If a filesystem supports this new flag,
it will indicate that with a new flag EXPORT_OP_NONBLOCK so that the VFS
knows not to call into a filesystem with the FILEID_CACHED flag, when
the FS does not know about that flag.

Support for the new FILEID_CACHED flag is added for xfs.

Thanks to Amir Goldstein for the review comments and suggesting this
approach on v1.

Testing
=======

As in v1, a liburing branch with a test is available at
https://github.com/bertschingert/liburing/tree/open_by_handle_at

and is run with

$ ./test/open_by_handle_at.t

v1 -> v2:
- rename some new helper functions:
	- do_name_to_handle_at() -> do_sys_name_to_handle_at()
	- __do_handle_open() -> do_filp_path_open()
- create a union member name_to_handle_flags in struct io_uring_sqe
- add new FILEID_CACHED and EXPORT_OP_NONBLOCK flags
- attempt non-blocking open_by_handle_at() in io_uring first, rather
  than always giving up and running in async context
- add support for FILEID_CACHED in xfs

[v1] https://lore.kernel.org/linux-fsdevel/20250814235431.995876-1-tahbertschinger@gmail.com/

Thomas Bertschinger (10):
  fhandle: create helper for name_to_handle_at(2)
  io_uring: add support for IORING_OP_NAME_TO_HANDLE_AT
  fhandle: helper for allocating, reading struct file_handle
  fhandle: create do_filp_path_open() helper
  fhandle: make do_filp_path_open() take struct open_flags
  exportfs: allow VFS flags in struct file_handle
  exportfs: new FILEID_CACHED flag for non-blocking fh lookup
  io_uring: add __io_open_prep() helper
  io_uring: add support for IORING_OP_OPEN_BY_HANDLE_AT
  xfs: add support for non-blocking fh_to_dentry()

 fs/exportfs/expfs.c           |  15 ++-
 fs/fhandle.c                  | 156 ++++++++++++++++-----------
 fs/internal.h                 |  13 +++
 fs/xfs/xfs_export.c           |  32 ++++--
 fs/xfs/xfs_export.h           |   3 +-
 fs/xfs/xfs_handle.c           |   2 +-
 include/linux/exportfs.h      |  34 +++++-
 include/uapi/linux/io_uring.h |   3 +
 io_uring/opdef.c              |  26 +++++
 io_uring/openclose.c          | 191 ++++++++++++++++++++++++++++++++--
 io_uring/openclose.h          |  13 +++
 11 files changed, 405 insertions(+), 83 deletions(-)


base-commit: 76eeb9b8de9880ca38696b2fb56ac45ac0a25c6c
-- 
2.51.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/10] fhandle: create helper for name_to_handle_at(2)
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-11 12:06   ` Amir Goldstein
  2025-09-10 21:49 ` [PATCH 02/10] io_uring: add support for IORING_OP_NAME_TO_HANDLE_AT Thomas Bertschinger
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger

Create a helper do_sys_name_to_handle_at() that takes an additional
argument, lookup_flags, beyond the syscall arguments.

Because name_to_handle_at(2) doesn't take any lookup flags, it always
passes 0 for this argument.

Future callers like io_uring may pass LOOKUP_CACHED in order to request
a non-blocking lookup.

This helper's name is confusingly similar to do_sys_name_to_handle()
which takes care of returning the file handle, once the filename has
been turned into a struct path. To distinguish the names more clearly,
rename the latter to do_path_to_handle().

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 fs/fhandle.c  | 61 ++++++++++++++++++++++++++++-----------------------
 fs/internal.h |  9 ++++++++
 2 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/fs/fhandle.c b/fs/fhandle.c
index 68a7d2861c58..605ad8e7d93d 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -14,10 +14,10 @@
 #include "internal.h"
 #include "mount.h"
 
-static long do_sys_name_to_handle(const struct path *path,
-				  struct file_handle __user *ufh,
-				  void __user *mnt_id, bool unique_mntid,
-				  int fh_flags)
+static long do_path_to_handle(const struct path *path,
+			      struct file_handle __user *ufh,
+			      void __user *mnt_id, bool unique_mntid,
+			      int fh_flags)
 {
 	long retval;
 	struct file_handle f_handle;
@@ -111,27 +111,11 @@ static long do_sys_name_to_handle(const struct path *path,
 	return retval;
 }
 
-/**
- * sys_name_to_handle_at: convert name to handle
- * @dfd: directory relative to which name is interpreted if not absolute
- * @name: name that should be converted to handle.
- * @handle: resulting file handle
- * @mnt_id: mount id of the file system containing the file
- *          (u64 if AT_HANDLE_MNT_ID_UNIQUE, otherwise int)
- * @flag: flag value to indicate whether to follow symlink or not
- *        and whether a decodable file handle is required.
- *
- * @handle->handle_size indicate the space available to store the
- * variable part of the file handle in bytes. If there is not
- * enough space, the field is updated to return the minimum
- * value required.
- */
-SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
-		struct file_handle __user *, handle, void __user *, mnt_id,
-		int, flag)
+long do_sys_name_to_handle_at(int dfd, const char __user *name,
+			      struct file_handle __user *handle,
+			      void __user *mnt_id, int flag, int lookup_flags)
 {
 	struct path path;
-	int lookup_flags;
 	int fh_flags = 0;
 	int err;
 
@@ -155,19 +139,42 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
 	else if (flag & AT_HANDLE_CONNECTABLE)
 		fh_flags |= EXPORT_FH_CONNECTABLE;
 
-	lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
+	if (flag & AT_SYMLINK_FOLLOW)
+		lookup_flags |= LOOKUP_FOLLOW;
 	if (flag & AT_EMPTY_PATH)
 		lookup_flags |= LOOKUP_EMPTY;
 	err = user_path_at(dfd, name, lookup_flags, &path);
 	if (!err) {
-		err = do_sys_name_to_handle(&path, handle, mnt_id,
-					    flag & AT_HANDLE_MNT_ID_UNIQUE,
-					    fh_flags);
+		err = do_path_to_handle(&path, handle, mnt_id,
+					flag & AT_HANDLE_MNT_ID_UNIQUE,
+					fh_flags);
 		path_put(&path);
 	}
 	return err;
 }
 
+/**
+ * sys_name_to_handle_at: convert name to handle
+ * @dfd: directory relative to which name is interpreted if not absolute
+ * @name: name that should be converted to handle.
+ * @handle: resulting file handle
+ * @mnt_id: mount id of the file system containing the file
+ *          (u64 if AT_HANDLE_MNT_ID_UNIQUE, otherwise int)
+ * @flag: flag value to indicate whether to follow symlink or not
+ *        and whether a decodable file handle is required.
+ *
+ * @handle->handle_size indicate the space available to store the
+ * variable part of the file handle in bytes. If there is not
+ * enough space, the field is updated to return the minimum
+ * value required.
+ */
+SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
+		struct file_handle __user *, handle, void __user *, mnt_id,
+		int, flag)
+{
+	return do_sys_name_to_handle_at(dfd, name, handle, mnt_id, flag, 0);
+}
+
 static int get_path_anchor(int fd, struct path *root)
 {
 	if (fd >= 0) {
diff --git a/fs/internal.h b/fs/internal.h
index 38e8aab27bbd..c972f8ade52d 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -355,3 +355,12 @@ int anon_inode_getattr(struct mnt_idmap *idmap, const struct path *path,
 int anon_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
 		       struct iattr *attr);
 void pidfs_get_root(struct path *path);
+
+/*
+ * fs/fhandle.c
+ */
+#ifdef CONFIG_FHANDLE
+long do_sys_name_to_handle_at(int dfd, const char __user *name,
+			      struct file_handle __user *handle,
+			      void __user *mnt_id, int flag, int lookup_flags);
+#endif /* CONFIG_FHANDLE */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 02/10] io_uring: add support for IORING_OP_NAME_TO_HANDLE_AT
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 01/10] fhandle: create helper for name_to_handle_at(2) Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 03/10] fhandle: helper for allocating, reading struct file_handle Thomas Bertschinger
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger

Add support for name_to_handle_at(2) to io_uring.

Like openat*(), this tries to do a non-blocking lookup first and resorts
to async lookup when that fails.

This uses sqe->addr for the path, ->addr2 for the file handle which is
filled in by the kernel, and ->addr3 for the mouint_id which is filled
in by the kernel.

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 include/uapi/linux/io_uring.h |  2 ++
 io_uring/opdef.c              | 11 +++++++++
 io_uring/openclose.c          | 45 +++++++++++++++++++++++++++++++++++
 io_uring/openclose.h          |  5 ++++
 4 files changed, 63 insertions(+)

diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 6957dc539d83..a4aa83ad9527 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -74,6 +74,7 @@ struct io_uring_sqe {
 		__u32		install_fd_flags;
 		__u32		nop_flags;
 		__u32		pipe_flags;
+		__u32		name_to_handle_flags;
 	};
 	__u64	user_data;	/* data to be passed back at completion time */
 	/* pack this to avoid bogus arm OABI complaints */
@@ -289,6 +290,7 @@ enum io_uring_op {
 	IORING_OP_READV_FIXED,
 	IORING_OP_WRITEV_FIXED,
 	IORING_OP_PIPE,
+	IORING_OP_NAME_TO_HANDLE_AT,
 
 	/* this goes last, obviously */
 	IORING_OP_LAST,
diff --git a/io_uring/opdef.c b/io_uring/opdef.c
index 9568785810d9..76306c9e0ecd 100644
--- a/io_uring/opdef.c
+++ b/io_uring/opdef.c
@@ -574,6 +574,14 @@ const struct io_issue_def io_issue_defs[] = {
 		.prep			= io_pipe_prep,
 		.issue			= io_pipe,
 	},
+	[IORING_OP_NAME_TO_HANDLE_AT] = {
+#if defined(CONFIG_FHANDLE)
+		.prep			= io_name_to_handle_at_prep,
+		.issue			= io_name_to_handle_at,
+#else
+		.prep			= io_eopnotsupp_prep,
+#endif
+	},
 };
 
 const struct io_cold_def io_cold_defs[] = {
@@ -824,6 +832,9 @@ const struct io_cold_def io_cold_defs[] = {
 	[IORING_OP_PIPE] = {
 		.name			= "PIPE",
 	},
+	[IORING_OP_NAME_TO_HANDLE_AT] = {
+		.name			= "NAME_TO_HANDLE_AT",
+	},
 };
 
 const char *io_uring_get_opcode(u8 opcode)
diff --git a/io_uring/openclose.c b/io_uring/openclose.c
index d70700e5cef8..884a66e56643 100644
--- a/io_uring/openclose.c
+++ b/io_uring/openclose.c
@@ -27,6 +27,15 @@ struct io_open {
 	unsigned long			nofile;
 };
 
+struct io_name_to_handle {
+	struct file			*file;
+	int				dfd;
+	int				flags;
+	struct file_handle __user	*ufh;
+	char __user			*path;
+	void __user			*mount_id;
+};
+
 struct io_close {
 	struct file			*file;
 	int				fd;
@@ -187,6 +196,42 @@ void io_open_cleanup(struct io_kiocb *req)
 		putname(open->filename);
 }
 
+#if defined(CONFIG_FHANDLE)
+int io_name_to_handle_at_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+	struct io_name_to_handle *nh = io_kiocb_to_cmd(req, struct io_name_to_handle);
+
+	nh->dfd = READ_ONCE(sqe->fd);
+	nh->flags = READ_ONCE(sqe->name_to_handle_flags);
+	nh->path = u64_to_user_ptr(READ_ONCE(sqe->addr));
+	nh->ufh = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+	nh->mount_id = u64_to_user_ptr(READ_ONCE(sqe->addr3));
+
+	return 0;
+}
+
+int io_name_to_handle_at(struct io_kiocb *req, unsigned int issue_flags)
+{
+	struct io_name_to_handle *nh = io_kiocb_to_cmd(req, struct io_name_to_handle);
+	int lookup_flags = 0;
+	long ret;
+
+	if (issue_flags & IO_URING_F_NONBLOCK)
+		lookup_flags = LOOKUP_CACHED;
+
+	ret = do_sys_name_to_handle_at(nh->dfd, nh->path, nh->ufh, nh->mount_id,
+				       nh->flags, lookup_flags);
+
+	if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
+		return -EAGAIN;
+
+	if (ret < 0)
+		req_set_fail(req);
+	io_req_set_res(req, ret, 0);
+	return IOU_COMPLETE;
+}
+#endif /* CONFIG_FHANDLE */
+
 int __io_close_fixed(struct io_ring_ctx *ctx, unsigned int issue_flags,
 		     unsigned int offset)
 {
diff --git a/io_uring/openclose.h b/io_uring/openclose.h
index 4ca2a9935abc..2fc1c8d35d0b 100644
--- a/io_uring/openclose.h
+++ b/io_uring/openclose.h
@@ -10,6 +10,11 @@ void io_open_cleanup(struct io_kiocb *req);
 int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
 int io_openat2(struct io_kiocb *req, unsigned int issue_flags);
 
+#if defined(CONFIG_FHANDLE)
+int io_name_to_handle_at_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_name_to_handle_at(struct io_kiocb *req, unsigned int issue_flags);
+#endif /* CONFIG_FHANDLE */
+
 int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
 int io_close(struct io_kiocb *req, unsigned int issue_flags);
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 03/10] fhandle: helper for allocating, reading struct file_handle
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 01/10] fhandle: create helper for name_to_handle_at(2) Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 02/10] io_uring: add support for IORING_OP_NAME_TO_HANDLE_AT Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-11 12:15   ` Amir Goldstein
  2025-09-10 21:49 ` [PATCH 04/10] fhandle: create do_filp_path_open() helper Thomas Bertschinger
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger

Pull the code for allocating and copying a struct file_handle from
userspace into a helper function get_user_handle() just for this.

do_handle_open() is updated to call get_user_handle() prior to calling
handle_to_path(), and the latter now takes a kernel pointer as a
parameter instead of a __user pointer.

This new helper, as well as handle_to_path(), are also exposed in
fs/internal.h. In a subsequent commit, io_uring will use these helpers
to support open_by_handle_at(2) in io_uring.

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 fs/fhandle.c  | 64 +++++++++++++++++++++++++++++----------------------
 fs/internal.h |  3 +++
 2 files changed, 40 insertions(+), 27 deletions(-)

diff --git a/fs/fhandle.c b/fs/fhandle.c
index 605ad8e7d93d..36e194dd4cb6 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -330,25 +330,45 @@ static inline int may_decode_fh(struct handle_to_path_ctx *ctx,
 	return 0;
 }
 
-static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
-		   struct path *path, unsigned int o_flags)
+struct file_handle *get_user_handle(struct file_handle __user *ufh)
 {
-	int retval = 0;
 	struct file_handle f_handle;
-	struct file_handle *handle __free(kfree) = NULL;
-	struct handle_to_path_ctx ctx = {};
-	const struct export_operations *eops;
+	struct file_handle *handle;
 
 	if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
-		return -EFAULT;
+		return ERR_PTR(-EFAULT);
 
 	if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
 	    (f_handle.handle_bytes == 0))
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	if (f_handle.handle_type < 0 ||
 	    FILEID_USER_FLAGS(f_handle.handle_type) & ~FILEID_VALID_USER_FLAGS)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
+
+	handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
+			 GFP_KERNEL);
+	if (!handle) {
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* copy the full handle */
+	*handle = f_handle;
+	if (copy_from_user(&handle->f_handle,
+			   &ufh->f_handle,
+			   f_handle.handle_bytes)) {
+		return ERR_PTR(-EFAULT);
+	}
+
+	return handle;
+}
+
+int handle_to_path(int mountdirfd, struct file_handle *handle,
+		   struct path *path, unsigned int o_flags)
+{
+	int retval = 0;
+	struct handle_to_path_ctx ctx = {};
+	const struct export_operations *eops;
 
 	retval = get_path_anchor(mountdirfd, &ctx.root);
 	if (retval)
@@ -362,31 +382,16 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
 	if (retval)
 		goto out_path;
 
-	handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
-			 GFP_KERNEL);
-	if (!handle) {
-		retval = -ENOMEM;
-		goto out_path;
-	}
-	/* copy the full handle */
-	*handle = f_handle;
-	if (copy_from_user(&handle->f_handle,
-			   &ufh->f_handle,
-			   f_handle.handle_bytes)) {
-		retval = -EFAULT;
-		goto out_path;
-	}
-
 	/*
 	 * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we
 	 * are decoding an fd with connected path, which is accessible from
 	 * the mount fd path.
 	 */
-	if (f_handle.handle_type & FILEID_IS_CONNECTABLE) {
+	if (handle->handle_type & FILEID_IS_CONNECTABLE) {
 		ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
 		ctx.flags |= HANDLE_CHECK_SUBTREE;
 	}
-	if (f_handle.handle_type & FILEID_IS_DIR)
+	if (handle->handle_type & FILEID_IS_DIR)
 		ctx.fh_flags |= EXPORT_FH_DIR_ONLY;
 	/* Filesystem code should not be exposed to user flags */
 	handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
@@ -400,12 +405,17 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
 static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
 			   int open_flag)
 {
+	struct file_handle *handle __free(kfree) = NULL;
 	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);
+	handle = get_user_handle(ufh);
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+
+	retval = handle_to_path(mountdirfd, handle, &path, open_flag);
 	if (retval)
 		return retval;
 
diff --git a/fs/internal.h b/fs/internal.h
index c972f8ade52d..ab80f83ded47 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -363,4 +363,7 @@ void pidfs_get_root(struct path *path);
 long do_sys_name_to_handle_at(int dfd, const char __user *name,
 			      struct file_handle __user *handle,
 			      void __user *mnt_id, int flag, int lookup_flags);
+struct file_handle *get_user_handle(struct file_handle __user *ufh);
+int handle_to_path(int mountdirfd, struct file_handle *handle,
+		   struct path *path, unsigned int o_flags);
 #endif /* CONFIG_FHANDLE */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 04/10] fhandle: create do_filp_path_open() helper
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
                   ` (2 preceding siblings ...)
  2025-09-10 21:49 ` [PATCH 03/10] fhandle: helper for allocating, reading struct file_handle Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-11  0:53   ` Al Viro
  2025-09-10 21:49 ` [PATCH 05/10] fhandle: make do_filp_path_open() take struct open_flags Thomas Bertschinger
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger

This pulls the code for opening a file, after its handle has been
converted to a struct path, into a new helper function.

This function will be used by io_uring once io_uring supports
open_by_handle_at(2).

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 fs/fhandle.c  | 21 +++++++++++++++------
 fs/internal.h |  1 +
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/fs/fhandle.c b/fs/fhandle.c
index 36e194dd4cb6..91b0d340a4d1 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -402,6 +402,20 @@ int handle_to_path(int mountdirfd, struct file_handle *handle,
 	return retval;
 }
 
+struct file *do_filp_path_open(struct path *path, int open_flag)
+{
+	const struct export_operations *eops;
+	struct file *file;
+
+	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);
+
+	return file;
+}
+
 static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
 			   int open_flag)
 {
@@ -409,7 +423,6 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
 	long retval = 0;
 	struct path path __free(path_put) = {};
 	struct file *file;
-	const struct export_operations *eops;
 
 	handle = get_user_handle(ufh);
 	if (IS_ERR(handle))
@@ -423,11 +436,7 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
 	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);
+	file = do_filp_path_open(&path, open_flag);
 	if (IS_ERR(file))
 		return PTR_ERR(file);
 
diff --git a/fs/internal.h b/fs/internal.h
index ab80f83ded47..599e0d7b450e 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -366,4 +366,5 @@ long do_sys_name_to_handle_at(int dfd, const char __user *name,
 struct file_handle *get_user_handle(struct file_handle __user *ufh);
 int handle_to_path(int mountdirfd, struct file_handle *handle,
 		   struct path *path, unsigned int o_flags);
+struct file *do_filp_path_open(struct path *path, int open_flag);
 #endif /* CONFIG_FHANDLE */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 05/10] fhandle: make do_filp_path_open() take struct open_flags
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
                   ` (3 preceding siblings ...)
  2025-09-10 21:49 ` [PATCH 04/10] fhandle: create do_filp_path_open() helper Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 06/10] exportfs: allow VFS flags in struct file_handle Thomas Bertschinger
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger

This allows the caller to pass additional flags, such as lookup flags,
if desired.

This will be used by io_uring to support non-blocking
open_by_handle_at(2).

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 fs/fhandle.c  | 14 ++++++++++----
 fs/internal.h |  2 +-
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/fs/fhandle.c b/fs/fhandle.c
index 91b0d340a4d1..01fc209853d8 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -402,16 +402,16 @@ int handle_to_path(int mountdirfd, struct file_handle *handle,
 	return retval;
 }
 
-struct file *do_filp_path_open(struct path *path, int open_flag)
+struct file *do_filp_path_open(struct path *path, struct open_flags *op)
 {
 	const struct export_operations *eops;
 	struct file *file;
 
 	eops = path->mnt->mnt_sb->s_export_op;
 	if (eops->open)
-		file = eops->open(path, open_flag);
+		file = eops->open(path, op->open_flag);
 	else
-		file = file_open_root(path, "", open_flag, 0);
+		file = do_file_open_root(path, "", op);
 
 	return file;
 }
@@ -423,6 +423,8 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
 	long retval = 0;
 	struct path path __free(path_put) = {};
 	struct file *file;
+	struct open_flags op;
+	struct open_how how;
 
 	handle = get_user_handle(ufh);
 	if (IS_ERR(handle))
@@ -436,7 +438,11 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
 	if (fd < 0)
 		return fd;
 
-	file = do_filp_path_open(&path, open_flag);
+	how = build_open_how(open_flag, 0);
+	retval = build_open_flags(&how, &op);
+	if (retval)
+		return retval;
+	file = do_filp_path_open(&path, &op);
 	if (IS_ERR(file))
 		return PTR_ERR(file);
 
diff --git a/fs/internal.h b/fs/internal.h
index 599e0d7b450e..0236391297bf 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -366,5 +366,5 @@ long do_sys_name_to_handle_at(int dfd, const char __user *name,
 struct file_handle *get_user_handle(struct file_handle __user *ufh);
 int handle_to_path(int mountdirfd, struct file_handle *handle,
 		   struct path *path, unsigned int o_flags);
-struct file *do_filp_path_open(struct path *path, int open_flag);
+struct file *do_filp_path_open(struct path *path, struct open_flags *op);
 #endif /* CONFIG_FHANDLE */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 06/10] exportfs: allow VFS flags in struct file_handle
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
                   ` (4 preceding siblings ...)
  2025-09-10 21:49 ` [PATCH 05/10] fhandle: make do_filp_path_open() take struct open_flags Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-11 12:24   ` Amir Goldstein
  2025-09-10 21:49 ` [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup Thomas Bertschinger
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger, Amir Goldstein, chuck.lever, jlayton

The handle_type field of struct file_handle is already being used to
pass "user" flags to open_by_handle_at() in the upper 16 bits.

Bits 8..15 are still unused, as FS implementations are expected to only
set the lower 8 bits.

This change prepares the VFS to pass flags to FS implementations of
fh_to_{dentry,parent}() using the previously unused bits 8..15 of
handle_type.

The user is prevented from setting VFS flags in a file handle--such a
handle will be rejected by open_by_handle_at(2). Only the VFS can set
those flags before passing the handle to the FS.

Suggested-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 fs/exportfs/expfs.c      |  2 +-
 fs/fhandle.c             |  2 +-
 include/linux/exportfs.h | 29 ++++++++++++++++++++++++++---
 3 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index d3e55de4a2a2..949ce6ef6c4e 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -391,7 +391,7 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
 	else
 		type = nop->encode_fh(inode, fid->raw, max_len, parent);
 
-	if (type > 0 && FILEID_USER_FLAGS(type)) {
+	if (type > 0 && (type & ~FILEID_HANDLE_TYPE_MASK)) {
 		pr_warn_once("%s: unexpected fh type value 0x%x from fstype %s.\n",
 			     __func__, type, inode->i_sb->s_type->name);
 		return -EINVAL;
diff --git a/fs/fhandle.c b/fs/fhandle.c
index 01fc209853d8..276c16454eb7 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -342,7 +342,7 @@ struct file_handle *get_user_handle(struct file_handle __user *ufh)
 	    (f_handle.handle_bytes == 0))
 		return ERR_PTR(-EINVAL);
 
-	if (f_handle.handle_type < 0 ||
+	if (f_handle.handle_type < 0 || FILEID_FS_FLAGS(f_handle.handle_type) ||
 	    FILEID_USER_FLAGS(f_handle.handle_type) & ~FILEID_VALID_USER_FLAGS)
 		return ERR_PTR(-EINVAL);
 
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index cfb0dd1ea49c..30a9791d88e0 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -173,10 +173,33 @@ struct handle_to_path_ctx {
 #define EXPORT_FH_DIR_ONLY	0x4 /* Only decode file handle for a directory */
 
 /*
- * Filesystems use only lower 8 bits of file_handle type for fid_type.
- * name_to_handle_at() uses upper 16 bits of type as user flags to be
- * interpreted by open_by_handle_at().
+ * The 32 bits of the handle_type field of struct file_handle are used for a few
+ * different purposes:
+ *
+ *   Filesystems use only lower 8 bits of file_handle type for fid_type.
+ *
+ *   VFS uses bits 8..15 of the handle_type to pass flags to the FS
+ *   implementation of fh_to_{dentry,parent}().
+ *
+ *   name_to_handle_at() uses upper 16 bits of type as user flags to be
+ *   interpreted by open_by_handle_at().
+ *
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |           user flags          |   VFS flags   |   fid_type    |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  (MSB)                                                       (LSB)
+ *
+ * Filesystems are expected not to fill in any bits outside of fid_type in
+ * their encode_fh() implementation.
  */
+#define FILEID_HANDLE_TYPE_MASK	0xff
+#define FILEID_TYPE(type)	((type) & FILEID_HANDLE_TYPE_MASK)
+
+/* VFS flags: */
+#define FILEID_FS_FLAGS_MASK	0xff00
+#define FILEID_FS_FLAGS(flags)	((flags) & FILEID_FS_FLAGS_MASK)
+
+/* User flags: */
 #define FILEID_USER_FLAGS_MASK	0xffff0000
 #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
                   ` (5 preceding siblings ...)
  2025-09-10 21:49 ` [PATCH 06/10] exportfs: allow VFS flags in struct file_handle Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-11 12:31   ` Amir Goldstein
  2025-09-12  8:21   ` Dan Carpenter
  2025-09-10 21:49 ` [PATCH 08/10] io_uring: add __io_open_prep() helper Thomas Bertschinger
                   ` (2 subsequent siblings)
  9 siblings, 2 replies; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger, Amir Goldstein, chuck.lever, jlayton

This defines a new flag FILEID_CACHED that the VFS can set in the
handle_type field of struct file_handle to request that the FS
implementations of fh_to_{dentry,parent}() only complete if they can
satisfy the request with cached data.

Because not every FS implementation will recognize this new flag, those
that do recognize the flag can indicate their support using a new
export flag, EXPORT_OP_NONBLOCK.

If FILEID_CACHED is set in a file handle, but the filesystem does not
set EXPORT_OP_NONBLOCK, then the VFS will return -EAGAIN without
attempting to call into the filesystem code.

exportfs_decode_fh_raw() is updated to respect the new flag by returning
-EAGAIN when it would need to do an operation that may not be possible
with only cached data.

Suggested-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 fs/exportfs/expfs.c      | 13 +++++++++++++
 fs/fhandle.c             |  2 ++
 include/linux/exportfs.h |  5 +++++
 3 files changed, 20 insertions(+)

diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 949ce6ef6c4e..88418b93abbf 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -441,6 +441,7 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
 		       void *context)
 {
 	const struct export_operations *nop = mnt->mnt_sb->s_export_op;
+	bool decode_cached = fileid_type & FILEID_CACHED;
 	struct dentry *result, *alias;
 	char nbuf[NAME_MAX+1];
 	int err;
@@ -453,6 +454,10 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
 	 */
 	if (!exportfs_can_decode_fh(nop))
 		return ERR_PTR(-ESTALE);
+
+	if (decode_cached && !(nop->flags & EXPORT_OP_NONBLOCK))
+		return ERR_PTR(-EAGAIN);
+
 	result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
 	if (IS_ERR_OR_NULL(result))
 		return result;
@@ -481,6 +486,10 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
 		 * filesystem root.
 		 */
 		if (result->d_flags & DCACHE_DISCONNECTED) {
+			err = -EAGAIN;
+			if (decode_cached)
+				goto err_result;
+
 			err = reconnect_path(mnt, result, nbuf);
 			if (err)
 				goto err_result;
@@ -526,6 +535,10 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
 		err = PTR_ERR(target_dir);
 		if (IS_ERR(target_dir))
 			goto err_result;
+		err = -EAGAIN;
+		if (decode_cached & (target_dir->d_flags & DCACHE_DISCONNECTED)) {
+			goto err_result;
+		}
 
 		/*
 		 * And as usual we need to make sure the parent directory is
diff --git a/fs/fhandle.c b/fs/fhandle.c
index 276c16454eb7..70e265f6a3ab 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -273,6 +273,8 @@ static int do_handle_to_path(struct file_handle *handle, struct path *path,
 	if (IS_ERR_OR_NULL(dentry)) {
 		if (dentry == ERR_PTR(-ENOMEM))
 			return -ENOMEM;
+		if (dentry == ERR_PTR(-EAGAIN))
+			return -EAGAIN;
 		return -ESTALE;
 	}
 	path->dentry = dentry;
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 30a9791d88e0..8238b6f67956 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -199,6 +199,8 @@ struct handle_to_path_ctx {
 #define FILEID_FS_FLAGS_MASK	0xff00
 #define FILEID_FS_FLAGS(flags)	((flags) & FILEID_FS_FLAGS_MASK)
 
+#define FILEID_CACHED		0x100 /* Use only cached data when decoding handle */
+
 /* User flags: */
 #define FILEID_USER_FLAGS_MASK	0xffff0000
 #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
@@ -303,6 +305,9 @@ struct export_operations {
 						*/
 #define EXPORT_OP_FLUSH_ON_CLOSE	(0x20) /* fs flushes file data on close */
 #define EXPORT_OP_NOLOCKS		(0x40) /* no file locking support */
+#define EXPORT_OP_NONBLOCK		(0x80) /* Filesystem supports non-
+						  blocking fh_to_dentry()
+						*/
 	unsigned long	flags;
 };
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 08/10] io_uring: add __io_open_prep() helper
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
                   ` (6 preceding siblings ...)
  2025-09-10 21:49 ` [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 09/10] io_uring: add support for IORING_OP_OPEN_BY_HANDLE_AT Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry() Thomas Bertschinger
  9 siblings, 0 replies; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger

This adds a helper, __io_open_prep(), which does the part of preparing
for an open that is shared between openat*() and open_by_handle_at().

It excludes reading in the user path or file handle--this will be done
by functions specific to the kind of open().

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 io_uring/openclose.c | 35 +++++++++++++++++++++++++----------
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/io_uring/openclose.c b/io_uring/openclose.c
index 884a66e56643..4da2afdb9773 100644
--- a/io_uring/openclose.c
+++ b/io_uring/openclose.c
@@ -58,11 +58,10 @@ static bool io_openat_force_async(struct io_open *open)
 	return open->how.flags & (O_TRUNC | O_CREAT | __O_TMPFILE);
 }
 
-static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+/* Prep for open that is common to both openat*() and open_by_handle_at() */
+static int __io_open_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
 	struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
-	const char __user *fname;
-	int ret;
 
 	if (unlikely(sqe->buf_index))
 		return -EINVAL;
@@ -74,6 +73,29 @@ static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
 		open->how.flags |= O_LARGEFILE;
 
 	open->dfd = READ_ONCE(sqe->fd);
+
+	open->file_slot = READ_ONCE(sqe->file_index);
+	if (open->file_slot && (open->how.flags & O_CLOEXEC))
+		return -EINVAL;
+
+	open->nofile = rlimit(RLIMIT_NOFILE);
+
+	if (io_openat_force_async(open))
+		req->flags |= REQ_F_FORCE_ASYNC;
+
+	return 0;
+}
+
+static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+	struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
+	const char __user *fname;
+	int ret;
+
+	ret = __io_open_prep(req, sqe);
+	if (ret)
+		return ret;
+
 	fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
 	open->filename = getname(fname);
 	if (IS_ERR(open->filename)) {
@@ -82,14 +104,7 @@ static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
 		return ret;
 	}
 
-	open->file_slot = READ_ONCE(sqe->file_index);
-	if (open->file_slot && (open->how.flags & O_CLOEXEC))
-		return -EINVAL;
-
-	open->nofile = rlimit(RLIMIT_NOFILE);
 	req->flags |= REQ_F_NEED_CLEANUP;
-	if (io_openat_force_async(open))
-		req->flags |= REQ_F_FORCE_ASYNC;
 	return 0;
 }
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 09/10] io_uring: add support for IORING_OP_OPEN_BY_HANDLE_AT
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
                   ` (7 preceding siblings ...)
  2025-09-10 21:49 ` [PATCH 08/10] io_uring: add __io_open_prep() helper Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-10 21:49 ` [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry() Thomas Bertschinger
  9 siblings, 0 replies; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger, chuck.lever, jlayton

This adds support for open_by_handle_at(2) to io_uring.

First an attempt to do a non-blocking open by handle is made. If that
fails, for example, because the target inode is not cached, a blocking
attempt is made.

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 include/uapi/linux/io_uring.h |   1 +
 io_uring/opdef.c              |  15 +++++
 io_uring/openclose.c          | 111 ++++++++++++++++++++++++++++++++++
 io_uring/openclose.h          |   8 +++
 4 files changed, 135 insertions(+)

diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index a4aa83ad9527..c571929e7807 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -291,6 +291,7 @@ enum io_uring_op {
 	IORING_OP_WRITEV_FIXED,
 	IORING_OP_PIPE,
 	IORING_OP_NAME_TO_HANDLE_AT,
+	IORING_OP_OPEN_BY_HANDLE_AT,
 
 	/* this goes last, obviously */
 	IORING_OP_LAST,
diff --git a/io_uring/opdef.c b/io_uring/opdef.c
index 76306c9e0ecd..1aa36f3f30de 100644
--- a/io_uring/opdef.c
+++ b/io_uring/opdef.c
@@ -580,6 +580,15 @@ const struct io_issue_def io_issue_defs[] = {
 		.issue			= io_name_to_handle_at,
 #else
 		.prep			= io_eopnotsupp_prep,
+#endif
+	},
+	[IORING_OP_OPEN_BY_HANDLE_AT] = {
+#if defined(CONFIG_FHANDLE)
+		.prep			= io_open_by_handle_at_prep,
+		.issue			= io_open_by_handle_at,
+		.async_size		= sizeof(struct io_open_handle_async),
+#else
+		.prep			= io_eopnotsupp_prep,
 #endif
 	},
 };
@@ -835,6 +844,12 @@ const struct io_cold_def io_cold_defs[] = {
 	[IORING_OP_NAME_TO_HANDLE_AT] = {
 		.name			= "NAME_TO_HANDLE_AT",
 	},
+	[IORING_OP_OPEN_BY_HANDLE_AT] = {
+		.name			= "OPEN_BY_HANDLE_AT",
+#if defined(CONFIG_FHANDLE)
+		.cleanup		= io_open_by_handle_cleanup,
+#endif
+	}
 };
 
 const char *io_uring_get_opcode(u8 opcode)
diff --git a/io_uring/openclose.c b/io_uring/openclose.c
index 4da2afdb9773..dbc883f4654c 100644
--- a/io_uring/openclose.c
+++ b/io_uring/openclose.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/exportfs.h>
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
@@ -245,6 +246,116 @@ int io_name_to_handle_at(struct io_kiocb *req, unsigned int issue_flags)
 	io_req_set_res(req, ret, 0);
 	return IOU_COMPLETE;
 }
+
+int io_open_by_handle_at_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+	struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
+	struct io_open_handle_async *ah;
+	u64 flags;
+	int ret;
+
+	flags = READ_ONCE(sqe->open_flags);
+	open->how = build_open_how(flags, 0);
+
+	ret = __io_open_prep(req, sqe);
+	if (ret)
+		return ret;
+
+	ah = io_uring_alloc_async_data(NULL, req);
+	if (!ah)
+		return -ENOMEM;
+	memset(&ah->path, 0, sizeof(ah->path));
+	ah->handle = get_user_handle(u64_to_user_ptr(READ_ONCE(sqe->addr)));
+	if (IS_ERR(ah->handle))
+		return PTR_ERR(ah->handle);
+
+	req->flags |= REQ_F_NEED_CLEANUP;
+
+	return 0;
+}
+
+int io_open_by_handle_at(struct io_kiocb *req, unsigned int issue_flags)
+{
+	struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
+	struct io_open_handle_async *ah = req->async_data;
+	bool nonblock_set = open->how.flags & O_NONBLOCK;
+	bool fixed = !!open->file_slot;
+	struct file *file;
+	struct open_flags op;
+	int ret;
+
+	ret = build_open_flags(&open->how, &op);
+	if (ret)
+		goto err;
+
+	if (issue_flags & IO_URING_F_NONBLOCK)
+		ah->handle->handle_type |= FILEID_CACHED;
+	else
+		ah->handle->handle_type &= ~FILEID_CACHED;
+
+	if (!ah->path.dentry) {
+		/*
+		 * Handle has not yet been converted to path, either because
+		 * this is our first try, or because we tried previously with
+		 * IO_URING_F_NONBLOCK set, and failed.
+		 */
+		ret = handle_to_path(open->dfd, ah->handle, &ah->path, op.open_flag);
+		if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
+			return -EAGAIN;
+
+		if (ret)
+			goto err;
+	}
+
+	if (!fixed) {
+		ret = __get_unused_fd_flags(open->how.flags, open->nofile);
+		if (ret < 0)
+			goto err;
+	}
+
+	if (issue_flags & IO_URING_F_NONBLOCK) {
+		WARN_ON_ONCE(io_openat_force_async(open));
+		op.lookup_flags |= LOOKUP_CACHED;
+		op.open_flag |= O_NONBLOCK;
+	}
+	file = do_filp_path_open(&ah->path, &op);
+
+	if (IS_ERR(file)) {
+		if (!fixed)
+			put_unused_fd(ret);
+		ret = PTR_ERR(file);
+		if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
+			return -EAGAIN;
+		goto err;
+	}
+
+	if ((issue_flags & IO_URING_F_NONBLOCK) && !nonblock_set)
+		file->f_flags &= ~O_NONBLOCK;
+
+	if (!fixed)
+		fd_install(ret, file);
+	else
+		ret = io_fixed_fd_install(req, issue_flags, file,
+					  open->file_slot);
+
+err:
+	io_open_by_handle_cleanup(req);
+	req->flags &= ~REQ_F_NEED_CLEANUP;
+	if (ret < 0)
+		req_set_fail(req);
+	io_req_set_res(req, ret, 0);
+	return IOU_COMPLETE;
+}
+
+void io_open_by_handle_cleanup(struct io_kiocb *req)
+{
+	struct io_open_handle_async *ah = req->async_data;
+	if (ah->path.dentry) {
+		path_put(&ah->path);
+	}
+
+	kfree(ah->handle);
+}
 #endif /* CONFIG_FHANDLE */
 
 int __io_close_fixed(struct io_ring_ctx *ctx, unsigned int issue_flags,
diff --git a/io_uring/openclose.h b/io_uring/openclose.h
index 2fc1c8d35d0b..f966859a8a92 100644
--- a/io_uring/openclose.h
+++ b/io_uring/openclose.h
@@ -10,9 +10,17 @@ void io_open_cleanup(struct io_kiocb *req);
 int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
 int io_openat2(struct io_kiocb *req, unsigned int issue_flags);
 
+struct io_open_handle_async {
+	struct file_handle		*handle;
+	struct path			path;
+};
+
 #if defined(CONFIG_FHANDLE)
 int io_name_to_handle_at_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
 int io_name_to_handle_at(struct io_kiocb *req, unsigned int issue_flags);
+int io_open_by_handle_at_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_open_by_handle_at(struct io_kiocb *req, unsigned int issue_flags);
+void io_open_by_handle_cleanup(struct io_kiocb *req);
 #endif /* CONFIG_FHANDLE */
 
 int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry()
  2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
                   ` (8 preceding siblings ...)
  2025-09-10 21:49 ` [PATCH 09/10] io_uring: add support for IORING_OP_OPEN_BY_HANDLE_AT Thomas Bertschinger
@ 2025-09-10 21:49 ` Thomas Bertschinger
  2025-09-11 12:29   ` Christoph Hellwig
  2025-09-11 12:38   ` Amir Goldstein
  9 siblings, 2 replies; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-10 21:49 UTC (permalink / raw)
  To: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs
  Cc: Thomas Bertschinger, linux-xfs, cem

This is to support using open_by_handle_at(2) via io_uring. It is useful
for io_uring to request that opening a file via handle be completed
using only cached data, or fail with -EAGAIN if that is not possible.

The signature of xfs_nfs_get_inode() is extended with a new flags
argument that allows callers to specify XFS_IGET_INCORE.

That flag is set when the VFS passes the FILEID_CACHED flag via the
fileid_type argument.

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
 fs/xfs/xfs_export.c | 32 ++++++++++++++++++++++++++------
 fs/xfs/xfs_export.h |  3 ++-
 fs/xfs/xfs_handle.c |  2 +-
 3 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c
index 201489d3de08..ca2a9ed0eb16 100644
--- a/fs/xfs/xfs_export.c
+++ b/fs/xfs/xfs_export.c
@@ -106,7 +106,8 @@ struct inode *
 xfs_nfs_get_inode(
 	struct super_block	*sb,
 	u64			ino,
-	u32			generation)
+	u32			generation,
+	uint			flags)
 {
  	xfs_mount_t		*mp = XFS_M(sb);
 	xfs_inode_t		*ip;
@@ -123,7 +124,9 @@ xfs_nfs_get_inode(
 	 * fine and not an indication of a corrupted filesystem as clients can
 	 * send invalid file handles and we have to handle it gracefully..
 	 */
-	error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip);
+	flags |= XFS_IGET_UNTRUSTED;
+
+	error = xfs_iget(mp, NULL, ino, flags, 0, &ip);
 	if (error) {
 
 		/*
@@ -140,6 +143,10 @@ xfs_nfs_get_inode(
 		case -EFSCORRUPTED:
 			error = -ESTALE;
 			break;
+		case -ENODATA:
+			if (flags & XFS_IGET_INCORE)
+				error = -EAGAIN;
+			break;
 		default:
 			break;
 		}
@@ -174,6 +181,12 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
 {
 	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
 	struct inode		*inode = NULL;
+	uint			flags = 0;
+
+	if (fileid_type & FILEID_CACHED)
+		flags = XFS_IGET_INCORE;
+
+	fileid_type = FILEID_TYPE(fileid_type);
 
 	if (fh_len < xfs_fileid_length(fileid_type))
 		return NULL;
@@ -181,11 +194,11 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
 	switch (fileid_type) {
 	case FILEID_INO32_GEN_PARENT:
 	case FILEID_INO32_GEN:
-		inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
+		inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen, flags);
 		break;
 	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
 	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
-		inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
+		inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen, flags);
 		break;
 	}
 
@@ -198,6 +211,12 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
 {
 	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
 	struct inode		*inode = NULL;
+	uint			flags = 0;
+
+	if (fileid_type & FILEID_CACHED)
+		flags = XFS_IGET_INCORE;
+
+	fileid_type = FILEID_TYPE(fileid_type);
 
 	if (fh_len < xfs_fileid_length(fileid_type))
 		return NULL;
@@ -205,11 +224,11 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
 	switch (fileid_type) {
 	case FILEID_INO32_GEN_PARENT:
 		inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
-					      fid->i32.parent_gen);
+					      fid->i32.parent_gen, flags);
 		break;
 	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
 		inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
-					      fid64->parent_gen);
+					      fid64->parent_gen, flags);
 		break;
 	}
 
@@ -248,4 +267,5 @@ const struct export_operations xfs_export_operations = {
 	.map_blocks		= xfs_fs_map_blocks,
 	.commit_blocks		= xfs_fs_commit_blocks,
 #endif
+	.flags			= EXPORT_OP_NONBLOCK,
 };
diff --git a/fs/xfs/xfs_export.h b/fs/xfs/xfs_export.h
index 3cd85e8901a5..9addfcd5b1e1 100644
--- a/fs/xfs/xfs_export.h
+++ b/fs/xfs/xfs_export.h
@@ -57,6 +57,7 @@ struct xfs_fid64 {
 /* This flag goes on the wire.  Don't play with it. */
 #define XFS_FILEID_TYPE_64FLAG	0x80	/* NFS fileid has 64bit inodes */
 
-struct inode *xfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 gen);
+struct inode *xfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 gen,
+				uint flags);
 
 #endif	/* __XFS_EXPORT_H__ */
diff --git a/fs/xfs/xfs_handle.c b/fs/xfs/xfs_handle.c
index f19fce557354..7d877ff504d6 100644
--- a/fs/xfs/xfs_handle.c
+++ b/fs/xfs/xfs_handle.c
@@ -193,7 +193,7 @@ xfs_khandle_to_inode(
 		return ERR_PTR(-EINVAL);
 
 	inode = xfs_nfs_get_inode(mp->m_super, handle->ha_fid.fid_ino,
-			handle->ha_fid.fid_gen);
+			handle->ha_fid.fid_gen, 0);
 	if (IS_ERR(inode))
 		return ERR_CAST(inode);
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 04/10] fhandle: create do_filp_path_open() helper
  2025-09-10 21:49 ` [PATCH 04/10] fhandle: create do_filp_path_open() helper Thomas Bertschinger
@ 2025-09-11  0:53   ` Al Viro
  2025-09-11 12:21     ` Amir Goldstein
  0 siblings, 1 reply; 25+ messages in thread
From: Al Viro @ 2025-09-11  0:53 UTC (permalink / raw)
  To: Thomas Bertschinger; +Cc: io-uring, axboe, linux-fsdevel, brauner, linux-nfs

On Wed, Sep 10, 2025 at 03:49:21PM -0600, Thomas Bertschinger wrote:
> This pulls the code for opening a file, after its handle has been
> converted to a struct path, into a new helper function.
> 
> This function will be used by io_uring once io_uring supports
> open_by_handle_at(2).

Not commenting on the rest of patchset, but...

Consider the choice of name NAKed with extreme prejudice.  "filp"
thing should die; please, do not introduce more instances.

It has crawled out of Minix guts, where AST had been tasteless enough
to call a structure the represents an open file (which is called struct
file on all Unices, Linux included) "struct filp" instead, the identifier
standing for "file and position", nevermind that he did include more
state than that - the damn thing (in OSD&I appendix) is
struct filp {
  mask_bits filp_mode;		/* RW bits, telling how file is opened */
  int filp_count;		/* how many file descriptors share this slot? */
  struct inode *filp_ino;	/* pointer to the inode */
  file_pos filp_pos;		/* file position */
}


Linus used "struct file" from the very beginning; unfortunately, if you
grep for filp in 0.01 you'll see a plenty of those - in form of
0.01:fs/file_dev.c:int file_write(struct m_inode * inode, struct file * filp, char * buf, int count)
as well as
0.01:fs/ioctl.c:        struct file * filp;
0.01:fs/ioctl.c:        if (fd >= NR_OPEN || !(filp = current->filp[fd]))
which was both inconsistent *and* resembling hungarian notation just
enough to confuse (note that in the original that 'p' does *NOT* stand for
"pointer" - it's "current IO position").  Unfortunately, it was confusing
enough to stick around; at some point it even leaked into function names
(filp_open(); that one is my fault - sorry for that brainfart).

Let's not propagate that wart any further, please.  If you are opening a file,
put "file" in the identifier.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] fhandle: create helper for name_to_handle_at(2)
  2025-09-10 21:49 ` [PATCH 01/10] fhandle: create helper for name_to_handle_at(2) Thomas Bertschinger
@ 2025-09-11 12:06   ` Amir Goldstein
  0 siblings, 0 replies; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 12:06 UTC (permalink / raw)
  To: Thomas Bertschinger
  Cc: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs

On Wed, Sep 10, 2025 at 11:47 PM Thomas Bertschinger
<tahbertschinger@gmail.com> wrote:
>
> Create a helper do_sys_name_to_handle_at() that takes an additional
> argument, lookup_flags, beyond the syscall arguments.
>
> Because name_to_handle_at(2) doesn't take any lookup flags, it always
> passes 0 for this argument.
>
> Future callers like io_uring may pass LOOKUP_CACHED in order to request
> a non-blocking lookup.
>
> This helper's name is confusingly similar to do_sys_name_to_handle()
> which takes care of returning the file handle, once the filename has
> been turned into a struct path. To distinguish the names more clearly,
> rename the latter to do_path_to_handle().
>
> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>

Thomas,

If you post another patch set please use git-format -v3 to add v3
to all patch subjects (not only to cover letter subject).

Feel free to add:

Reviewed-by: Amir Goldstein <amir73il@gmail.com>

Thanks,
Amir.

> ---
>  fs/fhandle.c  | 61 ++++++++++++++++++++++++++++-----------------------
>  fs/internal.h |  9 ++++++++
>  2 files changed, 43 insertions(+), 27 deletions(-)
>
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index 68a7d2861c58..605ad8e7d93d 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -14,10 +14,10 @@
>  #include "internal.h"
>  #include "mount.h"
>
> -static long do_sys_name_to_handle(const struct path *path,
> -                                 struct file_handle __user *ufh,
> -                                 void __user *mnt_id, bool unique_mntid,
> -                                 int fh_flags)
> +static long do_path_to_handle(const struct path *path,
> +                             struct file_handle __user *ufh,
> +                             void __user *mnt_id, bool unique_mntid,
> +                             int fh_flags)
>  {
>         long retval;
>         struct file_handle f_handle;
> @@ -111,27 +111,11 @@ static long do_sys_name_to_handle(const struct path *path,
>         return retval;
>  }
>
> -/**
> - * sys_name_to_handle_at: convert name to handle
> - * @dfd: directory relative to which name is interpreted if not absolute
> - * @name: name that should be converted to handle.
> - * @handle: resulting file handle
> - * @mnt_id: mount id of the file system containing the file
> - *          (u64 if AT_HANDLE_MNT_ID_UNIQUE, otherwise int)
> - * @flag: flag value to indicate whether to follow symlink or not
> - *        and whether a decodable file handle is required.
> - *
> - * @handle->handle_size indicate the space available to store the
> - * variable part of the file handle in bytes. If there is not
> - * enough space, the field is updated to return the minimum
> - * value required.
> - */
> -SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
> -               struct file_handle __user *, handle, void __user *, mnt_id,
> -               int, flag)
> +long do_sys_name_to_handle_at(int dfd, const char __user *name,
> +                             struct file_handle __user *handle,
> +                             void __user *mnt_id, int flag, int lookup_flags)
>  {
>         struct path path;
> -       int lookup_flags;
>         int fh_flags = 0;
>         int err;
>
> @@ -155,19 +139,42 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
>         else if (flag & AT_HANDLE_CONNECTABLE)
>                 fh_flags |= EXPORT_FH_CONNECTABLE;
>
> -       lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
> +       if (flag & AT_SYMLINK_FOLLOW)
> +               lookup_flags |= LOOKUP_FOLLOW;
>         if (flag & AT_EMPTY_PATH)
>                 lookup_flags |= LOOKUP_EMPTY;
>         err = user_path_at(dfd, name, lookup_flags, &path);
>         if (!err) {
> -               err = do_sys_name_to_handle(&path, handle, mnt_id,
> -                                           flag & AT_HANDLE_MNT_ID_UNIQUE,
> -                                           fh_flags);
> +               err = do_path_to_handle(&path, handle, mnt_id,
> +                                       flag & AT_HANDLE_MNT_ID_UNIQUE,
> +                                       fh_flags);
>                 path_put(&path);
>         }
>         return err;
>  }
>
> +/**
> + * sys_name_to_handle_at: convert name to handle
> + * @dfd: directory relative to which name is interpreted if not absolute
> + * @name: name that should be converted to handle.
> + * @handle: resulting file handle
> + * @mnt_id: mount id of the file system containing the file
> + *          (u64 if AT_HANDLE_MNT_ID_UNIQUE, otherwise int)
> + * @flag: flag value to indicate whether to follow symlink or not
> + *        and whether a decodable file handle is required.
> + *
> + * @handle->handle_size indicate the space available to store the
> + * variable part of the file handle in bytes. If there is not
> + * enough space, the field is updated to return the minimum
> + * value required.
> + */
> +SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
> +               struct file_handle __user *, handle, void __user *, mnt_id,
> +               int, flag)
> +{
> +       return do_sys_name_to_handle_at(dfd, name, handle, mnt_id, flag, 0);
> +}
> +
>  static int get_path_anchor(int fd, struct path *root)
>  {
>         if (fd >= 0) {
> diff --git a/fs/internal.h b/fs/internal.h
> index 38e8aab27bbd..c972f8ade52d 100644
> --- a/fs/internal.h
> +++ b/fs/internal.h
> @@ -355,3 +355,12 @@ int anon_inode_getattr(struct mnt_idmap *idmap, const struct path *path,
>  int anon_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
>                        struct iattr *attr);
>  void pidfs_get_root(struct path *path);
> +
> +/*
> + * fs/fhandle.c
> + */
> +#ifdef CONFIG_FHANDLE
> +long do_sys_name_to_handle_at(int dfd, const char __user *name,
> +                             struct file_handle __user *handle,
> +                             void __user *mnt_id, int flag, int lookup_flags);
> +#endif /* CONFIG_FHANDLE */
> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 03/10] fhandle: helper for allocating, reading struct file_handle
  2025-09-10 21:49 ` [PATCH 03/10] fhandle: helper for allocating, reading struct file_handle Thomas Bertschinger
@ 2025-09-11 12:15   ` Amir Goldstein
  2025-09-11 15:31     ` Thomas Bertschinger
  0 siblings, 1 reply; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 12:15 UTC (permalink / raw)
  To: Thomas Bertschinger
  Cc: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs

On Wed, Sep 10, 2025 at 11:47 PM Thomas Bertschinger
<tahbertschinger@gmail.com> wrote:
>
> Pull the code for allocating and copying a struct file_handle from
> userspace into a helper function get_user_handle() just for this.
>
> do_handle_open() is updated to call get_user_handle() prior to calling
> handle_to_path(), and the latter now takes a kernel pointer as a
> parameter instead of a __user pointer.
>
> This new helper, as well as handle_to_path(), are also exposed in
> fs/internal.h. In a subsequent commit, io_uring will use these helpers
> to support open_by_handle_at(2) in io_uring.
>
> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
> ---
>  fs/fhandle.c  | 64 +++++++++++++++++++++++++++++----------------------
>  fs/internal.h |  3 +++
>  2 files changed, 40 insertions(+), 27 deletions(-)
>
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index 605ad8e7d93d..36e194dd4cb6 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -330,25 +330,45 @@ static inline int may_decode_fh(struct handle_to_path_ctx *ctx,
>         return 0;
>  }
>
> -static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
> -                  struct path *path, unsigned int o_flags)
> +struct file_handle *get_user_handle(struct file_handle __user *ufh)
>  {
> -       int retval = 0;
>         struct file_handle f_handle;
> -       struct file_handle *handle __free(kfree) = NULL;
> -       struct handle_to_path_ctx ctx = {};
> -       const struct export_operations *eops;
> +       struct file_handle *handle;
>
>         if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
> -               return -EFAULT;
> +               return ERR_PTR(-EFAULT);
>
>         if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
>             (f_handle.handle_bytes == 0))
> -               return -EINVAL;
> +               return ERR_PTR(-EINVAL);
>
>         if (f_handle.handle_type < 0 ||
>             FILEID_USER_FLAGS(f_handle.handle_type) & ~FILEID_VALID_USER_FLAGS)
> -               return -EINVAL;
> +               return ERR_PTR(-EINVAL);
> +
> +       handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
> +                        GFP_KERNEL);
> +       if (!handle) {
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       /* copy the full handle */
> +       *handle = f_handle;
> +       if (copy_from_user(&handle->f_handle,
> +                          &ufh->f_handle,
> +                          f_handle.handle_bytes)) {
> +               return ERR_PTR(-EFAULT);
> +       }
> +
> +       return handle;
> +}
> +
> +int handle_to_path(int mountdirfd, struct file_handle *handle,
> +                  struct path *path, unsigned int o_flags)
> +{
> +       int retval = 0;
> +       struct handle_to_path_ctx ctx = {};
> +       const struct export_operations *eops;
>
>         retval = get_path_anchor(mountdirfd, &ctx.root);
>         if (retval)
> @@ -362,31 +382,16 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>         if (retval)
>                 goto out_path;
>
> -       handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
> -                        GFP_KERNEL);
> -       if (!handle) {
> -               retval = -ENOMEM;
> -               goto out_path;
> -       }
> -       /* copy the full handle */
> -       *handle = f_handle;
> -       if (copy_from_user(&handle->f_handle,
> -                          &ufh->f_handle,
> -                          f_handle.handle_bytes)) {
> -               retval = -EFAULT;
> -               goto out_path;
> -       }
> -
>         /*
>          * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we
>          * are decoding an fd with connected path, which is accessible from
>          * the mount fd path.
>          */
> -       if (f_handle.handle_type & FILEID_IS_CONNECTABLE) {
> +       if (handle->handle_type & FILEID_IS_CONNECTABLE) {
>                 ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
>                 ctx.flags |= HANDLE_CHECK_SUBTREE;
>         }
> -       if (f_handle.handle_type & FILEID_IS_DIR)
> +       if (handle->handle_type & FILEID_IS_DIR)
>                 ctx.fh_flags |= EXPORT_FH_DIR_ONLY;
>         /* Filesystem code should not be exposed to user flags */
>         handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
> @@ -400,12 +405,17 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>  static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
>                            int open_flag)
>  {
> +       struct file_handle *handle __free(kfree) = NULL;
>         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);
> +       handle = get_user_handle(ufh);
> +       if (IS_ERR(handle))
> +               return PTR_ERR(handle);

I don't think you can use __free(kfree) for something that can be an ERR_PTR.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 04/10] fhandle: create do_filp_path_open() helper
  2025-09-11  0:53   ` Al Viro
@ 2025-09-11 12:21     ` Amir Goldstein
  0 siblings, 0 replies; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 12:21 UTC (permalink / raw)
  To: Al Viro
  Cc: Thomas Bertschinger, io-uring, axboe, linux-fsdevel, brauner,
	linux-nfs

On Thu, Sep 11, 2025 at 2:53 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Wed, Sep 10, 2025 at 03:49:21PM -0600, Thomas Bertschinger wrote:
> > This pulls the code for opening a file, after its handle has been
> > converted to a struct path, into a new helper function.
> >
> > This function will be used by io_uring once io_uring supports
> > open_by_handle_at(2).
>
> Not commenting on the rest of patchset, but...
>
> Consider the choice of name NAKed with extreme prejudice.
> 0.01:fs/ioctl.c:        struct file * filp;
> 0.01:fs/ioctl.c:        if (fd >= NR_OPEN || !(filp = current->filp[fd]))
> which was both inconsistent *and* resembling hungarian notation just
> enough to confuse (note that in the original that 'p' does *NOT* stand for
> "pointer" - it's "current IO position").  Unfortunately, it was confusing
> enough to stick around; at some point it even leaked into function names
> (filp_open(); that one is my fault - sorry for that brainfart).
>
> Let's not propagate that wart any further, please.  If you are opening a file,
> put "file" in the identifier.
>

If I may join the bikeshedding. I find that an exported vfs helper called
do_file_path_open() does not sound like something that is expected
to call path.mnt->mnt_sb->s_export_op->open().

I am not sure how to express that in a good helper name.
IDK. Running out of names. Maybe do_handle_path_open()?

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 06/10] exportfs: allow VFS flags in struct file_handle
  2025-09-10 21:49 ` [PATCH 06/10] exportfs: allow VFS flags in struct file_handle Thomas Bertschinger
@ 2025-09-11 12:24   ` Amir Goldstein
  0 siblings, 0 replies; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 12:24 UTC (permalink / raw)
  To: Thomas Bertschinger
  Cc: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs,
	chuck.lever, jlayton

On Wed, Sep 10, 2025 at 11:47 PM Thomas Bertschinger
<tahbertschinger@gmail.com> wrote:
>
> The handle_type field of struct file_handle is already being used to
> pass "user" flags to open_by_handle_at() in the upper 16 bits.
>
> Bits 8..15 are still unused, as FS implementations are expected to only
> set the lower 8 bits.
>
> This change prepares the VFS to pass flags to FS implementations of
> fh_to_{dentry,parent}() using the previously unused bits 8..15 of
> handle_type.
>
> The user is prevented from setting VFS flags in a file handle--such a
> handle will be rejected by open_by_handle_at(2). Only the VFS can set
> those flags before passing the handle to the FS.
>
> Suggested-by: Amir Goldstein <amir73il@gmail.com>
> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>

Reviewed-by: Amir Goldstein <amir73il@gmail.com>

> ---
>  fs/exportfs/expfs.c      |  2 +-
>  fs/fhandle.c             |  2 +-
>  include/linux/exportfs.h | 29 ++++++++++++++++++++++++++---
>  3 files changed, 28 insertions(+), 5 deletions(-)
>
> diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> index d3e55de4a2a2..949ce6ef6c4e 100644
> --- a/fs/exportfs/expfs.c
> +++ b/fs/exportfs/expfs.c
> @@ -391,7 +391,7 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
>         else
>                 type = nop->encode_fh(inode, fid->raw, max_len, parent);
>
> -       if (type > 0 && FILEID_USER_FLAGS(type)) {
> +       if (type > 0 && (type & ~FILEID_HANDLE_TYPE_MASK)) {
>                 pr_warn_once("%s: unexpected fh type value 0x%x from fstype %s.\n",
>                              __func__, type, inode->i_sb->s_type->name);
>                 return -EINVAL;
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index 01fc209853d8..276c16454eb7 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -342,7 +342,7 @@ struct file_handle *get_user_handle(struct file_handle __user *ufh)
>             (f_handle.handle_bytes == 0))
>                 return ERR_PTR(-EINVAL);
>
> -       if (f_handle.handle_type < 0 ||
> +       if (f_handle.handle_type < 0 || FILEID_FS_FLAGS(f_handle.handle_type) ||
>             FILEID_USER_FLAGS(f_handle.handle_type) & ~FILEID_VALID_USER_FLAGS)
>                 return ERR_PTR(-EINVAL);
>
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index cfb0dd1ea49c..30a9791d88e0 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -173,10 +173,33 @@ struct handle_to_path_ctx {
>  #define EXPORT_FH_DIR_ONLY     0x4 /* Only decode file handle for a directory */
>
>  /*
> - * Filesystems use only lower 8 bits of file_handle type for fid_type.
> - * name_to_handle_at() uses upper 16 bits of type as user flags to be
> - * interpreted by open_by_handle_at().
> + * The 32 bits of the handle_type field of struct file_handle are used for a few
> + * different purposes:
> + *
> + *   Filesystems use only lower 8 bits of file_handle type for fid_type.
> + *
> + *   VFS uses bits 8..15 of the handle_type to pass flags to the FS
> + *   implementation of fh_to_{dentry,parent}().
> + *
> + *   name_to_handle_at() uses upper 16 bits of type as user flags to be
> + *   interpreted by open_by_handle_at().
> + *
> + *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + *  |           user flags          |   VFS flags   |   fid_type    |
> + *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + *  (MSB)                                                       (LSB)
> + *
> + * Filesystems are expected not to fill in any bits outside of fid_type in
> + * their encode_fh() implementation.
>   */
> +#define FILEID_HANDLE_TYPE_MASK        0xff
> +#define FILEID_TYPE(type)      ((type) & FILEID_HANDLE_TYPE_MASK)
> +
> +/* VFS flags: */
> +#define FILEID_FS_FLAGS_MASK   0xff00
> +#define FILEID_FS_FLAGS(flags) ((flags) & FILEID_FS_FLAGS_MASK)
> +
> +/* User flags: */
>  #define FILEID_USER_FLAGS_MASK 0xffff0000
>  #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
>
> --
> 2.51.0
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry()
  2025-09-10 21:49 ` [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry() Thomas Bertschinger
@ 2025-09-11 12:29   ` Christoph Hellwig
  2025-09-11 12:39     ` Amir Goldstein
  2025-09-11 12:38   ` Amir Goldstein
  1 sibling, 1 reply; 25+ messages in thread
From: Christoph Hellwig @ 2025-09-11 12:29 UTC (permalink / raw)
  To: Thomas Bertschinger
  Cc: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs,
	linux-xfs, cem

On Wed, Sep 10, 2025 at 03:49:27PM -0600, Thomas Bertschinger wrote:
> This is to support using open_by_handle_at(2) via io_uring. It is useful
> for io_uring to request that opening a file via handle be completed
> using only cached data, or fail with -EAGAIN if that is not possible.
> 
> The signature of xfs_nfs_get_inode() is extended with a new flags
> argument that allows callers to specify XFS_IGET_INCORE.
> 
> That flag is set when the VFS passes the FILEID_CACHED flag via the
> fileid_type argument.

Please post the entire series to all list.  No one has any idea what your
magic new flag does without seeing all the patches.



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup
  2025-09-10 21:49 ` [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup Thomas Bertschinger
@ 2025-09-11 12:31   ` Amir Goldstein
  2025-09-12  8:21   ` Dan Carpenter
  1 sibling, 0 replies; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 12:31 UTC (permalink / raw)
  To: Thomas Bertschinger
  Cc: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs,
	chuck.lever, jlayton

On Wed, Sep 10, 2025 at 11:47 PM Thomas Bertschinger
<tahbertschinger@gmail.com> wrote:
>
> This defines a new flag FILEID_CACHED that the VFS can set in the
> handle_type field of struct file_handle to request that the FS
> implementations of fh_to_{dentry,parent}() only complete if they can
> satisfy the request with cached data.
>
> Because not every FS implementation will recognize this new flag, those
> that do recognize the flag can indicate their support using a new
> export flag, EXPORT_OP_NONBLOCK.
>
> If FILEID_CACHED is set in a file handle, but the filesystem does not
> set EXPORT_OP_NONBLOCK, then the VFS will return -EAGAIN without
> attempting to call into the filesystem code.
>
> exportfs_decode_fh_raw() is updated to respect the new flag by returning
> -EAGAIN when it would need to do an operation that may not be possible
> with only cached data.
>
> Suggested-by: Amir Goldstein <amir73il@gmail.com>
> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>

Reviewed-by: Amir Goldstein <amir73il@gmail.com>

Small comment below

> ---
>  fs/exportfs/expfs.c      | 13 +++++++++++++
>  fs/fhandle.c             |  2 ++
>  include/linux/exportfs.h |  5 +++++
>  3 files changed, 20 insertions(+)
>
> diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> index 949ce6ef6c4e..88418b93abbf 100644
> --- a/fs/exportfs/expfs.c
> +++ b/fs/exportfs/expfs.c
> @@ -441,6 +441,7 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
>                        void *context)
>  {
>         const struct export_operations *nop = mnt->mnt_sb->s_export_op;
> +       bool decode_cached = fileid_type & FILEID_CACHED;
>         struct dentry *result, *alias;
>         char nbuf[NAME_MAX+1];
>         int err;
> @@ -453,6 +454,10 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
>          */
>         if (!exportfs_can_decode_fh(nop))
>                 return ERR_PTR(-ESTALE);
> +
> +       if (decode_cached && !(nop->flags & EXPORT_OP_NONBLOCK))
> +               return ERR_PTR(-EAGAIN);
> +
>         result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
>         if (IS_ERR_OR_NULL(result))
>                 return result;
> @@ -481,6 +486,10 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
>                  * filesystem root.
>                  */
>                 if (result->d_flags & DCACHE_DISCONNECTED) {
> +                       err = -EAGAIN;
> +                       if (decode_cached)
> +                               goto err_result;
> +
>                         err = reconnect_path(mnt, result, nbuf);
>                         if (err)
>                                 goto err_result;
> @@ -526,6 +535,10 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
>                 err = PTR_ERR(target_dir);
>                 if (IS_ERR(target_dir))
>                         goto err_result;
> +               err = -EAGAIN;
> +               if (decode_cached & (target_dir->d_flags & DCACHE_DISCONNECTED)) {
> +                       goto err_result;
> +               }
>
>                 /*
>                  * And as usual we need to make sure the parent directory is
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index 276c16454eb7..70e265f6a3ab 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -273,6 +273,8 @@ static int do_handle_to_path(struct file_handle *handle, struct path *path,
>         if (IS_ERR_OR_NULL(dentry)) {
>                 if (dentry == ERR_PTR(-ENOMEM))
>                         return -ENOMEM;
> +               if (dentry == ERR_PTR(-EAGAIN))
> +                       return -EAGAIN;
>                 return -ESTALE;
>         }
>         path->dentry = dentry;
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 30a9791d88e0..8238b6f67956 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -199,6 +199,8 @@ struct handle_to_path_ctx {
>  #define FILEID_FS_FLAGS_MASK   0xff00
>  #define FILEID_FS_FLAGS(flags) ((flags) & FILEID_FS_FLAGS_MASK)
>

/* vfs flags: */
> +#define FILEID_CACHED          0x100 /* Use only cached data when decoding handle */
> +
>  /* User flags: */
>  #define FILEID_USER_FLAGS_MASK 0xffff0000
>  #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
> @@ -303,6 +305,9 @@ struct export_operations {
>                                                 */
>  #define EXPORT_OP_FLUSH_ON_CLOSE       (0x20) /* fs flushes file data on close */
>  #define EXPORT_OP_NOLOCKS              (0x40) /* no file locking support */
> +#define EXPORT_OP_NONBLOCK             (0x80) /* Filesystem supports non-
> +                                                 blocking fh_to_dentry()
> +                                               */
>         unsigned long   flags;
>  };
>
> --
> 2.51.0
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry()
  2025-09-10 21:49 ` [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry() Thomas Bertschinger
  2025-09-11 12:29   ` Christoph Hellwig
@ 2025-09-11 12:38   ` Amir Goldstein
  1 sibling, 0 replies; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 12:38 UTC (permalink / raw)
  To: Thomas Bertschinger
  Cc: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs,
	linux-xfs, cem

On Wed, Sep 10, 2025 at 11:48 PM Thomas Bertschinger
<tahbertschinger@gmail.com> wrote:
>
> This is to support using open_by_handle_at(2) via io_uring. It is useful
> for io_uring to request that opening a file via handle be completed
> using only cached data, or fail with -EAGAIN if that is not possible.
>
> The signature of xfs_nfs_get_inode() is extended with a new flags
> argument that allows callers to specify XFS_IGET_INCORE.
>
> That flag is set when the VFS passes the FILEID_CACHED flag via the
> fileid_type argument.
>
> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>

I'll let xfs developers review this, but its looks pretty straightforward,
so on my part you may add:

Acked-by: Amir Goldstein <amir73il@gmail.com>

One small nit below

> ---
>  fs/xfs/xfs_export.c | 32 ++++++++++++++++++++++++++------
>  fs/xfs/xfs_export.h |  3 ++-
>  fs/xfs/xfs_handle.c |  2 +-
>  3 files changed, 29 insertions(+), 8 deletions(-)
>
> diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c
> index 201489d3de08..ca2a9ed0eb16 100644
> --- a/fs/xfs/xfs_export.c
> +++ b/fs/xfs/xfs_export.c
> @@ -106,7 +106,8 @@ struct inode *
>  xfs_nfs_get_inode(
>         struct super_block      *sb,
>         u64                     ino,
> -       u32                     generation)
> +       u32                     generation,
> +       uint                    flags)
>  {
>         xfs_mount_t             *mp = XFS_M(sb);
>         xfs_inode_t             *ip;
> @@ -123,7 +124,9 @@ xfs_nfs_get_inode(
>          * fine and not an indication of a corrupted filesystem as clients can
>          * send invalid file handles and we have to handle it gracefully..
>          */
> -       error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip);
> +       flags |= XFS_IGET_UNTRUSTED;
> +
> +       error = xfs_iget(mp, NULL, ino, flags, 0, &ip);
>         if (error) {
>
>                 /*
> @@ -140,6 +143,10 @@ xfs_nfs_get_inode(
>                 case -EFSCORRUPTED:
>                         error = -ESTALE;
>                         break;
> +               case -ENODATA:
> +                       if (flags & XFS_IGET_INCORE)
> +                               error = -EAGAIN;
> +                       break;
>                 default:
>                         break;
>                 }
> @@ -174,6 +181,12 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
>  {
>         struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fid;
>         struct inode            *inode = NULL;
> +       uint                    flags = 0;
> +
> +       if (fileid_type & FILEID_CACHED)
> +               flags = XFS_IGET_INCORE;
> +
> +       fileid_type = FILEID_TYPE(fileid_type);

That is a smelly practice.
It's better to rename the function argument to fileid_flags or fileid_type_flags
and use a local fileid_type var for fileid_type = FILEID_TYPE(fileid_flags)

Thanks,
Amir.

>
>         if (fh_len < xfs_fileid_length(fileid_type))
>                 return NULL;
> @@ -181,11 +194,11 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
>         switch (fileid_type) {
>         case FILEID_INO32_GEN_PARENT:
>         case FILEID_INO32_GEN:
> -               inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
> +               inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen, flags);
>                 break;
>         case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
>         case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
> -               inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
> +               inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen, flags);
>                 break;
>         }
>
> @@ -198,6 +211,12 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
>  {
>         struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fid;
>         struct inode            *inode = NULL;
> +       uint                    flags = 0;
> +
> +       if (fileid_type & FILEID_CACHED)
> +               flags = XFS_IGET_INCORE;
> +
> +       fileid_type = FILEID_TYPE(fileid_type);
>
>         if (fh_len < xfs_fileid_length(fileid_type))
>                 return NULL;
> @@ -205,11 +224,11 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
>         switch (fileid_type) {
>         case FILEID_INO32_GEN_PARENT:
>                 inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
> -                                             fid->i32.parent_gen);
> +                                             fid->i32.parent_gen, flags);
>                 break;
>         case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
>                 inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
> -                                             fid64->parent_gen);
> +                                             fid64->parent_gen, flags);
>                 break;
>         }
>
> @@ -248,4 +267,5 @@ const struct export_operations xfs_export_operations = {
>         .map_blocks             = xfs_fs_map_blocks,
>         .commit_blocks          = xfs_fs_commit_blocks,
>  #endif
> +       .flags                  = EXPORT_OP_NONBLOCK,
>  };
> diff --git a/fs/xfs/xfs_export.h b/fs/xfs/xfs_export.h
> index 3cd85e8901a5..9addfcd5b1e1 100644
> --- a/fs/xfs/xfs_export.h
> +++ b/fs/xfs/xfs_export.h
> @@ -57,6 +57,7 @@ struct xfs_fid64 {
>  /* This flag goes on the wire.  Don't play with it. */
>  #define XFS_FILEID_TYPE_64FLAG 0x80    /* NFS fileid has 64bit inodes */
>
> -struct inode *xfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 gen);
> +struct inode *xfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 gen,
> +                               uint flags);
>
>  #endif /* __XFS_EXPORT_H__ */
> diff --git a/fs/xfs/xfs_handle.c b/fs/xfs/xfs_handle.c
> index f19fce557354..7d877ff504d6 100644
> --- a/fs/xfs/xfs_handle.c
> +++ b/fs/xfs/xfs_handle.c
> @@ -193,7 +193,7 @@ xfs_khandle_to_inode(
>                 return ERR_PTR(-EINVAL);
>
>         inode = xfs_nfs_get_inode(mp->m_super, handle->ha_fid.fid_ino,
> -                       handle->ha_fid.fid_gen);
> +                       handle->ha_fid.fid_gen, 0);
>         if (IS_ERR(inode))
>                 return ERR_CAST(inode);
>
> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry()
  2025-09-11 12:29   ` Christoph Hellwig
@ 2025-09-11 12:39     ` Amir Goldstein
  2025-09-11 15:15       ` Thomas Bertschinger
  0 siblings, 1 reply; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 12:39 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Thomas Bertschinger, io-uring, axboe, linux-fsdevel, viro,
	brauner, linux-nfs, linux-xfs, cem

On Thu, Sep 11, 2025 at 2:29 PM Christoph Hellwig <hch@infradead.org> wrote:
>
> On Wed, Sep 10, 2025 at 03:49:27PM -0600, Thomas Bertschinger wrote:
> > This is to support using open_by_handle_at(2) via io_uring. It is useful
> > for io_uring to request that opening a file via handle be completed
> > using only cached data, or fail with -EAGAIN if that is not possible.
> >
> > The signature of xfs_nfs_get_inode() is extended with a new flags
> > argument that allows callers to specify XFS_IGET_INCORE.
> >
> > That flag is set when the VFS passes the FILEID_CACHED flag via the
> > fileid_type argument.
>
> Please post the entire series to all list.  No one has any idea what your
> magic new flag does without seeing all the patches.
>

Might as well re-post your entire v2 patches with v2 subjects and
cc xfs list.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry()
  2025-09-11 12:39     ` Amir Goldstein
@ 2025-09-11 15:15       ` Thomas Bertschinger
  2025-09-11 15:16         ` Amir Goldstein
  0 siblings, 1 reply; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-11 15:15 UTC (permalink / raw)
  To: Amir Goldstein, Christoph Hellwig
  Cc: Thomas Bertschinger, io-uring, axboe, linux-fsdevel, viro,
	brauner, linux-nfs, linux-xfs, cem

On Thu Sep 11, 2025 at 6:39 AM MDT, Amir Goldstein wrote:
> On Thu, Sep 11, 2025 at 2:29 PM Christoph Hellwig <hch@infradead.org> wrote:
>>
>> On Wed, Sep 10, 2025 at 03:49:27PM -0600, Thomas Bertschinger wrote:
>> > This is to support using open_by_handle_at(2) via io_uring. It is useful
>> > for io_uring to request that opening a file via handle be completed
>> > using only cached data, or fail with -EAGAIN if that is not possible.
>> >
>> > The signature of xfs_nfs_get_inode() is extended with a new flags
>> > argument that allows callers to specify XFS_IGET_INCORE.
>> >
>> > That flag is set when the VFS passes the FILEID_CACHED flag via the
>> > fileid_type argument.
>>
>> Please post the entire series to all list.  No one has any idea what your
>> magic new flag does without seeing all the patches.
>>
>
> Might as well re-post your entire v2 patches with v2 subjects and
> cc xfs list.
>
> Thanks,
> Amir.


Thanks for the advice, sorry for messing up the procedure...

Since there are a few quick fixups I can make, I may go straight to
sending v3 with the correct subject and cc. Any reason for me to not do
that -- is it preferable to resend v2 right away with no changes?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry()
  2025-09-11 15:15       ` Thomas Bertschinger
@ 2025-09-11 15:16         ` Amir Goldstein
  0 siblings, 0 replies; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 15:16 UTC (permalink / raw)
  To: Thomas Bertschinger
  Cc: Christoph Hellwig, io-uring, axboe, linux-fsdevel, viro, brauner,
	linux-nfs, linux-xfs, cem

On Thu, Sep 11, 2025 at 5:10 PM Thomas Bertschinger
<tahbertschinger@gmail.com> wrote:
>
> On Thu Sep 11, 2025 at 6:39 AM MDT, Amir Goldstein wrote:
> > On Thu, Sep 11, 2025 at 2:29 PM Christoph Hellwig <hch@infradead.org> wrote:
> >>
> >> On Wed, Sep 10, 2025 at 03:49:27PM -0600, Thomas Bertschinger wrote:
> >> > This is to support using open_by_handle_at(2) via io_uring. It is useful
> >> > for io_uring to request that opening a file via handle be completed
> >> > using only cached data, or fail with -EAGAIN if that is not possible.
> >> >
> >> > The signature of xfs_nfs_get_inode() is extended with a new flags
> >> > argument that allows callers to specify XFS_IGET_INCORE.
> >> >
> >> > That flag is set when the VFS passes the FILEID_CACHED flag via the
> >> > fileid_type argument.
> >>
> >> Please post the entire series to all list.  No one has any idea what your
> >> magic new flag does without seeing all the patches.
> >>
> >
> > Might as well re-post your entire v2 patches with v2 subjects and
> > cc xfs list.
> >
> > Thanks,
> > Amir.
>
>
> Thanks for the advice, sorry for messing up the procedure...
>
> Since there are a few quick fixups I can make, I may go straight to
> sending v3 with the correct subject and cc. Any reason for me to not do
> that -- is it preferable to resend v2 right away with no changes?

No worries. v3 is fine.
But maybe give it a day or two for other people to comment on v2
before posting v3. Some people may even be mid review of v2
and that can be a bit annoying to get v3 while in the middle of review of v2.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 03/10] fhandle: helper for allocating, reading struct file_handle
  2025-09-11 12:15   ` Amir Goldstein
@ 2025-09-11 15:31     ` Thomas Bertschinger
  2025-09-11 15:54       ` Amir Goldstein
  0 siblings, 1 reply; 25+ messages in thread
From: Thomas Bertschinger @ 2025-09-11 15:31 UTC (permalink / raw)
  To: Amir Goldstein, Thomas Bertschinger
  Cc: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs

On Thu Sep 11, 2025 at 6:15 AM MDT, Amir Goldstein wrote:
> On Wed, Sep 10, 2025 at 11:47 PM Thomas Bertschinger
> <tahbertschinger@gmail.com> wrote:
>>
>> Pull the code for allocating and copying a struct file_handle from
>> userspace into a helper function get_user_handle() just for this.
>>
>> do_handle_open() is updated to call get_user_handle() prior to calling
>> handle_to_path(), and the latter now takes a kernel pointer as a
>> parameter instead of a __user pointer.
>>
>> This new helper, as well as handle_to_path(), are also exposed in
>> fs/internal.h. In a subsequent commit, io_uring will use these helpers
>> to support open_by_handle_at(2) in io_uring.
>>
>> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
>> ---
>>  fs/fhandle.c  | 64 +++++++++++++++++++++++++++++----------------------
>>  fs/internal.h |  3 +++
>>  2 files changed, 40 insertions(+), 27 deletions(-)
>>
>> diff --git a/fs/fhandle.c b/fs/fhandle.c
>> index 605ad8e7d93d..36e194dd4cb6 100644
>> --- a/fs/fhandle.c
>> +++ b/fs/fhandle.c
>> @@ -330,25 +330,45 @@ static inline int may_decode_fh(struct handle_to_path_ctx *ctx,
>>         return 0;
>>  }
>>
>> -static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>> -                  struct path *path, unsigned int o_flags)
>> +struct file_handle *get_user_handle(struct file_handle __user *ufh)
>>  {
>> -       int retval = 0;
>>         struct file_handle f_handle;
>> -       struct file_handle *handle __free(kfree) = NULL;
>> -       struct handle_to_path_ctx ctx = {};
>> -       const struct export_operations *eops;
>> +       struct file_handle *handle;
>>
>>         if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
>> -               return -EFAULT;
>> +               return ERR_PTR(-EFAULT);
>>
>>         if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
>>             (f_handle.handle_bytes == 0))
>> -               return -EINVAL;
>> +               return ERR_PTR(-EINVAL);
>>
>>         if (f_handle.handle_type < 0 ||
>>             FILEID_USER_FLAGS(f_handle.handle_type) & ~FILEID_VALID_USER_FLAGS)
>> -               return -EINVAL;
>> +               return ERR_PTR(-EINVAL);
>> +
>> +       handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
>> +                        GFP_KERNEL);
>> +       if (!handle) {
>> +               return ERR_PTR(-ENOMEM);
>> +       }
>> +
>> +       /* copy the full handle */
>> +       *handle = f_handle;
>> +       if (copy_from_user(&handle->f_handle,
>> +                          &ufh->f_handle,
>> +                          f_handle.handle_bytes)) {
>> +               return ERR_PTR(-EFAULT);
>> +       }
>> +
>> +       return handle;
>> +}
>> +
>> +int handle_to_path(int mountdirfd, struct file_handle *handle,
>> +                  struct path *path, unsigned int o_flags)
>> +{
>> +       int retval = 0;
>> +       struct handle_to_path_ctx ctx = {};
>> +       const struct export_operations *eops;
>>
>>         retval = get_path_anchor(mountdirfd, &ctx.root);
>>         if (retval)
>> @@ -362,31 +382,16 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>>         if (retval)
>>                 goto out_path;
>>
>> -       handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
>> -                        GFP_KERNEL);
>> -       if (!handle) {
>> -               retval = -ENOMEM;
>> -               goto out_path;
>> -       }
>> -       /* copy the full handle */
>> -       *handle = f_handle;
>> -       if (copy_from_user(&handle->f_handle,
>> -                          &ufh->f_handle,
>> -                          f_handle.handle_bytes)) {
>> -               retval = -EFAULT;
>> -               goto out_path;
>> -       }
>> -
>>         /*
>>          * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we
>>          * are decoding an fd with connected path, which is accessible from
>>          * the mount fd path.
>>          */
>> -       if (f_handle.handle_type & FILEID_IS_CONNECTABLE) {
>> +       if (handle->handle_type & FILEID_IS_CONNECTABLE) {
>>                 ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
>>                 ctx.flags |= HANDLE_CHECK_SUBTREE;
>>         }
>> -       if (f_handle.handle_type & FILEID_IS_DIR)
>> +       if (handle->handle_type & FILEID_IS_DIR)
>>                 ctx.fh_flags |= EXPORT_FH_DIR_ONLY;
>>         /* Filesystem code should not be exposed to user flags */
>>         handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
>> @@ -400,12 +405,17 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>>  static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
>>                            int open_flag)
>>  {
>> +       struct file_handle *handle __free(kfree) = NULL;
>>         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);
>> +       handle = get_user_handle(ufh);
>> +       if (IS_ERR(handle))
>> +               return PTR_ERR(handle);
>
> I don't think you can use __free(kfree) for something that can be an ERR_PTR.
>
> Thanks,
> Amir.

It looks like the error pointer is correctly handled?

in include/linux/slab.h:

DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 03/10] fhandle: helper for allocating, reading struct file_handle
  2025-09-11 15:31     ` Thomas Bertschinger
@ 2025-09-11 15:54       ` Amir Goldstein
  0 siblings, 0 replies; 25+ messages in thread
From: Amir Goldstein @ 2025-09-11 15:54 UTC (permalink / raw)
  To: Thomas Bertschinger
  Cc: io-uring, axboe, linux-fsdevel, viro, brauner, linux-nfs

On Thu, Sep 11, 2025 at 5:26 PM Thomas Bertschinger
<tahbertschinger@gmail.com> wrote:
>
> On Thu Sep 11, 2025 at 6:15 AM MDT, Amir Goldstein wrote:
> > On Wed, Sep 10, 2025 at 11:47 PM Thomas Bertschinger
> > <tahbertschinger@gmail.com> wrote:
> >>
> >> Pull the code for allocating and copying a struct file_handle from
> >> userspace into a helper function get_user_handle() just for this.
> >>
> >> do_handle_open() is updated to call get_user_handle() prior to calling
> >> handle_to_path(), and the latter now takes a kernel pointer as a
> >> parameter instead of a __user pointer.
> >>
> >> This new helper, as well as handle_to_path(), are also exposed in
> >> fs/internal.h. In a subsequent commit, io_uring will use these helpers
> >> to support open_by_handle_at(2) in io_uring.
> >>
> >> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
> >> ---
> >>  fs/fhandle.c  | 64 +++++++++++++++++++++++++++++----------------------
> >>  fs/internal.h |  3 +++
> >>  2 files changed, 40 insertions(+), 27 deletions(-)
> >>
> >> diff --git a/fs/fhandle.c b/fs/fhandle.c
> >> index 605ad8e7d93d..36e194dd4cb6 100644
> >> --- a/fs/fhandle.c
> >> +++ b/fs/fhandle.c
> >> @@ -330,25 +330,45 @@ static inline int may_decode_fh(struct handle_to_path_ctx *ctx,
> >>         return 0;
> >>  }
> >>
> >> -static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
> >> -                  struct path *path, unsigned int o_flags)
> >> +struct file_handle *get_user_handle(struct file_handle __user *ufh)
> >>  {
> >> -       int retval = 0;
> >>         struct file_handle f_handle;
> >> -       struct file_handle *handle __free(kfree) = NULL;
> >> -       struct handle_to_path_ctx ctx = {};
> >> -       const struct export_operations *eops;
> >> +       struct file_handle *handle;
> >>
> >>         if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
> >> -               return -EFAULT;
> >> +               return ERR_PTR(-EFAULT);
> >>
> >>         if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
> >>             (f_handle.handle_bytes == 0))
> >> -               return -EINVAL;
> >> +               return ERR_PTR(-EINVAL);
> >>
> >>         if (f_handle.handle_type < 0 ||
> >>             FILEID_USER_FLAGS(f_handle.handle_type) & ~FILEID_VALID_USER_FLAGS)
> >> -               return -EINVAL;
> >> +               return ERR_PTR(-EINVAL);
> >> +
> >> +       handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
> >> +                        GFP_KERNEL);
> >> +       if (!handle) {
> >> +               return ERR_PTR(-ENOMEM);
> >> +       }
> >> +
> >> +       /* copy the full handle */
> >> +       *handle = f_handle;
> >> +       if (copy_from_user(&handle->f_handle,
> >> +                          &ufh->f_handle,
> >> +                          f_handle.handle_bytes)) {
> >> +               return ERR_PTR(-EFAULT);
> >> +       }
> >> +
> >> +       return handle;
> >> +}
> >> +
> >> +int handle_to_path(int mountdirfd, struct file_handle *handle,
> >> +                  struct path *path, unsigned int o_flags)
> >> +{
> >> +       int retval = 0;
> >> +       struct handle_to_path_ctx ctx = {};
> >> +       const struct export_operations *eops;
> >>
> >>         retval = get_path_anchor(mountdirfd, &ctx.root);
> >>         if (retval)
> >> @@ -362,31 +382,16 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
> >>         if (retval)
> >>                 goto out_path;
> >>
> >> -       handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
> >> -                        GFP_KERNEL);
> >> -       if (!handle) {
> >> -               retval = -ENOMEM;
> >> -               goto out_path;
> >> -       }
> >> -       /* copy the full handle */
> >> -       *handle = f_handle;
> >> -       if (copy_from_user(&handle->f_handle,
> >> -                          &ufh->f_handle,
> >> -                          f_handle.handle_bytes)) {
> >> -               retval = -EFAULT;
> >> -               goto out_path;
> >> -       }
> >> -
> >>         /*
> >>          * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we
> >>          * are decoding an fd with connected path, which is accessible from
> >>          * the mount fd path.
> >>          */
> >> -       if (f_handle.handle_type & FILEID_IS_CONNECTABLE) {
> >> +       if (handle->handle_type & FILEID_IS_CONNECTABLE) {
> >>                 ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
> >>                 ctx.flags |= HANDLE_CHECK_SUBTREE;
> >>         }
> >> -       if (f_handle.handle_type & FILEID_IS_DIR)
> >> +       if (handle->handle_type & FILEID_IS_DIR)
> >>                 ctx.fh_flags |= EXPORT_FH_DIR_ONLY;
> >>         /* Filesystem code should not be exposed to user flags */
> >>         handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
> >> @@ -400,12 +405,17 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
> >>  static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
> >>                            int open_flag)
> >>  {
> >> +       struct file_handle *handle __free(kfree) = NULL;
> >>         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);
> >> +       handle = get_user_handle(ufh);
> >> +       if (IS_ERR(handle))
> >> +               return PTR_ERR(handle);
> >
> > I don't think you can use __free(kfree) for something that can be an ERR_PTR.
> >
> > Thanks,
> > Amir.
>
> It looks like the error pointer is correctly handled?
>
> in include/linux/slab.h:
>
> DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))

Right! feel free to add for v3:
Reviewed-by: Amir Goldstein <amir73il@gmail.com>

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup
  2025-09-10 21:49 ` [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup Thomas Bertschinger
  2025-09-11 12:31   ` Amir Goldstein
@ 2025-09-12  8:21   ` Dan Carpenter
  1 sibling, 0 replies; 25+ messages in thread
From: Dan Carpenter @ 2025-09-12  8:21 UTC (permalink / raw)
  To: oe-kbuild, Thomas Bertschinger, io-uring, axboe, linux-fsdevel,
	viro, brauner, linux-nfs
  Cc: lkp, oe-kbuild-all, Thomas Bertschinger, Amir Goldstein,
	chuck.lever, jlayton

Hi Thomas,

kernel test robot noticed the following build warnings:

url:    https://github.com/intel-lab-lkp/linux/commits/Thomas-Bertschinger/fhandle-create-helper-for-name_to_handle_at-2/20250911-054830
base:   76eeb9b8de9880ca38696b2fb56ac45ac0a25c6c
patch link:    https://lore.kernel.org/r/20250910214927.480316-8-tahbertschinger%40gmail.com
patch subject: [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup
config: arm-randconfig-r071-20250911 (https://download.01.org/0day-ci/archive/20250912/202509120423.cZlR8oLY-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 21857ae337e0892a5522b6e7337899caa61de2a6)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202509120423.cZlR8oLY-lkp@intel.com/

smatch warnings:
fs/exportfs/expfs.c:539 exportfs_decode_fh_raw() warn: maybe use && instead of &

vim +539 fs/exportfs/expfs.c

d045465fc6cbfa4 Trond Myklebust     2020-11-30  437  struct dentry *
d045465fc6cbfa4 Trond Myklebust     2020-11-30  438  exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
620c266f394932e Christian Brauner   2024-05-24  439  		       int fileid_type, unsigned int flags,
d045465fc6cbfa4 Trond Myklebust     2020-11-30  440  		       int (*acceptable)(void *, struct dentry *),
d045465fc6cbfa4 Trond Myklebust     2020-11-30  441  		       void *context)
d37065cd6d6bbe9 Christoph Hellwig   2007-07-17  442  {
39655164405940d Christoph Hellwig   2007-10-21  443  	const struct export_operations *nop = mnt->mnt_sb->s_export_op;
638205375afdc8a Thomas Bertschinger 2025-09-10  444  	bool decode_cached = fileid_type & FILEID_CACHED;
2596110a3994593 Christoph Hellwig   2007-10-21  445  	struct dentry *result, *alias;
f3f8e17571934ea Al Viro             2008-08-11  446  	char nbuf[NAME_MAX+1];
2596110a3994593 Christoph Hellwig   2007-10-21  447  	int err;
d37065cd6d6bbe9 Christoph Hellwig   2007-07-17  448  
4a530a7c751d27f Amir Goldstein      2024-10-11  449  	if (fileid_type < 0 || FILEID_USER_FLAGS(fileid_type))
4a530a7c751d27f Amir Goldstein      2024-10-11  450  		return ERR_PTR(-EINVAL);
4a530a7c751d27f Amir Goldstein      2024-10-11  451  
2596110a3994593 Christoph Hellwig   2007-10-21  452  	/*
2596110a3994593 Christoph Hellwig   2007-10-21  453  	 * Try to get any dentry for the given file handle from the filesystem.
2596110a3994593 Christoph Hellwig   2007-10-21  454  	 */
66c62769bcf6aa1 Amir Goldstein      2023-10-23  455  	if (!exportfs_can_decode_fh(nop))
becfd1f37544798 Aneesh Kumar K.V    2011-01-29  456  		return ERR_PTR(-ESTALE);
638205375afdc8a Thomas Bertschinger 2025-09-10  457  
638205375afdc8a Thomas Bertschinger 2025-09-10  458  	if (decode_cached && !(nop->flags & EXPORT_OP_NONBLOCK))
638205375afdc8a Thomas Bertschinger 2025-09-10  459  		return ERR_PTR(-EAGAIN);
638205375afdc8a Thomas Bertschinger 2025-09-10  460  
2596110a3994593 Christoph Hellwig   2007-10-21  461  	result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
09bb8bfffd29c3d NeilBrown           2016-08-04  462  	if (IS_ERR_OR_NULL(result))
d045465fc6cbfa4 Trond Myklebust     2020-11-30  463  		return result;
2596110a3994593 Christoph Hellwig   2007-10-21  464  
620c266f394932e Christian Brauner   2024-05-24  465  	if ((flags & EXPORT_FH_DIR_ONLY) && !d_is_dir(result)) {
620c266f394932e Christian Brauner   2024-05-24  466  		err = -ENOTDIR;
620c266f394932e Christian Brauner   2024-05-24  467  		goto err_result;
620c266f394932e Christian Brauner   2024-05-24  468  	}
620c266f394932e Christian Brauner   2024-05-24  469  
8a22efa15b46d52 Amir Goldstein      2018-03-09  470  	/*
8a22efa15b46d52 Amir Goldstein      2018-03-09  471  	 * If no acceptance criteria was specified by caller, a disconnected
8a22efa15b46d52 Amir Goldstein      2018-03-09  472  	 * dentry is also accepatable. Callers may use this mode to query if
8a22efa15b46d52 Amir Goldstein      2018-03-09  473  	 * file handle is stale or to get a reference to an inode without
8a22efa15b46d52 Amir Goldstein      2018-03-09  474  	 * risking the high overhead caused by directory reconnect.
8a22efa15b46d52 Amir Goldstein      2018-03-09  475  	 */
8a22efa15b46d52 Amir Goldstein      2018-03-09  476  	if (!acceptable)
8a22efa15b46d52 Amir Goldstein      2018-03-09  477  		return result;
8a22efa15b46d52 Amir Goldstein      2018-03-09  478  
e36cb0b89ce20b4 David Howells       2015-01-29  479  	if (d_is_dir(result)) {
2596110a3994593 Christoph Hellwig   2007-10-21  480  		/*
2596110a3994593 Christoph Hellwig   2007-10-21  481  		 * This request is for a directory.
2596110a3994593 Christoph Hellwig   2007-10-21  482  		 *
2596110a3994593 Christoph Hellwig   2007-10-21  483  		 * On the positive side there is only one dentry for each
2596110a3994593 Christoph Hellwig   2007-10-21  484  		 * directory inode.  On the negative side this implies that we
2596110a3994593 Christoph Hellwig   2007-10-21  485  		 * to ensure our dentry is connected all the way up to the
2596110a3994593 Christoph Hellwig   2007-10-21  486  		 * filesystem root.
2596110a3994593 Christoph Hellwig   2007-10-21  487  		 */
2596110a3994593 Christoph Hellwig   2007-10-21  488  		if (result->d_flags & DCACHE_DISCONNECTED) {
638205375afdc8a Thomas Bertschinger 2025-09-10  489  			err = -EAGAIN;
638205375afdc8a Thomas Bertschinger 2025-09-10  490  			if (decode_cached)
638205375afdc8a Thomas Bertschinger 2025-09-10  491  				goto err_result;
638205375afdc8a Thomas Bertschinger 2025-09-10  492  
f3f8e17571934ea Al Viro             2008-08-11  493  			err = reconnect_path(mnt, result, nbuf);
2596110a3994593 Christoph Hellwig   2007-10-21  494  			if (err)
2596110a3994593 Christoph Hellwig   2007-10-21  495  				goto err_result;
2596110a3994593 Christoph Hellwig   2007-10-21  496  		}
2596110a3994593 Christoph Hellwig   2007-10-21  497  
2596110a3994593 Christoph Hellwig   2007-10-21  498  		if (!acceptable(context, result)) {
2596110a3994593 Christoph Hellwig   2007-10-21  499  			err = -EACCES;
2596110a3994593 Christoph Hellwig   2007-10-21  500  			goto err_result;
2596110a3994593 Christoph Hellwig   2007-10-21  501  		}
2596110a3994593 Christoph Hellwig   2007-10-21  502  
2596110a3994593 Christoph Hellwig   2007-10-21  503  		return result;
2596110a3994593 Christoph Hellwig   2007-10-21  504  	} else {
2596110a3994593 Christoph Hellwig   2007-10-21  505  		/*
2596110a3994593 Christoph Hellwig   2007-10-21  506  		 * It's not a directory.  Life is a little more complicated.
2596110a3994593 Christoph Hellwig   2007-10-21  507  		 */
2596110a3994593 Christoph Hellwig   2007-10-21  508  		struct dentry *target_dir, *nresult;
2596110a3994593 Christoph Hellwig   2007-10-21  509  
2596110a3994593 Christoph Hellwig   2007-10-21  510  		/*
2596110a3994593 Christoph Hellwig   2007-10-21  511  		 * See if either the dentry we just got from the filesystem
2596110a3994593 Christoph Hellwig   2007-10-21  512  		 * or any alias for it is acceptable.  This is always true
2596110a3994593 Christoph Hellwig   2007-10-21  513  		 * if this filesystem is exported without the subtreecheck
2596110a3994593 Christoph Hellwig   2007-10-21  514  		 * option.  If the filesystem is exported with the subtree
2596110a3994593 Christoph Hellwig   2007-10-21  515  		 * check option there's a fair chance we need to look at
2596110a3994593 Christoph Hellwig   2007-10-21  516  		 * the parent directory in the file handle and make sure
2596110a3994593 Christoph Hellwig   2007-10-21  517  		 * it's connected to the filesystem root.
2596110a3994593 Christoph Hellwig   2007-10-21  518  		 */
2596110a3994593 Christoph Hellwig   2007-10-21  519  		alias = find_acceptable_alias(result, acceptable, context);
2596110a3994593 Christoph Hellwig   2007-10-21  520  		if (alias)
2596110a3994593 Christoph Hellwig   2007-10-21  521  			return alias;
2596110a3994593 Christoph Hellwig   2007-10-21  522  
2596110a3994593 Christoph Hellwig   2007-10-21  523  		/*
2596110a3994593 Christoph Hellwig   2007-10-21  524  		 * Try to extract a dentry for the parent directory from the
2596110a3994593 Christoph Hellwig   2007-10-21  525  		 * file handle.  If this fails we'll have to give up.
2596110a3994593 Christoph Hellwig   2007-10-21  526  		 */
2596110a3994593 Christoph Hellwig   2007-10-21  527  		err = -ESTALE;
2596110a3994593 Christoph Hellwig   2007-10-21  528  		if (!nop->fh_to_parent)
2596110a3994593 Christoph Hellwig   2007-10-21  529  			goto err_result;
2596110a3994593 Christoph Hellwig   2007-10-21  530  
2596110a3994593 Christoph Hellwig   2007-10-21  531  		target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
2596110a3994593 Christoph Hellwig   2007-10-21  532  				fh_len, fileid_type);
a4f4d6df5373682 J. Bruce Fields     2008-12-08  533  		if (!target_dir)
a4f4d6df5373682 J. Bruce Fields     2008-12-08  534  			goto err_result;
2596110a3994593 Christoph Hellwig   2007-10-21  535  		err = PTR_ERR(target_dir);
2596110a3994593 Christoph Hellwig   2007-10-21  536  		if (IS_ERR(target_dir))
2596110a3994593 Christoph Hellwig   2007-10-21  537  			goto err_result;
638205375afdc8a Thomas Bertschinger 2025-09-10  538  		err = -EAGAIN;
638205375afdc8a Thomas Bertschinger 2025-09-10 @539  		if (decode_cached & (target_dir->d_flags & DCACHE_DISCONNECTED)) {

It needs to be &&.  DCACHE_DISCONNECTED is BIT(5).

638205375afdc8a Thomas Bertschinger 2025-09-10  540  			goto err_result;
638205375afdc8a Thomas Bertschinger 2025-09-10  541  		}
2596110a3994593 Christoph Hellwig   2007-10-21  542  
2596110a3994593 Christoph Hellwig   2007-10-21  543  		/*
2596110a3994593 Christoph Hellwig   2007-10-21  544  		 * And as usual we need to make sure the parent directory is
2596110a3994593 Christoph Hellwig   2007-10-21  545  		 * connected to the filesystem root.  The VFS really doesn't
2596110a3994593 Christoph Hellwig   2007-10-21  546  		 * like disconnected directories..
2596110a3994593 Christoph Hellwig   2007-10-21  547  		 */
f3f8e17571934ea Al Viro             2008-08-11  548  		err = reconnect_path(mnt, target_dir, nbuf);
2596110a3994593 Christoph Hellwig   2007-10-21  549  		if (err) {
2596110a3994593 Christoph Hellwig   2007-10-21  550  			dput(target_dir);
2596110a3994593 Christoph Hellwig   2007-10-21  551  			goto err_result;
2596110a3994593 Christoph Hellwig   2007-10-21  552  		}
2596110a3994593 Christoph Hellwig   2007-10-21  553  
2596110a3994593 Christoph Hellwig   2007-10-21  554  		/*
2596110a3994593 Christoph Hellwig   2007-10-21  555  		 * Now that we've got both a well-connected parent and a
2596110a3994593 Christoph Hellwig   2007-10-21  556  		 * dentry for the inode we're after, make sure that our
2596110a3994593 Christoph Hellwig   2007-10-21  557  		 * inode is actually connected to the parent.
2596110a3994593 Christoph Hellwig   2007-10-21  558  		 */
e38f981758118d8 Christoph Hellwig   2007-10-21  559  		err = exportfs_get_name(mnt, target_dir, nbuf, result);
a2ece088882666e Al Viro             2019-11-08  560  		if (err) {
a2ece088882666e Al Viro             2019-11-08  561  			dput(target_dir);
a2ece088882666e Al Viro             2019-11-08  562  			goto err_result;
a2ece088882666e Al Viro             2019-11-08  563  		}
a2ece088882666e Al Viro             2019-11-08  564  
ce3490038971a20 NeilBrown           2025-06-09  565  		nresult = lookup_one_unlocked(mnt_idmap(mnt), &QSTR(nbuf), target_dir);
2596110a3994593 Christoph Hellwig   2007-10-21  566  		if (!IS_ERR(nresult)) {
a2ece088882666e Al Viro             2019-11-08  567  			if (unlikely(nresult->d_inode != result->d_inode)) {
2596110a3994593 Christoph Hellwig   2007-10-21  568  				dput(nresult);
a2ece088882666e Al Viro             2019-11-08  569  				nresult = ERR_PTR(-ESTALE);
2596110a3994593 Christoph Hellwig   2007-10-21  570  			}
2596110a3994593 Christoph Hellwig   2007-10-21  571  		}
2596110a3994593 Christoph Hellwig   2007-10-21  572  		/*
2596110a3994593 Christoph Hellwig   2007-10-21  573  		 * At this point we are done with the parent, but it's pinned
2596110a3994593 Christoph Hellwig   2007-10-21  574  		 * by the child dentry anyway.
2596110a3994593 Christoph Hellwig   2007-10-21  575  		 */
2596110a3994593 Christoph Hellwig   2007-10-21  576  		dput(target_dir);
2596110a3994593 Christoph Hellwig   2007-10-21  577  
a2ece088882666e Al Viro             2019-11-08  578  		if (IS_ERR(nresult)) {
a2ece088882666e Al Viro             2019-11-08  579  			err = PTR_ERR(nresult);
a2ece088882666e Al Viro             2019-11-08  580  			goto err_result;
a2ece088882666e Al Viro             2019-11-08  581  		}
a2ece088882666e Al Viro             2019-11-08  582  		dput(result);
a2ece088882666e Al Viro             2019-11-08  583  		result = nresult;
a2ece088882666e Al Viro             2019-11-08  584  
2596110a3994593 Christoph Hellwig   2007-10-21  585  		/*
2596110a3994593 Christoph Hellwig   2007-10-21  586  		 * And finally make sure the dentry is actually acceptable
2596110a3994593 Christoph Hellwig   2007-10-21  587  		 * to NFSD.
2596110a3994593 Christoph Hellwig   2007-10-21  588  		 */
2596110a3994593 Christoph Hellwig   2007-10-21  589  		alias = find_acceptable_alias(result, acceptable, context);
2596110a3994593 Christoph Hellwig   2007-10-21  590  		if (!alias) {
2596110a3994593 Christoph Hellwig   2007-10-21  591  			err = -EACCES;
2596110a3994593 Christoph Hellwig   2007-10-21  592  			goto err_result;
2596110a3994593 Christoph Hellwig   2007-10-21  593  		}
2596110a3994593 Christoph Hellwig   2007-10-21  594  
2596110a3994593 Christoph Hellwig   2007-10-21  595  		return alias;
2596110a3994593 Christoph Hellwig   2007-10-21  596  	}
2596110a3994593 Christoph Hellwig   2007-10-21  597  
2596110a3994593 Christoph Hellwig   2007-10-21  598   err_result:
2596110a3994593 Christoph Hellwig   2007-10-21  599  	dput(result);
2596110a3994593 Christoph Hellwig   2007-10-21  600  	return ERR_PTR(err);
10f11c341da8c0e Christoph Hellwig   2007-07-17  601  }

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2025-09-12  8:21 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-10 21:49 [PATCHSET RFC v2 00/10] add support for name_to, open_by_handle_at() to io_uring Thomas Bertschinger
2025-09-10 21:49 ` [PATCH 01/10] fhandle: create helper for name_to_handle_at(2) Thomas Bertschinger
2025-09-11 12:06   ` Amir Goldstein
2025-09-10 21:49 ` [PATCH 02/10] io_uring: add support for IORING_OP_NAME_TO_HANDLE_AT Thomas Bertschinger
2025-09-10 21:49 ` [PATCH 03/10] fhandle: helper for allocating, reading struct file_handle Thomas Bertschinger
2025-09-11 12:15   ` Amir Goldstein
2025-09-11 15:31     ` Thomas Bertschinger
2025-09-11 15:54       ` Amir Goldstein
2025-09-10 21:49 ` [PATCH 04/10] fhandle: create do_filp_path_open() helper Thomas Bertschinger
2025-09-11  0:53   ` Al Viro
2025-09-11 12:21     ` Amir Goldstein
2025-09-10 21:49 ` [PATCH 05/10] fhandle: make do_filp_path_open() take struct open_flags Thomas Bertschinger
2025-09-10 21:49 ` [PATCH 06/10] exportfs: allow VFS flags in struct file_handle Thomas Bertschinger
2025-09-11 12:24   ` Amir Goldstein
2025-09-10 21:49 ` [PATCH 07/10] exportfs: new FILEID_CACHED flag for non-blocking fh lookup Thomas Bertschinger
2025-09-11 12:31   ` Amir Goldstein
2025-09-12  8:21   ` Dan Carpenter
2025-09-10 21:49 ` [PATCH 08/10] io_uring: add __io_open_prep() helper Thomas Bertschinger
2025-09-10 21:49 ` [PATCH 09/10] io_uring: add support for IORING_OP_OPEN_BY_HANDLE_AT Thomas Bertschinger
2025-09-10 21:49 ` [PATCH 10/10] xfs: add support for non-blocking fh_to_dentry() Thomas Bertschinger
2025-09-11 12:29   ` Christoph Hellwig
2025-09-11 12:39     ` Amir Goldstein
2025-09-11 15:15       ` Thomas Bertschinger
2025-09-11 15:16         ` Amir Goldstein
2025-09-11 12:38   ` Amir Goldstein

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox