Skip to content

Commit

Permalink
add get_name implementation for exports. (openzfs#16833)
Browse files Browse the repository at this point in the history
This fixes a serious performance problem with NFS handling of large
directories, as the new get_name code is much more efficient than the
default zfs_readdir. This is actually part of
20232ec in 2.3. But I've taken only
the minimum code to implement get_name, and not the rest of the long
name changes.

Signed-off-by: Charles Hedrick <hedrick@rutgers.edu>
Co-authored-by: Charles L. Hedrick <hedrick@ncommunis.cs.rutgers.edu>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
  • Loading branch information
2 people authored and anodos325 committed Dec 6, 2024
1 parent 51254f1 commit a4c1411
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/os/linux/zfs/sys/zfs_vnops_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extern int zfs_write_simple(znode_t *zp, const void *data, size_t len,
loff_t pos, size_t *resid);
extern int zfs_lookup(znode_t *dzp, char *nm, znode_t **zpp, int flags,
cred_t *cr, int *direntflags, pathname_t *realpnp);
extern int zfs_get_name(znode_t *dzp, char *name, znode_t *zp);
extern int zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl,
int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp,
zidmap_t *mnt_ns);
Expand Down
42 changes: 42 additions & 0 deletions module/os/linux/zfs/zfs_vnops_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,48 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr,
return (error);
}

/*
* Perform a linear search in directory for the name of specific inode.
* Note we don't pass in the buffer size of name because it's hardcoded to
* NAME_MAX+1(256) in Linux.
*
* IN: dzp - znode of directory to search.
* zp - znode of the target
*
* OUT: name - dentry name of the target
*
* RETURN: 0 on success, error code on failure.
*/
int
zfs_get_name(znode_t *dzp, char *name, znode_t *zp)
{
zfsvfs_t *zfsvfs = ZTOZSB(dzp);
int error = 0;

if ((error = zfs_enter_verify_zp(zfsvfs, dzp, FTAG)) != 0)
return (error);

if ((error = zfs_verify_zp(zp)) != 0) {
zfs_exit(zfsvfs, FTAG);
return (error);
}

/* ctldir should have got their name in zfs_vget */
if (dzp->z_is_ctldir || zp->z_is_ctldir) {
zfs_exit(zfsvfs, FTAG);
return (ENOENT);
}

/* buffer len is hardcoded to 256 in Linux kernel */
error = zap_value_search(zfsvfs->z_os, dzp->z_id, zp->z_id,
ZFS_DIRENT_OBJ(-1ULL), name);

zfs_exit(zfsvfs, FTAG);
return (error);
}



/*
* Attempt to create a new entry in a directory. If the entry
* already exists, truncate the file if permissible, else return
Expand Down
32 changes: 32 additions & 0 deletions module/os/linux/zfs/zpl_export.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/


#include <sys/file.h>
#include <sys/zfs_znode.h>
#include <sys/zfs_vnops.h>
#include <sys/zfs_ctldir.h>
Expand Down Expand Up @@ -109,6 +110,36 @@ zpl_fh_to_dentry(struct super_block *sb, struct fid *fh,
return (d_obtain_alias(ip));
}

/*
* In case the filesystem contains name longer than 255, we need to override
* the default get_name so we don't get buffer overflow. Unfortunately, since
* the buffer size is hardcoded in Linux, we will get ESTALE error in this
* case.
*/
static int
zpl_get_name(struct dentry *parent, char *name, struct dentry *child)
{
cred_t *cr = CRED();
fstrans_cookie_t cookie;
struct inode *dir = parent->d_inode;
struct inode *ip = child->d_inode;
int error;

if (!dir || !S_ISDIR(dir->i_mode))
return (-ENOTDIR);

crhold(cr);
cookie = spl_fstrans_mark();
spl_inode_lock_shared(dir);
error = -zfs_get_name(ITOZ(dir), name, ITOZ(ip));
spl_inode_unlock_shared(dir);
spl_fstrans_unmark(cookie);
crfree(cr);

return (error);
}


static struct dentry *
zpl_get_parent(struct dentry *child)
{
Expand Down Expand Up @@ -153,6 +184,7 @@ zpl_commit_metadata(struct inode *inode)
const struct export_operations zpl_export_operations = {
.encode_fh = zpl_encode_fh,
.fh_to_dentry = zpl_fh_to_dentry,
.get_name = zpl_get_name,
.get_parent = zpl_get_parent,
.commit_metadata = zpl_commit_metadata,
};

0 comments on commit a4c1411

Please sign in to comment.