diff options
author | Alyssa Ross <[email protected]> | 2021-05-07 22:08:16 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-07 15:08:16 -0700 |
commit | c074a7de1366656f77635da9db02cf5c09798cae (patch) | |
tree | 35977ffcebafa2037c87a506aa90cc343c929972 /module | |
parent | 4fb9e5638b31bc4b187607601d2ab824257e20d2 (diff) |
Return required size when encode_fh size too small
Quoting <linux/exportfs.h>:
> encode_fh() should return the fileid_type on success and on error
> returns 255 (if the space needed to encode fh is greater than
> @max_len*4 bytes). On error @max_len contains the minimum size (in 4
> byte unit) needed to encode the file handle.
ZFS was not setting max_len in the case where the handle was too
small. As a result of this, the `t_name_to_handle_at.c' example in
name_to_handle_at(2) did not work on ZFS.
zfsctl_fid() will itself set max_len if called with a fid that is too
small, so if we give zfs_fid() that behavior as well, the fix is quite
easy: if the handle is too small, just use a zero-size fid instead of
the handle.
Tested by running t_name_to_handle_at on a normal file, a directory, a
.zfs directory, and a snapshot.
Thanks-to: Puck Meerburg <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Tony Nguyen <[email protected]>
Signed-off-by: Alyssa Ross <[email protected]>
Closes #11995
Diffstat (limited to 'module')
-rw-r--r-- | module/os/linux/zfs/zfs_vnops_os.c | 7 | ||||
-rw-r--r-- | module/os/linux/zfs/zpl_export.c | 12 |
2 files changed, 15 insertions, 4 deletions
diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index e95d051ed..6f3faab04 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -3950,6 +3950,13 @@ zfs_fid(struct inode *ip, fid_t *fidp) int size, i, error; ZFS_ENTER(zfsvfs); + + if (fidp->fid_len < SHORT_FID_LEN) { + fidp->fid_len = SHORT_FID_LEN; + ZFS_EXIT(zfsvfs); + return (SET_ERROR(ENOSPC)); + } + ZFS_VERIFY_ZP(zp); if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zfsvfs), diff --git a/module/os/linux/zfs/zpl_export.c b/module/os/linux/zfs/zpl_export.c index eaf048c38..5be63532d 100644 --- a/module/os/linux/zfs/zpl_export.c +++ b/module/os/linux/zfs/zpl_export.c @@ -41,15 +41,19 @@ zpl_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, int connectable) struct inode *ip = dentry->d_inode; #endif /* HAVE_ENCODE_FH_WITH_INODE */ fstrans_cookie_t cookie; - fid_t *fid = (fid_t *)fh; + ushort_t empty_fid = 0; + fid_t *fid; int len_bytes, rc; len_bytes = *max_len * sizeof (__u32); - if (len_bytes < offsetof(fid_t, fid_data)) - return (255); + if (len_bytes < offsetof(fid_t, fid_data)) { + fid = (fid_t *)&empty_fid; + } else { + fid = (fid_t *)fh; + fid->fid_len = len_bytes - offsetof(fid_t, fid_data); + } - fid->fid_len = len_bytes - offsetof(fid_t, fid_data); cookie = spl_fstrans_mark(); if (zfsctl_is_node(ip)) |