2023-05-02 12:48:57

by Amir Goldstein

[permalink] [raw]
Subject: [PATCH v2 0/4] Prepare for supporting more filesystems with fanotify

Jan,

Following v2 incorporates a few fixes and ACKs from review of v1 [1].

While fanotify relaxes the requirements for filesystems to support
reporting fid to require only the ->encode_fh() operation, there are
currently no new filesystems that meet the relaxed requirements.

Patches to add ->encode_fh() to overlay with default configuation
are available on my github branch [2]. I will re-post them after
this patch set will be approved.

Based on the discussion on the UAPI alternatives, I kept the
AT_HANDLE_FID UAPI, which seems the simplest of them all.

There is an LTP test [3] that tests reporting fid from overlayfs,
which also demonstrates the use of AT_HANDLE_FID for requesting a
non-decodeable file handle by userspace and there is a man page
draft [4] for the documentation of the AT_HANDLE_FID flags.

Thanks,
Amir.

Changes since v1:
- Fixes to Kerneldoc (Chuck)
- Added ACKs (Chuck,Jeff)
- Explain the logic of requiring ->s_export_op (Jan)
- Added man page draft

[1] https://lore.kernel.org/linux-fsdevel/[email protected]/
[2] https://github.com/amir73il/linux/commits/exportfs_encode_fid
[3] https://github.com/amir73il/ltp/commits/exportfs_encode_fid
[4] https://github.com/amir73il/man-pages/commits/exportfs_encode_fid

Amir Goldstein (4):
exportfs: change connectable argument to bit flags
exportfs: add explicit flag to request non-decodeable file handles
exportfs: allow exporting non-decodeable file handles to userspace
fanotify: support reporting non-decodeable file handles

Documentation/filesystems/nfs/exporting.rst | 4 +--
fs/exportfs/expfs.c | 33 ++++++++++++++++++---
fs/fhandle.c | 22 +++++++++-----
fs/nfsd/nfsfh.c | 5 ++--
fs/notify/fanotify/fanotify.c | 4 +--
fs/notify/fanotify/fanotify_user.c | 7 ++---
fs/notify/fdinfo.c | 2 +-
include/linux/exportfs.h | 18 +++++++++--
include/uapi/linux/fcntl.h | 5 ++++
9 files changed, 74 insertions(+), 26 deletions(-)

--
2.34.1


2023-05-02 12:49:00

by Amir Goldstein

[permalink] [raw]
Subject: [PATCH v2 1/4] exportfs: change connectable argument to bit flags

Convert the bool connectable arguemnt into a bit flags argument and
define the EXPORT_FS_CONNECTABLE flag as a requested property of the
file handle.

We are going to add a flag for requesting non-decodeable file handles.

Acked-by: Jeff Layton <[email protected]>
Acked-by: Chuck Lever <[email protected]>
Signed-off-by: Amir Goldstein <[email protected]>
---
fs/exportfs/expfs.c | 13 +++++++++++--
fs/nfsd/nfsfh.c | 5 +++--
include/linux/exportfs.h | 6 ++++--
3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index ab88d33d106c..ab7feffe2d19 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -393,14 +393,23 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
}
EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);

+/**
+ * exportfs_encode_fh - encode a file handle from dentry
+ * @dentry: the object to encode
+ * @fid: where to store the file handle fragment
+ * @max_len: maximum length to store there
+ * @flags: properties of the requested file handle
+ *
+ * Returns an enum fid_type or a negative errno.
+ */
int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
- int connectable)
+ int flags)
{
int error;
struct dentry *p = NULL;
struct inode *inode = dentry->d_inode, *parent = NULL;

- if (connectable && !S_ISDIR(inode->i_mode)) {
+ if ((flags & EXPORT_FH_CONNECTABLE) && !S_ISDIR(inode->i_mode)) {
p = dget_parent(dentry);
/*
* note that while p might've ceased to be our parent already,
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index ccd8485fee04..31e4505c0df3 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -414,10 +414,11 @@ static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
struct fid *fid = (struct fid *)
(fhp->fh_handle.fh_fsid + fhp->fh_handle.fh_size/4 - 1);
int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
- int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
+ int fh_flags = (exp->ex_flags & NFSEXP_NOSUBTREECHECK) ? 0 :
+ EXPORT_FH_CONNECTABLE;

fhp->fh_handle.fh_fileid_type =
- exportfs_encode_fh(dentry, fid, &maxsize, subtreecheck);
+ exportfs_encode_fh(dentry, fid, &maxsize, fh_flags);
fhp->fh_handle.fh_size += maxsize * 4;
} else {
fhp->fh_handle.fh_fileid_type = FILEID_ROOT;
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 601700fedc91..66e16022cc3d 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -135,6 +135,8 @@ struct fid {
};
};

+#define EXPORT_FH_CONNECTABLE 0x1 /* Encode file handle with parent */
+
/**
* struct export_operations - for nfsd to communicate with file systems
* @encode_fh: encode a file handle fragment from a dentry
@@ -150,7 +152,7 @@ struct fid {
* encode_fh:
* @encode_fh should store in the file handle fragment @fh (using at most
* @max_len bytes) information that can be used by @decode_fh to recover the
- * file referred to by the &struct dentry @de. If the @connectable flag is
+ * file referred to by the &struct dentry @de. If @flag has CONNECTABLE bit
* set, the encode_fh() should store sufficient information so that a good
* attempt can be made to find not only the file but also it's place in the
* filesystem. This typically means storing a reference to de->d_parent in
@@ -226,7 +228,7 @@ struct export_operations {
extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
int *max_len, struct inode *parent);
extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
- int *max_len, int connectable);
+ int *max_len, int flags);
extern struct dentry *exportfs_decode_fh_raw(struct vfsmount *mnt,
struct fid *fid, int fh_len,
int fileid_type,
--
2.34.1

2023-05-02 12:49:41

by Amir Goldstein

[permalink] [raw]
Subject: [PATCH v2 2/4] exportfs: add explicit flag to request non-decodeable file handles

So far, all callers of exportfs_encode_inode_fh(), except for fsnotify's
show_mark_fhandle(), check that filesystem can decode file handles, but
we would like to add more callers that do not require a file handle that
can be decoded.

Introduce a flag to explicitly request a file handle that may not to be
decoded later and a wrapper exportfs_encode_fid() that sets this flag
and convert show_mark_fhandle() to use the new wrapper.

This will be used to allow adding fanotify support to filesystems that
do not support NFS export.

Acked-by: Jeff Layton <[email protected]>
Acked-by: Chuck Lever <[email protected]>
Signed-off-by: Amir Goldstein <[email protected]>
---
Documentation/filesystems/nfs/exporting.rst | 4 ++--
fs/exportfs/expfs.c | 20 ++++++++++++++++++--
fs/notify/fanotify/fanotify.c | 4 ++--
fs/notify/fdinfo.c | 2 +-
include/linux/exportfs.h | 12 +++++++++++-
5 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst
index 0e98edd353b5..3d97b8d8f735 100644
--- a/Documentation/filesystems/nfs/exporting.rst
+++ b/Documentation/filesystems/nfs/exporting.rst
@@ -122,8 +122,8 @@ are exportable by setting the s_export_op field in the struct
super_block. This field must point to a "struct export_operations"
struct which has the following members:

- encode_fh (optional)
- Takes a dentry and creates a filehandle fragment which can later be used
+ encode_fh (optional)
+ Takes a dentry and creates a filehandle fragment which may later be used
to find or create a dentry for the same object. The default
implementation creates a filehandle fragment that encodes a 32bit inode
and generation number for the inode encoded, and if necessary the
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index ab7feffe2d19..40e624cf7e92 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -381,11 +381,27 @@ static int export_encode_fh(struct inode *inode, struct fid *fid,
return type;
}

+/**
+ * exportfs_encode_inode_fh - encode a file handle from inode
+ * @inode: the object to encode
+ * @fid: where to store the file handle fragment
+ * @max_len: maximum length to store there
+ * @flags: properties of the requested file handle
+ *
+ * Returns an enum fid_type or a negative errno.
+ */
int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
- int *max_len, struct inode *parent)
+ int *max_len, struct inode *parent, int flags)
{
const struct export_operations *nop = inode->i_sb->s_export_op;

+ /*
+ * If a decodeable file handle was requested, we need to make sure that
+ * filesystem can decode file handles.
+ */
+ if (nop && !(flags & EXPORT_FH_FID) && !nop->fh_to_dentry)
+ return -EOPNOTSUPP;
+
if (nop && nop->encode_fh)
return nop->encode_fh(inode, fid->raw, max_len, parent);

@@ -418,7 +434,7 @@ int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
parent = p->d_inode;
}

- error = exportfs_encode_inode_fh(inode, fid, max_len, parent);
+ error = exportfs_encode_inode_fh(inode, fid, max_len, parent, flags);
dput(p);

return error;
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 29bdd99b29fa..d1a49f5b6e6d 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -380,7 +380,7 @@ static int fanotify_encode_fh_len(struct inode *inode)
if (!inode)
return 0;

- exportfs_encode_inode_fh(inode, NULL, &dwords, NULL);
+ exportfs_encode_inode_fh(inode, NULL, &dwords, NULL, 0);
fh_len = dwords << 2;

/*
@@ -443,7 +443,7 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
}

dwords = fh_len >> 2;
- type = exportfs_encode_inode_fh(inode, buf, &dwords, NULL);
+ type = exportfs_encode_inode_fh(inode, buf, &dwords, NULL, 0);
err = -EINVAL;
if (!type || type == FILEID_INVALID || fh_len != dwords << 2)
goto out_err;
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c
index 55081ae3a6ec..5c430736ec12 100644
--- a/fs/notify/fdinfo.c
+++ b/fs/notify/fdinfo.c
@@ -50,7 +50,7 @@ static void show_mark_fhandle(struct seq_file *m, struct inode *inode)
f.handle.handle_bytes = sizeof(f.pad);
size = f.handle.handle_bytes >> 2;

- ret = exportfs_encode_inode_fh(inode, (struct fid *)f.handle.f_handle, &size, NULL);
+ ret = exportfs_encode_fid(inode, (struct fid *)f.handle.f_handle, &size);
if ((ret == FILEID_INVALID) || (ret < 0)) {
WARN_ONCE(1, "Can't encode file handler for inotify: %d\n", ret);
return;
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 66e16022cc3d..ec86ea4fa5c1 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -136,6 +136,7 @@ struct fid {
};

#define EXPORT_FH_CONNECTABLE 0x1 /* Encode file handle with parent */
+#define EXPORT_FH_FID 0x2 /* File handle may be non-decodeable */

/**
* struct export_operations - for nfsd to communicate with file systems
@@ -226,9 +227,18 @@ struct export_operations {
};

extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
- int *max_len, struct inode *parent);
+ int *max_len, struct inode *parent,
+ int flags);
extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
int *max_len, int flags);
+
+static inline int exportfs_encode_fid(struct inode *inode, struct fid *fid,
+ int *max_len)
+{
+ return exportfs_encode_inode_fh(inode, fid, max_len, NULL,
+ EXPORT_FH_FID);
+}
+
extern struct dentry *exportfs_decode_fh_raw(struct vfsmount *mnt,
struct fid *fid, int fh_len,
int fileid_type,
--
2.34.1

2023-05-02 12:49:54

by Amir Goldstein

[permalink] [raw]
Subject: [PATCH v2 4/4] fanotify: support reporting non-decodeable file handles

fanotify users do not always need to decode the file handles reported
with FAN_REPORT_FID.

Relax the restriction that filesystem needs to support NFS export and
allow reporting file handles from filesystems that only support ecoding
unique file handles.

Even filesystems that do not have export_operations at all can fallback
to use the default FILEID_INO32_GEN encoding, but we use the existence
of export_operations as an indication that the encoded file handles will
be sufficiently unique and that user will be able to compare them to
filesystem objects using AT_HANDLE_FID flag to name_to_handle_at(2).

For filesystems that do not support NFS export, users will have to use
the AT_HANDLE_FID of name_to_handle_at(2) if they want to compare the
object in path to the object fid reported in an event.

Signed-off-by: Amir Goldstein <[email protected]>
---
fs/notify/fanotify/fanotify.c | 4 ++--
fs/notify/fanotify/fanotify_user.c | 7 +++----
2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index d1a49f5b6e6d..d2bbf1445a9e 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -380,7 +380,7 @@ static int fanotify_encode_fh_len(struct inode *inode)
if (!inode)
return 0;

- exportfs_encode_inode_fh(inode, NULL, &dwords, NULL, 0);
+ exportfs_encode_fid(inode, NULL, &dwords);
fh_len = dwords << 2;

/*
@@ -443,7 +443,7 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
}

dwords = fh_len >> 2;
- type = exportfs_encode_inode_fh(inode, buf, &dwords, NULL, 0);
+ type = exportfs_encode_fid(inode, buf, &dwords);
err = -EINVAL;
if (!type || type == FILEID_INVALID || fh_len != dwords << 2)
goto out_err;
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 8f430bfad487..e1936e968abb 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -1586,11 +1586,10 @@ static int fanotify_test_fid(struct dentry *dentry)
* We need to make sure that the file system supports at least
* encoding a file handle so user can use name_to_handle_at() to
* compare fid returned with event to the file handle of watched
- * objects. However, name_to_handle_at() requires that the
- * filesystem also supports decoding file handles.
+ * objects. However, even the relaxed AT_HANDLE_FID flag requires
+ * at least empty export_operations for ecoding unique file ids.
*/
- if (!dentry->d_sb->s_export_op ||
- !dentry->d_sb->s_export_op->fh_to_dentry)
+ if (!dentry->d_sb->s_export_op)
return -EOPNOTSUPP;

return 0;
--
2.34.1

2023-05-02 12:50:00

by Amir Goldstein

[permalink] [raw]
Subject: [PATCH v2 3/4] exportfs: allow exporting non-decodeable file handles to userspace

Some userspace programs use st_ino as a unique object identifier, even
though inode numbers may be recycable.

This issue has been addressed for NFS export long ago using the exportfs
file handle API and the unique file handle identifiers are also exported
to userspace via name_to_handle_at(2).

fanotify also uses file handles to identify objects in events, but only
for filesystems that support NFS export.

Relax the requirement for NFS export support and allow more filesystems
to export a unique object identifier via name_to_handle_at(2) with the
flag AT_HANDLE_FID.

A file handle requested with the AT_HANDLE_FID flag, may or may not be
usable as an argument to open_by_handle_at(2).

To allow filesystems to opt-in to supporting AT_HANDLE_FID, a struct
export_operations is required, but even an empty struct is sufficient
for encoding FIDs.

Acked-by: Jeff Layton <[email protected]>
Acked-by: Chuck Lever <[email protected]>
Signed-off-by: Amir Goldstein <[email protected]>
---
fs/fhandle.c | 22 ++++++++++++++--------
include/uapi/linux/fcntl.h | 5 +++++
2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/fs/fhandle.c b/fs/fhandle.c
index f2bc27d1975e..4a635cf787fc 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -16,7 +16,7 @@

static long do_sys_name_to_handle(const struct path *path,
struct file_handle __user *ufh,
- int __user *mnt_id)
+ int __user *mnt_id, int fh_flags)
{
long retval;
struct file_handle f_handle;
@@ -24,11 +24,14 @@ static long do_sys_name_to_handle(const struct path *path,
struct file_handle *handle = NULL;

/*
- * We need to make sure whether the file system
- * support decoding of the file handle
+ * We need to make sure whether the file system support decoding of
+ * the file handle if decodeable file handle was requested.
+ * Otherwise, even empty export_operations are sufficient to opt-in
+ * to encoding FIDs.
*/
if (!path->dentry->d_sb->s_export_op ||
- !path->dentry->d_sb->s_export_op->fh_to_dentry)
+ (!(fh_flags & EXPORT_FH_FID) &&
+ !path->dentry->d_sb->s_export_op->fh_to_dentry))
return -EOPNOTSUPP;

if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
@@ -45,10 +48,10 @@ 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 connected handle */
+ /* we ask for a non connectable maybe decodeable file handle */
retval = exportfs_encode_fh(path->dentry,
(struct fid *)handle->f_handle,
- &handle_dwords, 0);
+ &handle_dwords, fh_flags);
handle->handle_type = retval;
/* convert handle size to bytes */
handle_bytes = handle_dwords * sizeof(u32);
@@ -84,6 +87,7 @@ static long do_sys_name_to_handle(const struct path *path,
* @handle: resulting file handle
* @mnt_id: mount id of the file system containing the file
* @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
@@ -96,17 +100,19 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
{
struct path path;
int lookup_flags;
+ int fh_flags;
int err;

- if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
+ if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID))
return -EINVAL;

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);
if (!err) {
- err = do_sys_name_to_handle(&path, handle, mnt_id);
+ err = do_sys_name_to_handle(&path, handle, mnt_id, fh_flags);
path_put(&path);
}
return err;
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index e8c07da58c9f..3091080db069 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -112,4 +112,9 @@

#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */

+/* Flags for name_to_handle_at(2) */
+#define AT_HANDLE_FID 0x10000 /* file handle is needed to compare
+ object indentity and may not be
+ usable to open_by_handle_at(2) */
+
#endif /* _UAPI_LINUX_FCNTL_H */
--
2.34.1

2023-05-03 17:32:12

by Jan Kara

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] exportfs: allow exporting non-decodeable file handles to userspace

On Tue 02-05-23 15:48:16, Amir Goldstein wrote:
> Some userspace programs use st_ino as a unique object identifier, even
> though inode numbers may be recycable.
>
> This issue has been addressed for NFS export long ago using the exportfs
> file handle API and the unique file handle identifiers are also exported
> to userspace via name_to_handle_at(2).
>
> fanotify also uses file handles to identify objects in events, but only
> for filesystems that support NFS export.
>
> Relax the requirement for NFS export support and allow more filesystems
> to export a unique object identifier via name_to_handle_at(2) with the
> flag AT_HANDLE_FID.
>
> A file handle requested with the AT_HANDLE_FID flag, may or may not be
> usable as an argument to open_by_handle_at(2).
>
> To allow filesystems to opt-in to supporting AT_HANDLE_FID, a struct
> export_operations is required, but even an empty struct is sufficient
> for encoding FIDs.

Christian (or Al), are you OK with sparing one AT_ flag for this
functionality? Otherwise the patch series looks fine to me so I'd like to
queue it into my tree. Thanks!

Honza

>
> Acked-by: Jeff Layton <[email protected]>
> Acked-by: Chuck Lever <[email protected]>
> Signed-off-by: Amir Goldstein <[email protected]>
> ---
> fs/fhandle.c | 22 ++++++++++++++--------
> include/uapi/linux/fcntl.h | 5 +++++
> 2 files changed, 19 insertions(+), 8 deletions(-)
>
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index f2bc27d1975e..4a635cf787fc 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -16,7 +16,7 @@
>
> static long do_sys_name_to_handle(const struct path *path,
> struct file_handle __user *ufh,
> - int __user *mnt_id)
> + int __user *mnt_id, int fh_flags)
> {
> long retval;
> struct file_handle f_handle;
> @@ -24,11 +24,14 @@ static long do_sys_name_to_handle(const struct path *path,
> struct file_handle *handle = NULL;
>
> /*
> - * We need to make sure whether the file system
> - * support decoding of the file handle
> + * We need to make sure whether the file system support decoding of
> + * the file handle if decodeable file handle was requested.
> + * Otherwise, even empty export_operations are sufficient to opt-in
> + * to encoding FIDs.
> */
> if (!path->dentry->d_sb->s_export_op ||
> - !path->dentry->d_sb->s_export_op->fh_to_dentry)
> + (!(fh_flags & EXPORT_FH_FID) &&
> + !path->dentry->d_sb->s_export_op->fh_to_dentry))
> return -EOPNOTSUPP;
>
> if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
> @@ -45,10 +48,10 @@ 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 connected handle */
> + /* we ask for a non connectable maybe decodeable file handle */
> retval = exportfs_encode_fh(path->dentry,
> (struct fid *)handle->f_handle,
> - &handle_dwords, 0);
> + &handle_dwords, fh_flags);
> handle->handle_type = retval;
> /* convert handle size to bytes */
> handle_bytes = handle_dwords * sizeof(u32);
> @@ -84,6 +87,7 @@ static long do_sys_name_to_handle(const struct path *path,
> * @handle: resulting file handle
> * @mnt_id: mount id of the file system containing the file
> * @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
> @@ -96,17 +100,19 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
> {
> struct path path;
> int lookup_flags;
> + int fh_flags;
> int err;
>
> - if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
> + if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID))
> return -EINVAL;
>
> 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);
> if (!err) {
> - err = do_sys_name_to_handle(&path, handle, mnt_id);
> + err = do_sys_name_to_handle(&path, handle, mnt_id, fh_flags);
> path_put(&path);
> }
> return err;
> diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
> index e8c07da58c9f..3091080db069 100644
> --- a/include/uapi/linux/fcntl.h
> +++ b/include/uapi/linux/fcntl.h
> @@ -112,4 +112,9 @@
>
> #define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */
>
> +/* Flags for name_to_handle_at(2) */
> +#define AT_HANDLE_FID 0x10000 /* file handle is needed to compare
> + object indentity and may not be
> + usable to open_by_handle_at(2) */
> +
> #endif /* _UAPI_LINUX_FCNTL_H */
> --
> 2.34.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR

2023-05-04 11:25:10

by Christian Brauner

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] exportfs: allow exporting non-decodeable file handles to userspace

On Wed, May 03, 2023 at 07:23:14PM +0200, Jan Kara wrote:
> On Tue 02-05-23 15:48:16, Amir Goldstein wrote:
> > Some userspace programs use st_ino as a unique object identifier, even
> > though inode numbers may be recycable.
> >
> > This issue has been addressed for NFS export long ago using the exportfs
> > file handle API and the unique file handle identifiers are also exported
> > to userspace via name_to_handle_at(2).
> >
> > fanotify also uses file handles to identify objects in events, but only
> > for filesystems that support NFS export.
> >
> > Relax the requirement for NFS export support and allow more filesystems
> > to export a unique object identifier via name_to_handle_at(2) with the
> > flag AT_HANDLE_FID.
> >
> > A file handle requested with the AT_HANDLE_FID flag, may or may not be
> > usable as an argument to open_by_handle_at(2).
> >
> > To allow filesystems to opt-in to supporting AT_HANDLE_FID, a struct
> > export_operations is required, but even an empty struct is sufficient
> > for encoding FIDs.
>
> Christian (or Al), are you OK with sparing one AT_ flag for this
> functionality? Otherwise the patch series looks fine to me so I'd like to
> queue it into my tree. Thanks!

At first it looked like there are reasons to complain about this on the
grounds that this seems like a flag only for a single system call. But
another look at include/uapi/linux/fcntl.h reveals that oh well, the
AT_* flag namespace already contains system call specific flags.

The overloading of AT_EACCESS and AT_REMOVEDIR as 0x200 is especially
creative since it doesn't even use an infix like the statx specific
flags.

Long story short, since there's already overloading of the flag
namespace happening it wouldn't be unprecedent or in any way wrong if
this patch just reused the 0x200 value as well.

In fact, it might come in handy since it would mean that we have the bit
you're using right now free for a flag that is meaningful for multiple
system calls. So something to consider but you can just change that
in-tree as far as I'm concerned.

All this amounts to a long-winded,

Acked-by: Christian Brauner <[email protected]>

2023-05-04 11:45:50

by Amir Goldstein

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] exportfs: allow exporting non-decodeable file handles to userspace

On Thu, May 4, 2023 at 2:19 PM Christian Brauner <[email protected]> wrote:
>
> On Wed, May 03, 2023 at 07:23:14PM +0200, Jan Kara wrote:
> > On Tue 02-05-23 15:48:16, Amir Goldstein wrote:
> > > Some userspace programs use st_ino as a unique object identifier, even
> > > though inode numbers may be recycable.
> > >
> > > This issue has been addressed for NFS export long ago using the exportfs
> > > file handle API and the unique file handle identifiers are also exported
> > > to userspace via name_to_handle_at(2).
> > >
> > > fanotify also uses file handles to identify objects in events, but only
> > > for filesystems that support NFS export.
> > >
> > > Relax the requirement for NFS export support and allow more filesystems
> > > to export a unique object identifier via name_to_handle_at(2) with the
> > > flag AT_HANDLE_FID.
> > >
> > > A file handle requested with the AT_HANDLE_FID flag, may or may not be
> > > usable as an argument to open_by_handle_at(2).
> > >
> > > To allow filesystems to opt-in to supporting AT_HANDLE_FID, a struct
> > > export_operations is required, but even an empty struct is sufficient
> > > for encoding FIDs.
> >
> > Christian (or Al), are you OK with sparing one AT_ flag for this
> > functionality? Otherwise the patch series looks fine to me so I'd like to
> > queue it into my tree. Thanks!
>
> At first it looked like there are reasons to complain about this on the
> grounds that this seems like a flag only for a single system call. But
> another look at include/uapi/linux/fcntl.h reveals that oh well, the
> AT_* flag namespace already contains system call specific flags.
>
> The overloading of AT_EACCESS and AT_REMOVEDIR as 0x200 is especially
> creative since it doesn't even use an infix like the statx specific
> flags.
>
> Long story short, since there's already overloading of the flag
> namespace happening it wouldn't be unprecedent or in any way wrong if
> this patch just reused the 0x200 value as well.
>

I had considered this myself as well...
Couldn't decide if this was ugly or not.
Obviously, I do not mind which value the flag gets.

> In fact, it might come in handy since it would mean that we have the bit
> you're using right now free for a flag that is meaningful for multiple
> system calls. So something to consider but you can just change that
> in-tree as far as I'm concerned.
>
> All this amounts to a long-winded,
>
> Acked-by: Christian Brauner <[email protected]>

Thanks,
Amir.