From f15ec889a9b57596a67c120bec60fcbe598c3ae7 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Fri, 7 May 2021 22:08:16 +0000 Subject: [PATCH] Return required size when encode_fh size too small Quoting : > 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 Reviewed-by: Brian Behlendorf Reviewed-by: Tony Nguyen Signed-off-by: Alyssa Ross Closes #11995 --- module/os/linux/zfs/zfs_vnops_os.c | 7 +++++++ 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 e95d051ed0..6f3faab04f 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 eaf048c38d..5be63532d3 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))