mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	add get_name implementation for exports. (#16833)
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
20232ecfaa 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>
			
			
This commit is contained in:
		
							parent
							
								
									299da6ace3
								
							
						
					
					
						commit
						0bd8481aa7
					
				| @ -44,6 +44,7 @@ extern int zfs_write_simple(znode_t *zp, const void *data, size_t len, | |||||||
|     loff_t pos, size_t *resid); |     loff_t pos, size_t *resid); | ||||||
| extern int zfs_lookup(znode_t *dzp, char *nm, znode_t **zpp, int flags, | extern int zfs_lookup(znode_t *dzp, char *nm, znode_t **zpp, int flags, | ||||||
|     cred_t *cr, int *direntflags, pathname_t *realpnp); |     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, | 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, |     int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp, | ||||||
|     zidmap_t *mnt_ns); |     zidmap_t *mnt_ns); | ||||||
|  | |||||||
| @ -526,6 +526,48 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr, | |||||||
| 	return (error); | 	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 |  * Attempt to create a new entry in a directory.  If the entry | ||||||
|  * already exists, truncate the file if permissible, else return |  * already exists, truncate the file if permissible, else return | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #include <sys/file.h> | ||||||
| #include <sys/zfs_znode.h> | #include <sys/zfs_znode.h> | ||||||
| #include <sys/zfs_vnops.h> | #include <sys/zfs_vnops.h> | ||||||
| #include <sys/zfs_ctldir.h> | #include <sys/zfs_ctldir.h> | ||||||
| @ -102,6 +103,36 @@ zpl_fh_to_dentry(struct super_block *sb, struct fid *fh, | |||||||
| 	return (d_obtain_alias(ip)); | 	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 * | static struct dentry * | ||||||
| zpl_get_parent(struct dentry *child) | zpl_get_parent(struct dentry *child) | ||||||
| { | { | ||||||
| @ -146,6 +177,7 @@ zpl_commit_metadata(struct inode *inode) | |||||||
| const struct export_operations zpl_export_operations = { | const struct export_operations zpl_export_operations = { | ||||||
| 	.encode_fh		= zpl_encode_fh, | 	.encode_fh		= zpl_encode_fh, | ||||||
| 	.fh_to_dentry		= zpl_fh_to_dentry, | 	.fh_to_dentry		= zpl_fh_to_dentry, | ||||||
|  | 	.get_name		= zpl_get_name, | ||||||
| 	.get_parent		= zpl_get_parent, | 	.get_parent		= zpl_get_parent, | ||||||
| 	.commit_metadata	= zpl_commit_metadata, | 	.commit_metadata	= zpl_commit_metadata, | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Charles Hedrick
						Charles Hedrick