All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] API for exporting connectable file handles to userspace
@ 2024-10-08 15:21 Amir Goldstein
  2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Amir Goldstein @ 2024-10-08 15:21 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

Jeff,

These patches bring the NFS connectable file handles feature to
userspace servers.

They rely on Christian's and Aleksa's changes recently merged to v6.12.

The API I chose for encoding conenctable file handles is pretty
conventional (AT_HANDLE_CONNECTABLE).

open_by_handle_at(2) does not have AT_ flags argument, but also, I find
it more useful API that encoding a connectable file handle can mandate
the resolving of a connected fd, without having to opt-in for a
connected fd independently.

I chose to implemnent this by using upper bits in the handle type field
It may be valid (?) for filesystems to return a handle type with upper
bits set, but AFAIK, no in-tree filesystem does that.
I added some assertions just in case.

Thanks,
Amir.

Changes since v2 [2]:
- Use bit arithmetics instead of bitfileds (Jeff)
- Add assertions about use of high type bits

Changes since v1 [1]:
- Assert on encode for disconnected path (Jeff)
- Don't allow AT_HANDLE_CONNECTABLE with AT_EMPTY_PATH
- Drop the O_PATH mount_fd API hack (Jeff)
- Encode an explicit "connectable" flag in handle type

[1] https://lore.kernel.org/linux-fsdevel/20240919140611.1771651-1-amir73il@gmail.com/
[2] https://lore.kernel.org/linux-fsdevel/20240923082829.1910210-1-amir73il@gmail.com/

Amir Goldstein (3):
  fs: prepare for "explicit connectable" file handles
  fs: name_to_handle_at() support for "explicit connectable" file
    handles
  fs: open_by_handle_at() support for decoding "explicit connectable"
    file handles

 fs/exportfs/expfs.c        | 14 ++++++--
 fs/fhandle.c               | 74 ++++++++++++++++++++++++++++++++++----
 include/linux/exportfs.h   | 16 +++++++++
 include/uapi/linux/fcntl.h |  1 +
 4 files changed, 97 insertions(+), 8 deletions(-)

-- 
2.34.1


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

* [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
  2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
@ 2024-10-08 15:21 ` Amir Goldstein
  2024-10-08 18:19   ` Jeff Layton
                     ` (2 more replies)
  2024-10-08 15:21 ` [PATCH v3 2/3] fs: name_to_handle_at() support " Amir Goldstein
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 15+ messages in thread
From: Amir Goldstein @ 2024-10-08 15:21 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

We would like to use the high 16bit of the handle_type field to encode
file handle traits, such as "connectable".

In preparation for this change, make sure that filesystems do not return
a handle_type value with upper bits set and that the open_by_handle_at(2)
syscall rejects these handle types.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/exportfs/expfs.c      | 14 ++++++++++++--
 fs/fhandle.c             |  6 ++++++
 include/linux/exportfs.h | 14 ++++++++++++++
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 4f2dd4ab4486..c8eb660fdde4 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -382,14 +382,21 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
 			     int *max_len, struct inode *parent, int flags)
 {
 	const struct export_operations *nop = inode->i_sb->s_export_op;
+	enum fid_type type;
 
 	if (!exportfs_can_encode_fh(nop, flags))
 		return -EOPNOTSUPP;
 
 	if (!nop && (flags & EXPORT_FH_FID))
-		return exportfs_encode_ino64_fid(inode, fid, max_len);
+		type = exportfs_encode_ino64_fid(inode, fid, max_len);
+	else
+		type = nop->encode_fh(inode, fid->raw, max_len, parent);
+
+	if (WARN_ON_ONCE(FILEID_USER_FLAGS(type)))
+		return -EINVAL;
+
+	return type;
 
-	return nop->encode_fh(inode, fid->raw, max_len, parent);
 }
 EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
 
@@ -436,6 +443,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
 	char nbuf[NAME_MAX+1];
 	int err;
 
+	if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
+		return -EINVAL;
+
 	/*
 	 * Try to get any dentry for the given file handle from the filesystem.
 	 */
diff --git a/fs/fhandle.c b/fs/fhandle.c
index 82df28d45cd7..c5792cf3c6e9 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -307,6 +307,10 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
 		retval = -EINVAL;
 		goto out_path;
 	}
+	if (!FILEID_USER_TYPE_IS_VALID(f_handle.handle_type)) {
+		retval = -EINVAL;
+		goto out_path;
+	}
 	handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
 			 GFP_KERNEL);
 	if (!handle) {
@@ -322,6 +326,8 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
 		goto out_handle;
 	}
 
+	/* Filesystem code should not be exposed to user flags */
+	handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
 	retval = do_handle_to_path(handle, path, &ctx);
 
 out_handle:
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 893a1d21dc1c..76a3050b3593 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -160,6 +160,20 @@ struct fid {
 #define EXPORT_FH_FID		0x2 /* File handle may be non-decodeable */
 #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().
+ */
+#define FILEID_USER_FLAGS_MASK	0xffff0000
+#define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
+
+/* Flags supported in encoded handle_type that is exported to user */
+#define FILEID_VALID_USER_FLAGS	(0)
+
+#define FILEID_USER_TYPE_IS_VALID(type) \
+	(!(FILEID_USER_FLAGS(type) & ~FILEID_VALID_USER_FLAGS))
+
 /**
  * struct export_operations - for nfsd to communicate with file systems
  * @encode_fh:      encode a file handle fragment from a dentry
-- 
2.34.1


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

* [PATCH v3 2/3] fs: name_to_handle_at() support for "explicit connectable" file handles
  2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
  2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
@ 2024-10-08 15:21 ` Amir Goldstein
  2024-10-08 18:31   ` Jeff Layton
  2024-10-08 15:21 ` [PATCH v3 3/3] fs: open_by_handle_at() support for decoding " Amir Goldstein
  2024-10-09  7:17 ` [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
  3 siblings, 1 reply; 15+ messages in thread
From: Amir Goldstein @ 2024-10-08 15:21 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

nfsd encodes "connectable" file handles for the subtree_check feature,
which can be resolved to an open file with a connected path.
So far, userspace nfs server could not make use of this functionality.

Introduce a new flag AT_HANDLE_CONNECTABLE to name_to_handle_at(2).
When used, the encoded file handle is "explicitly connectable".

The "explicitly connectable" file handle sets bits in the high 16bit of
the handle_type field, so open_by_handle_at(2) will know that it needs
to open a file with a connected path.

old kernels will now recognize the handle_type with high bits set,
so "explicitly connectable" file handles cannot be decoded by
open_by_handle_at(2) on old kernels.

The flag AT_HANDLE_CONNECTABLE is not allowed together with either
AT_HANDLE_FID or AT_EMPTY_PATH.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/fhandle.c               | 48 ++++++++++++++++++++++++++++++++++----
 include/linux/exportfs.h   |  2 ++
 include/uapi/linux/fcntl.h |  1 +
 3 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/fs/fhandle.c b/fs/fhandle.c
index c5792cf3c6e9..7b4c8945efcb 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -31,6 +31,14 @@ static long do_sys_name_to_handle(const struct path *path,
 	if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags))
 		return -EOPNOTSUPP;
 
+	/*
+	 * A request to encode a connectable handle for a disconnected dentry
+	 * is unexpected since AT_EMPTY_PATH is not allowed.
+	 */
+	if (fh_flags & EXPORT_FH_CONNECTABLE &&
+	    WARN_ON(path->dentry->d_flags & DCACHE_DISCONNECTED))
+		return -EINVAL;
+
 	if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
 		return -EFAULT;
 
@@ -45,7 +53,7 @@ static long do_sys_name_to_handle(const struct path *path,
 	/* convert handle size to multiple of sizeof(u32) */
 	handle_dwords = f_handle.handle_bytes >> 2;
 
-	/* we ask for a non connectable maybe decodeable file handle */
+	/* Encode a possibly decodeable/connectable file handle */
 	retval = exportfs_encode_fh(path->dentry,
 				    (struct fid *)handle->f_handle,
 				    &handle_dwords, fh_flags);
@@ -67,8 +75,23 @@ static long do_sys_name_to_handle(const struct path *path,
 		 * non variable part of the file_handle
 		 */
 		handle_bytes = 0;
-	} else
+	} else {
+		/*
+		 * When asked to encode a connectable file handle, encode this
+		 * property in the file handle itself, so that we later know
+		 * how to decode it.
+		 * For sanity, also encode in the file handle if the encoded
+		 * object is a directory and verify this during decode, because
+		 * decoding directory file handles is quite different than
+		 * decoding connectable non-directory file handles.
+		 */
+		if (fh_flags & EXPORT_FH_CONNECTABLE) {
+			handle->handle_type |= FILEID_IS_CONNECTABLE;
+			if (d_is_dir(path->dentry))
+				fh_flags |= FILEID_IS_DIR;
+		}
 		retval = 0;
+	}
 	/* copy the mount id */
 	if (unique_mntid) {
 		if (put_user(real_mount(path->mnt)->mnt_id_unique,
@@ -109,15 +132,30 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
 {
 	struct path path;
 	int lookup_flags;
-	int fh_flags;
+	int fh_flags = 0;
 	int err;
 
 	if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID |
-		     AT_HANDLE_MNT_ID_UNIQUE))
+		     AT_HANDLE_MNT_ID_UNIQUE | AT_HANDLE_CONNECTABLE))
+		return -EINVAL;
+
+	/*
+	 * AT_HANDLE_FID means there is no intention to decode file handle
+	 * AT_HANDLE_CONNECTABLE means there is an intention to decode a
+	 * connected fd (with known path), so these flags are conflicting.
+	 * AT_EMPTY_PATH could be used along with a dfd that refers to a
+	 * disconnected non-directory, which cannot be used to encode a
+	 * connectable file handle, because its parent is unknown.
+	 */
+	if (flag & AT_HANDLE_CONNECTABLE &&
+	    flag & (AT_HANDLE_FID | AT_EMPTY_PATH))
 		return -EINVAL;
+	else if (flag & AT_HANDLE_FID)
+		fh_flags |= EXPORT_FH_FID;
+	else if (flag & AT_HANDLE_CONNECTABLE)
+		fh_flags |= EXPORT_FH_CONNECTABLE;
 
 	lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
-	fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
 	if (flag & AT_EMPTY_PATH)
 		lookup_flags |= LOOKUP_EMPTY;
 	err = user_path_at(dfd, name, lookup_flags, &path);
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 76a3050b3593..230b0e1d669d 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -169,6 +169,8 @@ struct fid {
 #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
 
 /* Flags supported in encoded handle_type that is exported to user */
+#define FILEID_IS_CONNECTABLE	0x10000
+#define FILEID_IS_DIR		0x40000
 #define FILEID_VALID_USER_FLAGS	(0)
 
 #define FILEID_USER_TYPE_IS_VALID(type) \
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index 87e2dec79fea..56ff2100e021 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -153,6 +153,7 @@
 					   object identity and may not be
 					   usable with open_by_handle_at(2). */
 #define AT_HANDLE_MNT_ID_UNIQUE	0x001	/* Return the u64 unique mount ID. */
+#define AT_HANDLE_CONNECTABLE	0x002	/* Request a connectable file handle */
 
 #if defined(__KERNEL__)
 #define AT_GETATTR_NOSEC	0x80000000
-- 
2.34.1


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

* [PATCH v3 3/3] fs: open_by_handle_at() support for decoding "explicit connectable" file handles
  2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
  2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
  2024-10-08 15:21 ` [PATCH v3 2/3] fs: name_to_handle_at() support " Amir Goldstein
@ 2024-10-08 15:21 ` Amir Goldstein
  2024-10-08 18:37   ` Jeff Layton
  2024-10-09  7:17 ` [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
  3 siblings, 1 reply; 15+ messages in thread
From: Amir Goldstein @ 2024-10-08 15:21 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

Teach open_by_handle_at(2) about the type format of "explicit connectable"
file handles that were created using the AT_HANDLE_CONNECTABLE flag to
name_to_handle_at(2).

When decoding an "explicit connectable" file handles, name_to_handle_at(2)
should fail if it cannot open a "connected" fd with known path, which is
accessible (to capable user) from mount fd path.

Note that this does not check if the path is accessible to the calling
user, just that it is accessible wrt the mount namesapce, so if there
is no "connected" alias, or if parts of the path are hidden in the
mount namespace, open_by_handle_at(2) will return -ESTALE.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/fhandle.c             | 20 +++++++++++++++++++-
 include/linux/exportfs.h |  2 +-
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/fs/fhandle.c b/fs/fhandle.c
index 7b4c8945efcb..6a5458c3c6c9 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -246,7 +246,13 @@ static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
 
 	if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root)
 		retval = 1;
-	WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
+	/*
+	 * exportfs_decode_fh_raw() does not call acceptable() callback with
+	 * a disconnected directory dentry, so we should have reached either
+	 * mount fd directory or sb root.
+	 */
+	if (ctx->fh_flags & EXPORT_FH_DIR_ONLY)
+		WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
 	dput(d);
 	return retval;
 }
@@ -349,6 +355,7 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
 		retval = -EINVAL;
 		goto out_path;
 	}
+
 	handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
 			 GFP_KERNEL);
 	if (!handle) {
@@ -364,6 +371,17 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
 		goto out_handle;
 	}
 
+	/*
+	 * 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) {
+		ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
+		ctx.flags |= HANDLE_CHECK_SUBTREE;
+	}
+	if (f_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;
 	retval = do_handle_to_path(handle, path, &ctx);
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 230b0e1d669d..a48d4c94ff74 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -171,7 +171,7 @@ struct fid {
 /* Flags supported in encoded handle_type that is exported to user */
 #define FILEID_IS_CONNECTABLE	0x10000
 #define FILEID_IS_DIR		0x40000
-#define FILEID_VALID_USER_FLAGS	(0)
+#define FILEID_VALID_USER_FLAGS	(FILEID_IS_CONNECTABLE | FILEID_IS_DIR)
 
 #define FILEID_USER_TYPE_IS_VALID(type) \
 	(!(FILEID_USER_FLAGS(type) & ~FILEID_VALID_USER_FLAGS))
-- 
2.34.1


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

* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
  2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
@ 2024-10-08 18:19   ` Jeff Layton
  2024-10-08 20:31     ` Amir Goldstein
  2024-10-11 11:03   ` kernel test robot
  2024-10-11 17:21   ` kernel test robot
  2 siblings, 1 reply; 15+ messages in thread
From: Jeff Layton @ 2024-10-08 18:19 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> We would like to use the high 16bit of the handle_type field to encode
> file handle traits, such as "connectable".
> 
> In preparation for this change, make sure that filesystems do not return
> a handle_type value with upper bits set and that the open_by_handle_at(2)
> syscall rejects these handle types.
> 
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>  fs/exportfs/expfs.c      | 14 ++++++++++++--
>  fs/fhandle.c             |  6 ++++++
>  include/linux/exportfs.h | 14 ++++++++++++++
>  3 files changed, 32 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> index 4f2dd4ab4486..c8eb660fdde4 100644
> --- a/fs/exportfs/expfs.c
> +++ b/fs/exportfs/expfs.c
> @@ -382,14 +382,21 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
>  			     int *max_len, struct inode *parent, int flags)
>  {
>  	const struct export_operations *nop = inode->i_sb->s_export_op;
> +	enum fid_type type;
>  
>  	if (!exportfs_can_encode_fh(nop, flags))
>  		return -EOPNOTSUPP;
>  
>  	if (!nop && (flags & EXPORT_FH_FID))
> -		return exportfs_encode_ino64_fid(inode, fid, max_len);
> +		type = exportfs_encode_ino64_fid(inode, fid, max_len);
> +	else
> +		type = nop->encode_fh(inode, fid->raw, max_len, parent);
> +
> +	if (WARN_ON_ONCE(FILEID_USER_FLAGS(type)))
> +		return -EINVAL;
> +

The stack trace won't be very useful here. Rather than a WARN, it might
be better to dump out some info about the fstype (and maybe other
info?) that returned the bogus type value here. I'm pretty sure most
in-kernel fs's don't do this, but who knows what 3rd party fs's might
do.

> +	return type;
>  
> -	return nop->encode_fh(inode, fid->raw, max_len, parent);
>  }
>  EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
>  
> @@ -436,6 +443,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
>  	char nbuf[NAME_MAX+1];
>  	int err;
>  
> +	if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
> +		return -EINVAL;
> +


This is called from do_handle_to_path() or nfsd_set_fh_dentry(), which
means that this fh comes from userland or from an NFS client. I don't
think we want to WARN because someone crafted a bogus fh and passed it
to us.


>  	/*
>  	 * Try to get any dentry for the given file handle from the filesystem.
>  	 */
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index 82df28d45cd7..c5792cf3c6e9 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -307,6 +307,10 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>  		retval = -EINVAL;
>  		goto out_path;
>  	}
> +	if (!FILEID_USER_TYPE_IS_VALID(f_handle.handle_type)) {
> +		retval = -EINVAL;
> +		goto out_path;
> +	}
>  	handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
>  			 GFP_KERNEL);
>  	if (!handle) {
> @@ -322,6 +326,8 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>  		goto out_handle;
>  	}
>  
> +	/* Filesystem code should not be exposed to user flags */
> +	handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
>  	retval = do_handle_to_path(handle, path, &ctx);
>  
>  out_handle:
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 893a1d21dc1c..76a3050b3593 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -160,6 +160,20 @@ struct fid {
>  #define EXPORT_FH_FID		0x2 /* File handle may be non-decodeable */
>  #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().
> + */
> +#define FILEID_USER_FLAGS_MASK	0xffff0000
> +#define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
> +
> +/* Flags supported in encoded handle_type that is exported to user */
> +#define FILEID_VALID_USER_FLAGS	(0)
> +
> +#define FILEID_USER_TYPE_IS_VALID(type) \
> +	(!(FILEID_USER_FLAGS(type) & ~FILEID_VALID_USER_FLAGS))
> +
>  /**
>   * struct export_operations - for nfsd to communicate with file systems
>   * @encode_fh:      encode a file handle fragment from a dentry

The rest looks reasonable.
-- 
Jeff Layton <jlayton@kernel.org>

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

* Re: [PATCH v3 2/3] fs: name_to_handle_at() support for "explicit connectable" file handles
  2024-10-08 15:21 ` [PATCH v3 2/3] fs: name_to_handle_at() support " Amir Goldstein
@ 2024-10-08 18:31   ` Jeff Layton
  2024-10-08 19:43     ` Amir Goldstein
  0 siblings, 1 reply; 15+ messages in thread
From: Jeff Layton @ 2024-10-08 18:31 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> nfsd encodes "connectable" file handles for the subtree_check feature,
> which can be resolved to an open file with a connected path.
> So far, userspace nfs server could not make use of this functionality.
> 
> Introduce a new flag AT_HANDLE_CONNECTABLE to name_to_handle_at(2).
> When used, the encoded file handle is "explicitly connectable".
> 
> The "explicitly connectable" file handle sets bits in the high 16bit of
> the handle_type field, so open_by_handle_at(2) will know that it needs
> to open a file with a connected path.
> 
> old kernels will now recognize the handle_type with high bits set,
> so "explicitly connectable" file handles cannot be decoded by
> open_by_handle_at(2) on old kernels.
> 
> The flag AT_HANDLE_CONNECTABLE is not allowed together with either
> AT_HANDLE_FID or AT_EMPTY_PATH.
> 
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>  fs/fhandle.c               | 48 ++++++++++++++++++++++++++++++++++----
>  include/linux/exportfs.h   |  2 ++
>  include/uapi/linux/fcntl.h |  1 +
>  3 files changed, 46 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index c5792cf3c6e9..7b4c8945efcb 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -31,6 +31,14 @@ static long do_sys_name_to_handle(const struct path *path,
>  	if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags))
>  		return -EOPNOTSUPP;
>  
> +	/*
> +	 * A request to encode a connectable handle for a disconnected dentry
> +	 * is unexpected since AT_EMPTY_PATH is not allowed.
> +	 */
> +	if (fh_flags & EXPORT_FH_CONNECTABLE &&
> +	    WARN_ON(path->dentry->d_flags & DCACHE_DISCONNECTED))
> +		return -EINVAL;
> +

Is it possible to get a DCACHE_DISCONNECTED dentry here? This thing
comes from a userland path walk (a'la name_to_handle_at()). That means
that it necessarily is connected.

I'd drop the fh_flags check, since it seems like having that set on any
dentry we get in this interface would be a bug.

>  	if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
>  		return -EFAULT;
>  
> @@ -45,7 +53,7 @@ static long do_sys_name_to_handle(const struct path *path,
>  	/* convert handle size to multiple of sizeof(u32) */
>  	handle_dwords = f_handle.handle_bytes >> 2;
>  
> -	/* we ask for a non connectable maybe decodeable file handle */
> +	/* Encode a possibly decodeable/connectable file handle */
>  	retval = exportfs_encode_fh(path->dentry,
>  				    (struct fid *)handle->f_handle,
>  				    &handle_dwords, fh_flags);
> @@ -67,8 +75,23 @@ static long do_sys_name_to_handle(const struct path *path,
>  		 * non variable part of the file_handle
>  		 */
>  		handle_bytes = 0;
> -	} else
> +	} else {
> +		/*
> +		 * When asked to encode a connectable file handle, encode this
> +		 * property in the file handle itself, so that we later know
> +		 * how to decode it.
> +		 * For sanity, also encode in the file handle if the encoded
> +		 * object is a directory and verify this during decode, because
> +		 * decoding directory file handles is quite different than
> +		 * decoding connectable non-directory file handles.
> +		 */
> +		if (fh_flags & EXPORT_FH_CONNECTABLE) {
> +			handle->handle_type |= FILEID_IS_CONNECTABLE;
> +			if (d_is_dir(path->dentry))
> +				fh_flags |= FILEID_IS_DIR;
> +		}
>  		retval = 0;
> +	}
>  	/* copy the mount id */
>  	if (unique_mntid) {
>  		if (put_user(real_mount(path->mnt)->mnt_id_unique,
> @@ -109,15 +132,30 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
>  {
>  	struct path path;
>  	int lookup_flags;
> -	int fh_flags;
> +	int fh_flags = 0;
>  	int err;
>  
>  	if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID |
> -		     AT_HANDLE_MNT_ID_UNIQUE))
> +		     AT_HANDLE_MNT_ID_UNIQUE | AT_HANDLE_CONNECTABLE))
> +		return -EINVAL;
> +
> +	/*
> +	 * AT_HANDLE_FID means there is no intention to decode file handle
> +	 * AT_HANDLE_CONNECTABLE means there is an intention to decode a
> +	 * connected fd (with known path), so these flags are conflicting.
> +	 * AT_EMPTY_PATH could be used along with a dfd that refers to a
> +	 * disconnected non-directory, which cannot be used to encode a
> +	 * connectable file handle, because its parent is unknown.
> +	 */
> +	if (flag & AT_HANDLE_CONNECTABLE &&
> +	    flag & (AT_HANDLE_FID | AT_EMPTY_PATH))
>  		return -EINVAL;
> +	else if (flag & AT_HANDLE_FID)
> +		fh_flags |= EXPORT_FH_FID;
> +	else if (flag & AT_HANDLE_CONNECTABLE)
> +		fh_flags |= EXPORT_FH_CONNECTABLE;
>  
>  	lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
> -	fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
>  	if (flag & AT_EMPTY_PATH)
>  		lookup_flags |= LOOKUP_EMPTY;
>  	err = user_path_at(dfd, name, lookup_flags, &path);
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 76a3050b3593..230b0e1d669d 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -169,6 +169,8 @@ struct fid {
>  #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
>  
>  /* Flags supported in encoded handle_type that is exported to user */
> +#define FILEID_IS_CONNECTABLE	0x10000
> +#define FILEID_IS_DIR		0x40000

nit: why skip 0x20000 ?

>  #define FILEID_VALID_USER_FLAGS	(0)
>  
>  #define FILEID_USER_TYPE_IS_VALID(type) \
> diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
> index 87e2dec79fea..56ff2100e021 100644
> --- a/include/uapi/linux/fcntl.h
> +++ b/include/uapi/linux/fcntl.h
> @@ -153,6 +153,7 @@
>  					   object identity and may not be
>  					   usable with open_by_handle_at(2). */
>  #define AT_HANDLE_MNT_ID_UNIQUE	0x001	/* Return the u64 unique mount ID. */
> +#define AT_HANDLE_CONNECTABLE	0x002	/* Request a connectable file handle */
>  
>  #if defined(__KERNEL__)
>  #define AT_GETATTR_NOSEC	0x80000000

-- 
Jeff Layton <jlayton@kernel.org>

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

* Re: [PATCH v3 3/3] fs: open_by_handle_at() support for decoding "explicit connectable" file handles
  2024-10-08 15:21 ` [PATCH v3 3/3] fs: open_by_handle_at() support for decoding " Amir Goldstein
@ 2024-10-08 18:37   ` Jeff Layton
  2024-10-08 20:01     ` Amir Goldstein
  0 siblings, 1 reply; 15+ messages in thread
From: Jeff Layton @ 2024-10-08 18:37 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> Teach open_by_handle_at(2) about the type format of "explicit connectable"
> file handles that were created using the AT_HANDLE_CONNECTABLE flag to
> name_to_handle_at(2).
> 
> When decoding an "explicit connectable" file handles, name_to_handle_at(2)
> should fail if it cannot open a "connected" fd with known path, which is
> accessible (to capable user) from mount fd path.
> 
> Note that this does not check if the path is accessible to the calling
> user, just that it is accessible wrt the mount namesapce, so if there
> is no "connected" alias, or if parts of the path are hidden in the
> mount namespace, open_by_handle_at(2) will return -ESTALE.
> 
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>  fs/fhandle.c             | 20 +++++++++++++++++++-
>  include/linux/exportfs.h |  2 +-
>  2 files changed, 20 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index 7b4c8945efcb..6a5458c3c6c9 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -246,7 +246,13 @@ static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
>  
>  	if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root)
>  		retval = 1;
> -	WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
> +	/*
> +	 * exportfs_decode_fh_raw() does not call acceptable() callback with
> +	 * a disconnected directory dentry, so we should have reached either
> +	 * mount fd directory or sb root.
> +	 */
> +	if (ctx->fh_flags & EXPORT_FH_DIR_ONLY)
> +		WARN_ON_ONCE(d != root && d != root->d_sb->s_root);

I don't quite get the test for EXPORT_FH_DIR_ONLY here. Why does this
change require that instead of just continuing to WARN unconditionally?

>  	dput(d);
>  	return retval;
>  }
> @@ -349,6 +355,7 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>  		retval = -EINVAL;
>  		goto out_path;
>  	}
> +
>  	handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
>  			 GFP_KERNEL);
>  	if (!handle) {
> @@ -364,6 +371,17 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
>  		goto out_handle;
>  	}
>  
> +	/*
> +	 * 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) {
> +		ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
> +		ctx.flags |= HANDLE_CHECK_SUBTREE;
> +	}
> +	if (f_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;
>  	retval = do_handle_to_path(handle, path, &ctx);
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 230b0e1d669d..a48d4c94ff74 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -171,7 +171,7 @@ struct fid {
>  /* Flags supported in encoded handle_type that is exported to user */
>  #define FILEID_IS_CONNECTABLE	0x10000
>  #define FILEID_IS_DIR		0x40000
> -#define FILEID_VALID_USER_FLAGS	(0)
> +#define FILEID_VALID_USER_FLAGS	(FILEID_IS_CONNECTABLE | FILEID_IS_DIR)
>  
>  #define FILEID_USER_TYPE_IS_VALID(type) \
>  	(!(FILEID_USER_FLAGS(type) & ~FILEID_VALID_USER_FLAGS))

-- 
Jeff Layton <jlayton@kernel.org>

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

* Re: [PATCH v3 2/3] fs: name_to_handle_at() support for "explicit connectable" file handles
  2024-10-08 18:31   ` Jeff Layton
@ 2024-10-08 19:43     ` Amir Goldstein
  0 siblings, 0 replies; 15+ messages in thread
From: Amir Goldstein @ 2024-10-08 19:43 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

On Tue, Oct 8, 2024 at 8:31 PM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> > nfsd encodes "connectable" file handles for the subtree_check feature,
> > which can be resolved to an open file with a connected path.
> > So far, userspace nfs server could not make use of this functionality.
> >
> > Introduce a new flag AT_HANDLE_CONNECTABLE to name_to_handle_at(2).
> > When used, the encoded file handle is "explicitly connectable".
> >
> > The "explicitly connectable" file handle sets bits in the high 16bit of
> > the handle_type field, so open_by_handle_at(2) will know that it needs
> > to open a file with a connected path.
> >
> > old kernels will now recognize the handle_type with high bits set,
> > so "explicitly connectable" file handles cannot be decoded by
> > open_by_handle_at(2) on old kernels.
> >
> > The flag AT_HANDLE_CONNECTABLE is not allowed together with either
> > AT_HANDLE_FID or AT_EMPTY_PATH.
> >
> > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > ---
> >  fs/fhandle.c               | 48 ++++++++++++++++++++++++++++++++++----
> >  include/linux/exportfs.h   |  2 ++
> >  include/uapi/linux/fcntl.h |  1 +
> >  3 files changed, 46 insertions(+), 5 deletions(-)
> >
> > diff --git a/fs/fhandle.c b/fs/fhandle.c
> > index c5792cf3c6e9..7b4c8945efcb 100644
> > --- a/fs/fhandle.c
> > +++ b/fs/fhandle.c
> > @@ -31,6 +31,14 @@ static long do_sys_name_to_handle(const struct path *path,
> >       if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags))
> >               return -EOPNOTSUPP;
> >
> > +     /*
> > +      * A request to encode a connectable handle for a disconnected dentry
> > +      * is unexpected since AT_EMPTY_PATH is not allowed.
> > +      */
> > +     if (fh_flags & EXPORT_FH_CONNECTABLE &&
> > +         WARN_ON(path->dentry->d_flags & DCACHE_DISCONNECTED))
> > +             return -EINVAL;
> > +
>
> Is it possible to get a DCACHE_DISCONNECTED dentry here? This thing
> comes from a userland path walk (a'la name_to_handle_at()). That means
> that it necessarily is connected.

Can't you get it with AT_EMPTY_PATH if dfd is obtained by open_by_handle()?

>
> I'd drop the fh_flags check, since it seems like having that set on any
> dentry we get in this interface would be a bug.
>

Well I don't know if giving a disconnected dentry to name_to_handle
is intentional, but it is not wrong, unless user actually requests a
connectable file handle. No?

> >       if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
> >               return -EFAULT;
> >
> > @@ -45,7 +53,7 @@ static long do_sys_name_to_handle(const struct path *path,
> >       /* convert handle size to multiple of sizeof(u32) */
> >       handle_dwords = f_handle.handle_bytes >> 2;
> >
> > -     /* we ask for a non connectable maybe decodeable file handle */
> > +     /* Encode a possibly decodeable/connectable file handle */
> >       retval = exportfs_encode_fh(path->dentry,
> >                                   (struct fid *)handle->f_handle,
> >                                   &handle_dwords, fh_flags);
> > @@ -67,8 +75,23 @@ static long do_sys_name_to_handle(const struct path *path,
> >                * non variable part of the file_handle
> >                */
> >               handle_bytes = 0;
> > -     } else
> > +     } else {
> > +             /*
> > +              * When asked to encode a connectable file handle, encode this
> > +              * property in the file handle itself, so that we later know
> > +              * how to decode it.
> > +              * For sanity, also encode in the file handle if the encoded
> > +              * object is a directory and verify this during decode, because
> > +              * decoding directory file handles is quite different than
> > +              * decoding connectable non-directory file handles.
> > +              */
> > +             if (fh_flags & EXPORT_FH_CONNECTABLE) {
> > +                     handle->handle_type |= FILEID_IS_CONNECTABLE;
> > +                     if (d_is_dir(path->dentry))
> > +                             fh_flags |= FILEID_IS_DIR;
> > +             }
> >               retval = 0;
> > +     }
> >       /* copy the mount id */
> >       if (unique_mntid) {
> >               if (put_user(real_mount(path->mnt)->mnt_id_unique,
> > @@ -109,15 +132,30 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
> >  {
> >       struct path path;
> >       int lookup_flags;
> > -     int fh_flags;
> > +     int fh_flags = 0;
> >       int err;
> >
> >       if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID |
> > -                  AT_HANDLE_MNT_ID_UNIQUE))
> > +                  AT_HANDLE_MNT_ID_UNIQUE | AT_HANDLE_CONNECTABLE))
> > +             return -EINVAL;
> > +
> > +     /*
> > +      * AT_HANDLE_FID means there is no intention to decode file handle
> > +      * AT_HANDLE_CONNECTABLE means there is an intention to decode a
> > +      * connected fd (with known path), so these flags are conflicting.
> > +      * AT_EMPTY_PATH could be used along with a dfd that refers to a
> > +      * disconnected non-directory, which cannot be used to encode a
> > +      * connectable file handle, because its parent is unknown.
> > +      */
> > +     if (flag & AT_HANDLE_CONNECTABLE &&
> > +         flag & (AT_HANDLE_FID | AT_EMPTY_PATH))
> >               return -EINVAL;
> > +     else if (flag & AT_HANDLE_FID)
> > +             fh_flags |= EXPORT_FH_FID;
> > +     else if (flag & AT_HANDLE_CONNECTABLE)
> > +             fh_flags |= EXPORT_FH_CONNECTABLE;
> >
> >       lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
> > -     fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
> >       if (flag & AT_EMPTY_PATH)
> >               lookup_flags |= LOOKUP_EMPTY;
> >       err = user_path_at(dfd, name, lookup_flags, &path);
> > diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> > index 76a3050b3593..230b0e1d669d 100644
> > --- a/include/linux/exportfs.h
> > +++ b/include/linux/exportfs.h
> > @@ -169,6 +169,8 @@ struct fid {
> >  #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
> >
> >  /* Flags supported in encoded handle_type that is exported to user */
> > +#define FILEID_IS_CONNECTABLE        0x10000
> > +#define FILEID_IS_DIR                0x40000
>
> nit: why skip 0x20000 ?

Well in v2, the values were just shifting the EXPORT_FH_ flags left
so I kept it this way, although I am not sure if FILEID_ID_FID is ever
going to be useful, so I guess there is no good reason to skip 0x20000

Thanks,
Amir.

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

* Re: [PATCH v3 3/3] fs: open_by_handle_at() support for decoding "explicit connectable" file handles
  2024-10-08 18:37   ` Jeff Layton
@ 2024-10-08 20:01     ` Amir Goldstein
  0 siblings, 0 replies; 15+ messages in thread
From: Amir Goldstein @ 2024-10-08 20:01 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

On Tue, Oct 8, 2024 at 8:37 PM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> > Teach open_by_handle_at(2) about the type format of "explicit connectable"
> > file handles that were created using the AT_HANDLE_CONNECTABLE flag to
> > name_to_handle_at(2).
> >
> > When decoding an "explicit connectable" file handles, name_to_handle_at(2)
> > should fail if it cannot open a "connected" fd with known path, which is
> > accessible (to capable user) from mount fd path.
> >
> > Note that this does not check if the path is accessible to the calling
> > user, just that it is accessible wrt the mount namesapce, so if there
> > is no "connected" alias, or if parts of the path are hidden in the
> > mount namespace, open_by_handle_at(2) will return -ESTALE.
> >
> > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > ---
> >  fs/fhandle.c             | 20 +++++++++++++++++++-
> >  include/linux/exportfs.h |  2 +-
> >  2 files changed, 20 insertions(+), 2 deletions(-)
> >
> > diff --git a/fs/fhandle.c b/fs/fhandle.c
> > index 7b4c8945efcb..6a5458c3c6c9 100644
> > --- a/fs/fhandle.c
> > +++ b/fs/fhandle.c
> > @@ -246,7 +246,13 @@ static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
> >
> >       if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root)
> >               retval = 1;
> > -     WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
> > +     /*
> > +      * exportfs_decode_fh_raw() does not call acceptable() callback with
> > +      * a disconnected directory dentry, so we should have reached either
> > +      * mount fd directory or sb root.
> > +      */
> > +     if (ctx->fh_flags & EXPORT_FH_DIR_ONLY)
> > +             WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
>
> I don't quite get the test for EXPORT_FH_DIR_ONLY here. Why does this
> change require that instead of just continuing to WARN unconditionally?
>

The reason is at the end of may_decode_fh(), you have:
       ctx->fh_flags = EXPORT_FH_DIR_ONLY;
       return true;

So until THIS patch, vfs_dentry_acceptable() was always called
with EXPORT_FH_DIR_ONLY.

THIS patch adds another use case where HANDLE_CHECK_SUBTREE
is being requested, but this time EXPORT_FH_DIR_ONLY is optional.

The comment above "exportfs_decode_fh_raw() does not call acceptable()..."
explains why the assertion is only true for directories.

Thanks,
Amir.

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

* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
  2024-10-08 18:19   ` Jeff Layton
@ 2024-10-08 20:31     ` Amir Goldstein
  2024-10-10 11:01       ` Amir Goldstein
  0 siblings, 1 reply; 15+ messages in thread
From: Amir Goldstein @ 2024-10-08 20:31 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

On Tue, Oct 8, 2024 at 8:19 PM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> > We would like to use the high 16bit of the handle_type field to encode
> > file handle traits, such as "connectable".
> >
> > In preparation for this change, make sure that filesystems do not return
> > a handle_type value with upper bits set and that the open_by_handle_at(2)
> > syscall rejects these handle types.
> >
> > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > ---
> >  fs/exportfs/expfs.c      | 14 ++++++++++++--
> >  fs/fhandle.c             |  6 ++++++
> >  include/linux/exportfs.h | 14 ++++++++++++++
> >  3 files changed, 32 insertions(+), 2 deletions(-)
> >
> > diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> > index 4f2dd4ab4486..c8eb660fdde4 100644
> > --- a/fs/exportfs/expfs.c
> > +++ b/fs/exportfs/expfs.c
> > @@ -382,14 +382,21 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
> >                            int *max_len, struct inode *parent, int flags)
> >  {
> >       const struct export_operations *nop = inode->i_sb->s_export_op;
> > +     enum fid_type type;
> >
> >       if (!exportfs_can_encode_fh(nop, flags))
> >               return -EOPNOTSUPP;
> >
> >       if (!nop && (flags & EXPORT_FH_FID))
> > -             return exportfs_encode_ino64_fid(inode, fid, max_len);
> > +             type = exportfs_encode_ino64_fid(inode, fid, max_len);
> > +     else
> > +             type = nop->encode_fh(inode, fid->raw, max_len, parent);
> > +
> > +     if (WARN_ON_ONCE(FILEID_USER_FLAGS(type)))
> > +             return -EINVAL;
> > +
>
> The stack trace won't be very useful here. Rather than a WARN, it might
> be better to dump out some info about the fstype (and maybe other
> info?) that returned the bogus type value here. I'm pretty sure most
> in-kernel fs's don't do this, but who knows what 3rd party fs's might
> do.
>

Right. I changed to:

        if (FILEID_USER_FLAGS(type)) {
                pr_warn_once("%s: unexpected fh type value 0x%x from
fstype %s.\n",
                             __func__, type, inode->i_sb->s_type->name);
                return -EINVAL;
        }


> > +     return type;
> >
> > -     return nop->encode_fh(inode, fid->raw, max_len, parent);
> >  }
> >  EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
> >
> > @@ -436,6 +443,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
> >       char nbuf[NAME_MAX+1];
> >       int err;
> >
> > +     if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
> > +             return -EINVAL;
> > +
>
>
> This is called from do_handle_to_path() or nfsd_set_fh_dentry(), which
> means that this fh comes from userland or from an NFS client. I don't
> think we want to WARN because someone crafted a bogus fh and passed it
> to us.
>

Good point, I will remove the WARN and also fix the bug :-/

        if (FILEID_USER_FLAGS(fileid_type))
                return ERR_PTR(-EINVAL);

Pushed this and othe minor fixes to
https://github.com/amir73il/linux/commits/connectable-fh/
until we sort out the rest of your comments and maybe get more feedback.

Thanks for the review!
Amir.

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

* Re: [PATCH v3 0/3] API for exporting connectable file handles to userspace
  2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
                   ` (2 preceding siblings ...)
  2024-10-08 15:21 ` [PATCH v3 3/3] fs: open_by_handle_at() support for decoding " Amir Goldstein
@ 2024-10-09  7:17 ` Amir Goldstein
  3 siblings, 0 replies; 15+ messages in thread
From: Amir Goldstein @ 2024-10-09  7:17 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

On Tue, Oct 8, 2024 at 5:21 PM Amir Goldstein <amir73il@gmail.com> wrote:
>
> Jeff,
>
> These patches bring the NFS connectable file handles feature to
> userspace servers.
>
> They rely on Christian's and Aleksa's changes recently merged to v6.12.
>
> The API I chose for encoding conenctable file handles is pretty
> conventional (AT_HANDLE_CONNECTABLE).
>
> open_by_handle_at(2) does not have AT_ flags argument, but also, I find
> it more useful API that encoding a connectable file handle can mandate
> the resolving of a connected fd, without having to opt-in for a
> connected fd independently.
>
> I chose to implemnent this by using upper bits in the handle type field
> It may be valid (?) for filesystems to return a handle type with upper
> bits set, but AFAIK, no in-tree filesystem does that.
> I added some assertions just in case.

FYI, version with softened assertions at:
https://github.com/amir73il/linux/commits/connectable-fh/

fstest at:
https://github.com/amir73il/xfstests/commits/connectable-fh/

man-page at:
https://github.com/amir73il/man-pages/commits/connectable-fh/

>
> Thanks,
> Amir.
>
> Changes since v2 [2]:
> - Use bit arithmetics instead of bitfileds (Jeff)
> - Add assertions about use of high type bits
>
> Changes since v1 [1]:
> - Assert on encode for disconnected path (Jeff)
> - Don't allow AT_HANDLE_CONNECTABLE with AT_EMPTY_PATH
> - Drop the O_PATH mount_fd API hack (Jeff)
> - Encode an explicit "connectable" flag in handle type
>
> [1] https://lore.kernel.org/linux-fsdevel/20240919140611.1771651-1-amir73il@gmail.com/
> [2] https://lore.kernel.org/linux-fsdevel/20240923082829.1910210-1-amir73il@gmail.com/
>
> Amir Goldstein (3):
>   fs: prepare for "explicit connectable" file handles
>   fs: name_to_handle_at() support for "explicit connectable" file
>     handles
>   fs: open_by_handle_at() support for decoding "explicit connectable"
>     file handles
>
>  fs/exportfs/expfs.c        | 14 ++++++--
>  fs/fhandle.c               | 74 ++++++++++++++++++++++++++++++++++----
>  include/linux/exportfs.h   | 16 +++++++++
>  include/uapi/linux/fcntl.h |  1 +
>  4 files changed, 97 insertions(+), 8 deletions(-)
>
> --
> 2.34.1
>

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

* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
  2024-10-08 20:31     ` Amir Goldstein
@ 2024-10-10 11:01       ` Amir Goldstein
  0 siblings, 0 replies; 15+ messages in thread
From: Amir Goldstein @ 2024-10-10 11:01 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
	linux-fsdevel, linux-nfs

On Tue, Oct 8, 2024 at 10:31 PM Amir Goldstein <amir73il@gmail.com> wrote:
>
> On Tue, Oct 8, 2024 at 8:19 PM Jeff Layton <jlayton@kernel.org> wrote:
> >
> > On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> > > We would like to use the high 16bit of the handle_type field to encode
> > > file handle traits, such as "connectable".
> > >
> > > In preparation for this change, make sure that filesystems do not return
> > > a handle_type value with upper bits set and that the open_by_handle_at(2)
> > > syscall rejects these handle types.
> > >
> > > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > > ---
> > >  fs/exportfs/expfs.c      | 14 ++++++++++++--
> > >  fs/fhandle.c             |  6 ++++++
> > >  include/linux/exportfs.h | 14 ++++++++++++++
> > >  3 files changed, 32 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> > > index 4f2dd4ab4486..c8eb660fdde4 100644
> > > --- a/fs/exportfs/expfs.c
> > > +++ b/fs/exportfs/expfs.c
> > > @@ -382,14 +382,21 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
> > >                            int *max_len, struct inode *parent, int flags)
> > >  {
> > >       const struct export_operations *nop = inode->i_sb->s_export_op;
> > > +     enum fid_type type;
> > >
> > >       if (!exportfs_can_encode_fh(nop, flags))
> > >               return -EOPNOTSUPP;
> > >
> > >       if (!nop && (flags & EXPORT_FH_FID))
> > > -             return exportfs_encode_ino64_fid(inode, fid, max_len);
> > > +             type = exportfs_encode_ino64_fid(inode, fid, max_len);
> > > +     else
> > > +             type = nop->encode_fh(inode, fid->raw, max_len, parent);
> > > +
> > > +     if (WARN_ON_ONCE(FILEID_USER_FLAGS(type)))
> > > +             return -EINVAL;
> > > +
> >
> > The stack trace won't be very useful here. Rather than a WARN, it might
> > be better to dump out some info about the fstype (and maybe other
> > info?) that returned the bogus type value here. I'm pretty sure most
> > in-kernel fs's don't do this, but who knows what 3rd party fs's might
> > do.
> >
>
> Right. I changed to:
>
>         if (FILEID_USER_FLAGS(type)) {
>                 pr_warn_once("%s: unexpected fh type value 0x%x from
> fstype %s.\n",
>                              __func__, type, inode->i_sb->s_type->name);
>                 return -EINVAL;
>         }
>
>

FYI, following Jan's comment about mixing bitwise with negative values,
I changes this to:

        if (type > 0 && FILEID_USER_FLAGS(type)) {
                pr_warn_once("%s: unexpected fh type value 0x%x from
fstype %s.\n",
                             __func__, type, inode->i_sb->s_type->name);
                return -EINVAL;
        }

        return type;

because ->encode_fh() method are allowed to return a negative error
(e.g. -EOVERFLOW)

> > > +     return type;
> > >
> > > -     return nop->encode_fh(inode, fid->raw, max_len, parent);
> > >  }
> > >  EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
> > >
> > > @@ -436,6 +443,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
> > >       char nbuf[NAME_MAX+1];
> > >       int err;
> > >
> > > +     if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
> > > +             return -EINVAL;
> > > +
> >
> >
> > This is called from do_handle_to_path() or nfsd_set_fh_dentry(), which
> > means that this fh comes from userland or from an NFS client. I don't
> > think we want to WARN because someone crafted a bogus fh and passed it
> > to us.
> >
>
> Good point, I will remove the WARN and also fix the bug :-/
>
>         if (FILEID_USER_FLAGS(fileid_type))
>                 return ERR_PTR(-EINVAL);
>

And changed this to:

@@ -436,6 +446,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt,
struct fid *fid, int fh_len,
        char nbuf[NAME_MAX+1];
        int err;

+       if (fileid_type < 0 || FILEID_USER_FLAGS(fileid_type))
+               return ERR_PTR(-EINVAL);
+

> Pushed this and othe minor fixes to
> https://github.com/amir73il/linux/commits/connectable-fh/
> until we sort out the rest of your comments and maybe get more feedback.
>

If no further comments I will post v4.

Thanks,
Amir.

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

* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
  2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
  2024-10-08 18:19   ` Jeff Layton
@ 2024-10-11 11:03   ` kernel test robot
  2024-10-11 11:29     ` Amir Goldstein
  2024-10-11 17:21   ` kernel test robot
  2 siblings, 1 reply; 15+ messages in thread
From: kernel test robot @ 2024-10-11 11:03 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: llvm, oe-kbuild-all

Hi Amir,

kernel test robot noticed the following build errors:

[auto build test ERROR on brauner-vfs/vfs.all]
[also build test ERROR on linus/master v6.12-rc2 next-20241011]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Amir-Goldstein/fs-prepare-for-explicit-connectable-file-handles/20241008-232246
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link:    https://lore.kernel.org/r/20241008152118.453724-2-amir73il%40gmail.com
patch subject: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
config: s390-allnoconfig (https://download.01.org/0day-ci/archive/20241011/202410111804.pPMW9rqn-lkp@intel.com/config)
compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project 70e0a7e7e6a8541bcc46908c592eed561850e416)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241011/202410111804.pPMW9rqn-lkp@intel.com/reproduce)

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>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410111804.pPMW9rqn-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from fs/exportfs/expfs.c:15:
   In file included from include/linux/module.h:19:
   In file included from include/linux/elf.h:6:
   In file included from arch/s390/include/asm/elf.h:181:
   In file included from arch/s390/include/asm/mmu_context.h:11:
   In file included from arch/s390/include/asm/pgalloc.h:18:
   In file included from include/linux/mm.h:2213:
   include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     518 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
>> fs/exportfs/expfs.c:447:10: error: incompatible integer to pointer conversion returning 'int' from a function with result type 'struct dentry *' [-Wint-conversion]
     447 |                 return -EINVAL;
         |                        ^~~~~~~
   1 warning and 1 error generated.


vim +447 fs/exportfs/expfs.c

   434	
   435	struct dentry *
   436	exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
   437			       int fileid_type, unsigned int flags,
   438			       int (*acceptable)(void *, struct dentry *),
   439			       void *context)
   440	{
   441		const struct export_operations *nop = mnt->mnt_sb->s_export_op;
   442		struct dentry *result, *alias;
   443		char nbuf[NAME_MAX+1];
   444		int err;
   445	
   446		if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
 > 447			return -EINVAL;
   448	
   449		/*
   450		 * Try to get any dentry for the given file handle from the filesystem.
   451		 */
   452		if (!exportfs_can_decode_fh(nop))
   453			return ERR_PTR(-ESTALE);
   454		result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
   455		if (IS_ERR_OR_NULL(result))
   456			return result;
   457	
   458		if ((flags & EXPORT_FH_DIR_ONLY) && !d_is_dir(result)) {
   459			err = -ENOTDIR;
   460			goto err_result;
   461		}
   462	
   463		/*
   464		 * If no acceptance criteria was specified by caller, a disconnected
   465		 * dentry is also accepatable. Callers may use this mode to query if
   466		 * file handle is stale or to get a reference to an inode without
   467		 * risking the high overhead caused by directory reconnect.
   468		 */
   469		if (!acceptable)
   470			return result;
   471	
   472		if (d_is_dir(result)) {
   473			/*
   474			 * This request is for a directory.
   475			 *
   476			 * On the positive side there is only one dentry for each
   477			 * directory inode.  On the negative side this implies that we
   478			 * to ensure our dentry is connected all the way up to the
   479			 * filesystem root.
   480			 */
   481			if (result->d_flags & DCACHE_DISCONNECTED) {
   482				err = reconnect_path(mnt, result, nbuf);
   483				if (err)
   484					goto err_result;
   485			}
   486	
   487			if (!acceptable(context, result)) {
   488				err = -EACCES;
   489				goto err_result;
   490			}
   491	
   492			return result;
   493		} else {
   494			/*
   495			 * It's not a directory.  Life is a little more complicated.
   496			 */
   497			struct dentry *target_dir, *nresult;
   498	
   499			/*
   500			 * See if either the dentry we just got from the filesystem
   501			 * or any alias for it is acceptable.  This is always true
   502			 * if this filesystem is exported without the subtreecheck
   503			 * option.  If the filesystem is exported with the subtree
   504			 * check option there's a fair chance we need to look at
   505			 * the parent directory in the file handle and make sure
   506			 * it's connected to the filesystem root.
   507			 */
   508			alias = find_acceptable_alias(result, acceptable, context);
   509			if (alias)
   510				return alias;
   511	
   512			/*
   513			 * Try to extract a dentry for the parent directory from the
   514			 * file handle.  If this fails we'll have to give up.
   515			 */
   516			err = -ESTALE;
   517			if (!nop->fh_to_parent)
   518				goto err_result;
   519	
   520			target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
   521					fh_len, fileid_type);
   522			if (!target_dir)
   523				goto err_result;
   524			err = PTR_ERR(target_dir);
   525			if (IS_ERR(target_dir))
   526				goto err_result;
   527	
   528			/*
   529			 * And as usual we need to make sure the parent directory is
   530			 * connected to the filesystem root.  The VFS really doesn't
   531			 * like disconnected directories..
   532			 */
   533			err = reconnect_path(mnt, target_dir, nbuf);
   534			if (err) {
   535				dput(target_dir);
   536				goto err_result;
   537			}
   538	
   539			/*
   540			 * Now that we've got both a well-connected parent and a
   541			 * dentry for the inode we're after, make sure that our
   542			 * inode is actually connected to the parent.
   543			 */
   544			err = exportfs_get_name(mnt, target_dir, nbuf, result);
   545			if (err) {
   546				dput(target_dir);
   547				goto err_result;
   548			}
   549	
   550			inode_lock(target_dir->d_inode);
   551			nresult = lookup_one(mnt_idmap(mnt), nbuf,
   552					     target_dir, strlen(nbuf));
   553			if (!IS_ERR(nresult)) {
   554				if (unlikely(nresult->d_inode != result->d_inode)) {
   555					dput(nresult);
   556					nresult = ERR_PTR(-ESTALE);
   557				}
   558			}
   559			inode_unlock(target_dir->d_inode);
   560			/*
   561			 * At this point we are done with the parent, but it's pinned
   562			 * by the child dentry anyway.
   563			 */
   564			dput(target_dir);
   565	
   566			if (IS_ERR(nresult)) {
   567				err = PTR_ERR(nresult);
   568				goto err_result;
   569			}
   570			dput(result);
   571			result = nresult;
   572	
   573			/*
   574			 * And finally make sure the dentry is actually acceptable
   575			 * to NFSD.
   576			 */
   577			alias = find_acceptable_alias(result, acceptable, context);
   578			if (!alias) {
   579				err = -EACCES;
   580				goto err_result;
   581			}
   582	
   583			return alias;
   584		}
   585	
   586	 err_result:
   587		dput(result);
   588		return ERR_PTR(err);
   589	}
   590	EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw);
   591	

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

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

* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
  2024-10-11 11:03   ` kernel test robot
@ 2024-10-11 11:29     ` Amir Goldstein
  0 siblings, 0 replies; 15+ messages in thread
From: Amir Goldstein @ 2024-10-11 11:29 UTC (permalink / raw)
  To: kernel test robot; +Cc: llvm, oe-kbuild-all

On Fri, Oct 11, 2024 at 1:04 PM kernel test robot <lkp@intel.com> wrote:
>
> Hi Amir,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on brauner-vfs/vfs.all]
> [also build test ERROR on linus/master v6.12-rc2 next-20241011]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Amir-Goldstein/fs-prepare-for-explicit-connectable-file-handles/20241008-232246
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
> patch link:    https://lore.kernel.org/r/20241008152118.453724-2-amir73il%40gmail.com
> patch subject: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
> config: s390-allnoconfig (https://download.01.org/0day-ci/archive/20241011/202410111804.pPMW9rqn-lkp@intel.com/config)
> compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project 70e0a7e7e6a8541bcc46908c592eed561850e416)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241011/202410111804.pPMW9rqn-lkp@intel.com/reproduce)
>
> 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>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202410111804.pPMW9rqn-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
>    In file included from fs/exportfs/expfs.c:15:
>    In file included from include/linux/module.h:19:
>    In file included from include/linux/elf.h:6:
>    In file included from arch/s390/include/asm/elf.h:181:
>    In file included from arch/s390/include/asm/mmu_context.h:11:
>    In file included from arch/s390/include/asm/pgalloc.h:18:
>    In file included from include/linux/mm.h:2213:
>    include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
>      518 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
>          |                               ~~~~~~~~~~~ ^ ~~~
> >> fs/exportfs/expfs.c:447:10: error: incompatible integer to pointer conversion returning 'int' from a function with result type 'struct dentry *' [-Wint-conversion]
>      447 |                 return -EINVAL;
>          |                        ^~~~~~~
>    1 warning and 1 error generated.
>
>

This braino was already fixed in v4.

Sorry for the noise.

Thanks,
Amir.

> vim +447 fs/exportfs/expfs.c
>
>    434
>    435  struct dentry *
>    436  exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
>    437                         int fileid_type, unsigned int flags,
>    438                         int (*acceptable)(void *, struct dentry *),
>    439                         void *context)
>    440  {
>    441          const struct export_operations *nop = mnt->mnt_sb->s_export_op;
>    442          struct dentry *result, *alias;
>    443          char nbuf[NAME_MAX+1];
>    444          int err;
>    445
>    446          if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
>  > 447                  return -EINVAL;
>    448
>    449          /*
>    450           * Try to get any dentry for the given file handle from the filesystem.
>    451           */
>    452          if (!exportfs_can_decode_fh(nop))
>    453                  return ERR_PTR(-ESTALE);
>    454          result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
>    455          if (IS_ERR_OR_NULL(result))
>    456                  return result;
>    457
>    458          if ((flags & EXPORT_FH_DIR_ONLY) && !d_is_dir(result)) {
>    459                  err = -ENOTDIR;
>    460                  goto err_result;
>    461          }
>    462
>    463          /*
>    464           * If no acceptance criteria was specified by caller, a disconnected
>    465           * dentry is also accepatable. Callers may use this mode to query if
>    466           * file handle is stale or to get a reference to an inode without
>    467           * risking the high overhead caused by directory reconnect.
>    468           */
>    469          if (!acceptable)
>    470                  return result;
>    471
>    472          if (d_is_dir(result)) {
>    473                  /*
>    474                   * This request is for a directory.
>    475                   *
>    476                   * On the positive side there is only one dentry for each
>    477                   * directory inode.  On the negative side this implies that we
>    478                   * to ensure our dentry is connected all the way up to the
>    479                   * filesystem root.
>    480                   */
>    481                  if (result->d_flags & DCACHE_DISCONNECTED) {
>    482                          err = reconnect_path(mnt, result, nbuf);
>    483                          if (err)
>    484                                  goto err_result;
>    485                  }
>    486
>    487                  if (!acceptable(context, result)) {
>    488                          err = -EACCES;
>    489                          goto err_result;
>    490                  }
>    491
>    492                  return result;
>    493          } else {
>    494                  /*
>    495                   * It's not a directory.  Life is a little more complicated.
>    496                   */
>    497                  struct dentry *target_dir, *nresult;
>    498
>    499                  /*
>    500                   * See if either the dentry we just got from the filesystem
>    501                   * or any alias for it is acceptable.  This is always true
>    502                   * if this filesystem is exported without the subtreecheck
>    503                   * option.  If the filesystem is exported with the subtree
>    504                   * check option there's a fair chance we need to look at
>    505                   * the parent directory in the file handle and make sure
>    506                   * it's connected to the filesystem root.
>    507                   */
>    508                  alias = find_acceptable_alias(result, acceptable, context);
>    509                  if (alias)
>    510                          return alias;
>    511
>    512                  /*
>    513                   * Try to extract a dentry for the parent directory from the
>    514                   * file handle.  If this fails we'll have to give up.
>    515                   */
>    516                  err = -ESTALE;
>    517                  if (!nop->fh_to_parent)
>    518                          goto err_result;
>    519
>    520                  target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
>    521                                  fh_len, fileid_type);
>    522                  if (!target_dir)
>    523                          goto err_result;
>    524                  err = PTR_ERR(target_dir);
>    525                  if (IS_ERR(target_dir))
>    526                          goto err_result;
>    527
>    528                  /*
>    529                   * And as usual we need to make sure the parent directory is
>    530                   * connected to the filesystem root.  The VFS really doesn't
>    531                   * like disconnected directories..
>    532                   */
>    533                  err = reconnect_path(mnt, target_dir, nbuf);
>    534                  if (err) {
>    535                          dput(target_dir);
>    536                          goto err_result;
>    537                  }
>    538
>    539                  /*
>    540                   * Now that we've got both a well-connected parent and a
>    541                   * dentry for the inode we're after, make sure that our
>    542                   * inode is actually connected to the parent.
>    543                   */
>    544                  err = exportfs_get_name(mnt, target_dir, nbuf, result);
>    545                  if (err) {
>    546                          dput(target_dir);
>    547                          goto err_result;
>    548                  }
>    549
>    550                  inode_lock(target_dir->d_inode);
>    551                  nresult = lookup_one(mnt_idmap(mnt), nbuf,
>    552                                       target_dir, strlen(nbuf));
>    553                  if (!IS_ERR(nresult)) {
>    554                          if (unlikely(nresult->d_inode != result->d_inode)) {
>    555                                  dput(nresult);
>    556                                  nresult = ERR_PTR(-ESTALE);
>    557                          }
>    558                  }
>    559                  inode_unlock(target_dir->d_inode);
>    560                  /*
>    561                   * At this point we are done with the parent, but it's pinned
>    562                   * by the child dentry anyway.
>    563                   */
>    564                  dput(target_dir);
>    565
>    566                  if (IS_ERR(nresult)) {
>    567                          err = PTR_ERR(nresult);
>    568                          goto err_result;
>    569                  }
>    570                  dput(result);
>    571                  result = nresult;
>    572
>    573                  /*
>    574                   * And finally make sure the dentry is actually acceptable
>    575                   * to NFSD.
>    576                   */
>    577                  alias = find_acceptable_alias(result, acceptable, context);
>    578                  if (!alias) {
>    579                          err = -EACCES;
>    580                          goto err_result;
>    581                  }
>    582
>    583                  return alias;
>    584          }
>    585
>    586   err_result:
>    587          dput(result);
>    588          return ERR_PTR(err);
>    589  }
>    590  EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw);
>    591
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki

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

* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
  2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
  2024-10-08 18:19   ` Jeff Layton
  2024-10-11 11:03   ` kernel test robot
@ 2024-10-11 17:21   ` kernel test robot
  2 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2024-10-11 17:21 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: oe-kbuild-all

Hi Amir,

kernel test robot noticed the following build errors:

[auto build test ERROR on brauner-vfs/vfs.all]
[also build test ERROR on linus/master v6.12-rc2 next-20241011]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Amir-Goldstein/fs-prepare-for-explicit-connectable-file-handles/20241008-232246
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link:    https://lore.kernel.org/r/20241008152118.453724-2-amir73il%40gmail.com
patch subject: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
config: openrisc-allnoconfig (https://download.01.org/0day-ci/archive/20241011/202410112259.QfHlqgCD-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241011/202410112259.QfHlqgCD-lkp@intel.com/reproduce)

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>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410112259.QfHlqgCD-lkp@intel.com/

All errors (new ones prefixed by >>):

   fs/exportfs/expfs.c: In function 'exportfs_decode_fh_raw':
>> fs/exportfs/expfs.c:447:24: error: returning 'int' from a function with return type 'struct dentry *' makes pointer from integer without a cast [-Wint-conversion]
     447 |                 return -EINVAL;
         |                        ^


vim +447 fs/exportfs/expfs.c

   434	
   435	struct dentry *
   436	exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
   437			       int fileid_type, unsigned int flags,
   438			       int (*acceptable)(void *, struct dentry *),
   439			       void *context)
   440	{
   441		const struct export_operations *nop = mnt->mnt_sb->s_export_op;
   442		struct dentry *result, *alias;
   443		char nbuf[NAME_MAX+1];
   444		int err;
   445	
   446		if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
 > 447			return -EINVAL;
   448	
   449		/*
   450		 * Try to get any dentry for the given file handle from the filesystem.
   451		 */
   452		if (!exportfs_can_decode_fh(nop))
   453			return ERR_PTR(-ESTALE);
   454		result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
   455		if (IS_ERR_OR_NULL(result))
   456			return result;
   457	
   458		if ((flags & EXPORT_FH_DIR_ONLY) && !d_is_dir(result)) {
   459			err = -ENOTDIR;
   460			goto err_result;
   461		}
   462	
   463		/*
   464		 * If no acceptance criteria was specified by caller, a disconnected
   465		 * dentry is also accepatable. Callers may use this mode to query if
   466		 * file handle is stale or to get a reference to an inode without
   467		 * risking the high overhead caused by directory reconnect.
   468		 */
   469		if (!acceptable)
   470			return result;
   471	
   472		if (d_is_dir(result)) {
   473			/*
   474			 * This request is for a directory.
   475			 *
   476			 * On the positive side there is only one dentry for each
   477			 * directory inode.  On the negative side this implies that we
   478			 * to ensure our dentry is connected all the way up to the
   479			 * filesystem root.
   480			 */
   481			if (result->d_flags & DCACHE_DISCONNECTED) {
   482				err = reconnect_path(mnt, result, nbuf);
   483				if (err)
   484					goto err_result;
   485			}
   486	
   487			if (!acceptable(context, result)) {
   488				err = -EACCES;
   489				goto err_result;
   490			}
   491	
   492			return result;
   493		} else {
   494			/*
   495			 * It's not a directory.  Life is a little more complicated.
   496			 */
   497			struct dentry *target_dir, *nresult;
   498	
   499			/*
   500			 * See if either the dentry we just got from the filesystem
   501			 * or any alias for it is acceptable.  This is always true
   502			 * if this filesystem is exported without the subtreecheck
   503			 * option.  If the filesystem is exported with the subtree
   504			 * check option there's a fair chance we need to look at
   505			 * the parent directory in the file handle and make sure
   506			 * it's connected to the filesystem root.
   507			 */
   508			alias = find_acceptable_alias(result, acceptable, context);
   509			if (alias)
   510				return alias;
   511	
   512			/*
   513			 * Try to extract a dentry for the parent directory from the
   514			 * file handle.  If this fails we'll have to give up.
   515			 */
   516			err = -ESTALE;
   517			if (!nop->fh_to_parent)
   518				goto err_result;
   519	
   520			target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
   521					fh_len, fileid_type);
   522			if (!target_dir)
   523				goto err_result;
   524			err = PTR_ERR(target_dir);
   525			if (IS_ERR(target_dir))
   526				goto err_result;
   527	
   528			/*
   529			 * And as usual we need to make sure the parent directory is
   530			 * connected to the filesystem root.  The VFS really doesn't
   531			 * like disconnected directories..
   532			 */
   533			err = reconnect_path(mnt, target_dir, nbuf);
   534			if (err) {
   535				dput(target_dir);
   536				goto err_result;
   537			}
   538	
   539			/*
   540			 * Now that we've got both a well-connected parent and a
   541			 * dentry for the inode we're after, make sure that our
   542			 * inode is actually connected to the parent.
   543			 */
   544			err = exportfs_get_name(mnt, target_dir, nbuf, result);
   545			if (err) {
   546				dput(target_dir);
   547				goto err_result;
   548			}
   549	
   550			inode_lock(target_dir->d_inode);
   551			nresult = lookup_one(mnt_idmap(mnt), nbuf,
   552					     target_dir, strlen(nbuf));
   553			if (!IS_ERR(nresult)) {
   554				if (unlikely(nresult->d_inode != result->d_inode)) {
   555					dput(nresult);
   556					nresult = ERR_PTR(-ESTALE);
   557				}
   558			}
   559			inode_unlock(target_dir->d_inode);
   560			/*
   561			 * At this point we are done with the parent, but it's pinned
   562			 * by the child dentry anyway.
   563			 */
   564			dput(target_dir);
   565	
   566			if (IS_ERR(nresult)) {
   567				err = PTR_ERR(nresult);
   568				goto err_result;
   569			}
   570			dput(result);
   571			result = nresult;
   572	
   573			/*
   574			 * And finally make sure the dentry is actually acceptable
   575			 * to NFSD.
   576			 */
   577			alias = find_acceptable_alias(result, acceptable, context);
   578			if (!alias) {
   579				err = -EACCES;
   580				goto err_result;
   581			}
   582	
   583			return alias;
   584		}
   585	
   586	 err_result:
   587		dput(result);
   588		return ERR_PTR(err);
   589	}
   590	EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw);
   591	

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

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

end of thread, other threads:[~2024-10-11 17:22 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
2024-10-08 18:19   ` Jeff Layton
2024-10-08 20:31     ` Amir Goldstein
2024-10-10 11:01       ` Amir Goldstein
2024-10-11 11:03   ` kernel test robot
2024-10-11 11:29     ` Amir Goldstein
2024-10-11 17:21   ` kernel test robot
2024-10-08 15:21 ` [PATCH v3 2/3] fs: name_to_handle_at() support " Amir Goldstein
2024-10-08 18:31   ` Jeff Layton
2024-10-08 19:43     ` Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 3/3] fs: open_by_handle_at() support for decoding " Amir Goldstein
2024-10-08 18:37   ` Jeff Layton
2024-10-08 20:01     ` Amir Goldstein
2024-10-09  7:17 ` [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.