nfs: make nfs_path() work without vfsmount
part 3: now we have everything to get nfs_path() just by dentry - just follow to (disconnected) root and pick the rest of the thing there. Start killing propagation of struct vfsmount * on the paths that used to bring it to nfs_path(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									b1942c5f8c
								
							
						
					
					
						commit
						b514f872f8
					
				| @ -163,10 +163,10 @@ static inline void nfs_fs_proc_exit(void) | ||||
| 
 | ||||
| /* nfs4namespace.c */ | ||||
| #ifdef CONFIG_NFS_V4 | ||||
| extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry); | ||||
| extern struct vfsmount *nfs_do_refmount(struct super_block *sb, struct dentry *dentry); | ||||
| #else | ||||
| static inline | ||||
| struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | ||||
| struct vfsmount *nfs_do_refmount(struct super_block *sb, struct dentry *dentry) | ||||
| { | ||||
| 	return ERR_PTR(-ENOENT); | ||||
| } | ||||
| @ -247,9 +247,7 @@ extern void nfs_sb_active(struct super_block *sb); | ||||
| extern void nfs_sb_deactive(struct super_block *sb); | ||||
| 
 | ||||
| /* namespace.c */ | ||||
| extern char *nfs_path(const char *base, | ||||
| 		      const struct dentry *droot, | ||||
| 		      const struct dentry *dentry, | ||||
| extern char *nfs_path(char **p, struct dentry *dentry, | ||||
| 		      char *buffer, ssize_t buflen); | ||||
| extern struct vfsmount *nfs_d_automount(struct path *path); | ||||
| 
 | ||||
| @ -290,12 +288,11 @@ extern int _nfs4_call_sync_session(struct nfs_server *server, | ||||
| /*
 | ||||
|  * Determine the device name as a string | ||||
|  */ | ||||
| static inline char *nfs_devname(const struct vfsmount *mnt_parent, | ||||
| 				const struct dentry *dentry, | ||||
| static inline char *nfs_devname(struct dentry *dentry, | ||||
| 				char *buffer, ssize_t buflen) | ||||
| { | ||||
| 	return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root, | ||||
| 			dentry, buffer, buflen); | ||||
| 	char *dummy; | ||||
| 	return nfs_path(&dummy, dentry, buffer, buflen); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -25,33 +25,31 @@ static LIST_HEAD(nfs_automount_list); | ||||
| static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); | ||||
| int nfs_mountpoint_expiry_timeout = 500 * HZ; | ||||
| 
 | ||||
| static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, | ||||
| 					const struct dentry *dentry, | ||||
| static struct vfsmount *nfs_do_submount(struct super_block *sb, | ||||
| 					struct dentry *dentry, | ||||
| 					struct nfs_fh *fh, | ||||
| 					struct nfs_fattr *fattr); | ||||
| 
 | ||||
| /*
 | ||||
|  * nfs_path - reconstruct the path given an arbitrary dentry | ||||
|  * @base - arbitrary string to prepend to the path | ||||
|  * @droot - pointer to root dentry for mountpoint | ||||
|  * @base - used to return pointer to the end of devname part of path | ||||
|  * @dentry - pointer to dentry | ||||
|  * @buffer - result buffer | ||||
|  * @buflen - length of buffer | ||||
|  * | ||||
|  * Helper function for constructing the path from the | ||||
|  * root dentry to an arbitrary hashed dentry. | ||||
|  * Helper function for constructing the server pathname | ||||
|  * by arbitrary hashed dentry. | ||||
|  * | ||||
|  * This is mainly for use in figuring out the path on the | ||||
|  * server side when automounting on top of an existing partition. | ||||
|  * server side when automounting on top of an existing partition | ||||
|  * and in generating /proc/mounts and friends. | ||||
|  */ | ||||
| char *nfs_path(const char *base, | ||||
| 	       const struct dentry *droot, | ||||
| 	       const struct dentry *dentry, | ||||
| 	       char *buffer, ssize_t buflen) | ||||
| char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) | ||||
| { | ||||
| 	char *end; | ||||
| 	int namelen; | ||||
| 	unsigned seq; | ||||
| 	const char *base; | ||||
| 
 | ||||
| rename_retry: | ||||
| 	end = buffer+buflen; | ||||
| @ -60,7 +58,10 @@ rename_retry: | ||||
| 
 | ||||
| 	seq = read_seqbegin(&rename_lock); | ||||
| 	rcu_read_lock(); | ||||
| 	while (!IS_ROOT(dentry) && dentry != droot) { | ||||
| 	while (1) { | ||||
| 		spin_lock(&dentry->d_lock); | ||||
| 		if (IS_ROOT(dentry)) | ||||
| 			break; | ||||
| 		namelen = dentry->d_name.len; | ||||
| 		buflen -= namelen + 1; | ||||
| 		if (buflen < 0) | ||||
| @ -68,27 +69,47 @@ rename_retry: | ||||
| 		end -= namelen; | ||||
| 		memcpy(end, dentry->d_name.name, namelen); | ||||
| 		*--end = '/'; | ||||
| 		spin_unlock(&dentry->d_lock); | ||||
| 		dentry = dentry->d_parent; | ||||
| 	} | ||||
| 	rcu_read_unlock(); | ||||
| 	if (read_seqretry(&rename_lock, seq)) | ||||
| 	if (read_seqretry(&rename_lock, seq)) { | ||||
| 		spin_unlock(&dentry->d_lock); | ||||
| 		rcu_read_unlock(); | ||||
| 		goto rename_retry; | ||||
| 	} | ||||
| 	if (*end != '/') { | ||||
| 		if (--buflen < 0) | ||||
| 		if (--buflen < 0) { | ||||
| 			spin_unlock(&dentry->d_lock); | ||||
| 			rcu_read_unlock(); | ||||
| 			goto Elong; | ||||
| 		} | ||||
| 		*--end = '/'; | ||||
| 	} | ||||
| 	*p = end; | ||||
| 	base = dentry->d_fsdata; | ||||
| 	if (!base) { | ||||
| 		spin_unlock(&dentry->d_lock); | ||||
| 		rcu_read_unlock(); | ||||
| 		WARN_ON(1); | ||||
| 		return end; | ||||
| 	} | ||||
| 	namelen = strlen(base); | ||||
| 	/* Strip off excess slashes in base string */ | ||||
| 	while (namelen > 0 && base[namelen - 1] == '/') | ||||
| 		namelen--; | ||||
| 	buflen -= namelen; | ||||
| 	if (buflen < 0) | ||||
| 	if (buflen < 0) { | ||||
| 		spin_lock(&dentry->d_lock); | ||||
| 		rcu_read_unlock(); | ||||
| 		goto Elong; | ||||
| 	} | ||||
| 	end -= namelen; | ||||
| 	memcpy(end, base, namelen); | ||||
| 	spin_unlock(&dentry->d_lock); | ||||
| 	rcu_read_unlock(); | ||||
| 	return end; | ||||
| Elong_unlock: | ||||
| 	spin_lock(&dentry->d_lock); | ||||
| 	rcu_read_unlock(); | ||||
| 	if (read_seqretry(&rename_lock, seq)) | ||||
| 		goto rename_retry; | ||||
| @ -143,9 +164,9 @@ struct vfsmount *nfs_d_automount(struct path *path) | ||||
| 	} | ||||
| 
 | ||||
| 	if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | ||||
| 		mnt = nfs_do_refmount(path->mnt, path->dentry); | ||||
| 		mnt = nfs_do_refmount(path->mnt->mnt_sb, path->dentry); | ||||
| 	else | ||||
| 		mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr); | ||||
| 		mnt = nfs_do_submount(path->mnt->mnt_sb, path->dentry, fh, fattr); | ||||
| 	if (IS_ERR(mnt)) | ||||
| 		goto out; | ||||
| 
 | ||||
| @ -209,19 +230,19 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, | ||||
| 
 | ||||
| /**
 | ||||
|  * nfs_do_submount - set up mountpoint when crossing a filesystem boundary | ||||
|  * @mnt_parent - mountpoint of parent directory | ||||
|  * @sb - superblock of parent directory | ||||
|  * @dentry - parent directory | ||||
|  * @fh - filehandle for new root dentry | ||||
|  * @fattr - attributes for new root inode | ||||
|  * | ||||
|  */ | ||||
| static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, | ||||
| 					const struct dentry *dentry, | ||||
| static struct vfsmount *nfs_do_submount(struct super_block *sb, | ||||
| 					struct dentry *dentry, | ||||
| 					struct nfs_fh *fh, | ||||
| 					struct nfs_fattr *fattr) | ||||
| { | ||||
| 	struct nfs_clone_mount mountdata = { | ||||
| 		.sb = mnt_parent->mnt_sb, | ||||
| 		.sb = sb, | ||||
| 		.dentry = dentry, | ||||
| 		.fh = fh, | ||||
| 		.fattr = fattr, | ||||
| @ -237,11 +258,11 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, | ||||
| 			dentry->d_name.name); | ||||
| 	if (page == NULL) | ||||
| 		goto out; | ||||
| 	devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); | ||||
| 	devname = nfs_devname(dentry, page, PAGE_SIZE); | ||||
| 	mnt = (struct vfsmount *)devname; | ||||
| 	if (IS_ERR(devname)) | ||||
| 		goto free_page; | ||||
| 	mnt = nfs_do_clone_mount(NFS_SB(mnt_parent->mnt_sb), devname, &mountdata); | ||||
| 	mnt = nfs_do_clone_mount(NFS_SB(sb), devname, &mountdata); | ||||
| free_page: | ||||
| 	free_page((unsigned long)page); | ||||
| out: | ||||
|  | ||||
| @ -54,33 +54,29 @@ Elong: | ||||
| /*
 | ||||
|  * Determine the mount path as a string | ||||
|  */ | ||||
| static char *nfs4_path(const struct vfsmount *mnt_parent, | ||||
| 		       const struct dentry *dentry, | ||||
| 		       char *buffer, ssize_t buflen) | ||||
| static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) | ||||
| { | ||||
| 	const char *srvpath; | ||||
| 
 | ||||
| 	srvpath = strchr(mnt_parent->mnt_devname, ':'); | ||||
| 	if (srvpath) | ||||
| 		srvpath++; | ||||
| 	else | ||||
| 		srvpath = mnt_parent->mnt_devname; | ||||
| 
 | ||||
| 	return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen); | ||||
| 	char *limit; | ||||
| 	char *path = nfs_path(&limit, dentry, buffer, buflen); | ||||
| 	if (!IS_ERR(path)) { | ||||
| 		char *colon = strchr(path, ':'); | ||||
| 		if (colon && colon < limit) | ||||
| 			path = colon + 1; | ||||
| 	} | ||||
| 	return path; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we | ||||
|  * believe to be the server path to this dentry | ||||
|  */ | ||||
| static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, | ||||
| 				const struct dentry *dentry, | ||||
| static int nfs4_validate_fspath(struct dentry *dentry, | ||||
| 				const struct nfs4_fs_locations *locations, | ||||
| 				char *page, char *page2) | ||||
| { | ||||
| 	const char *path, *fs_path; | ||||
| 
 | ||||
| 	path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE); | ||||
| 	path = nfs4_path(dentry, page, PAGE_SIZE); | ||||
| 	if (IS_ERR(path)) | ||||
| 		return PTR_ERR(path); | ||||
| 
 | ||||
| @ -165,20 +161,20 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | ||||
| 
 | ||||
| /**
 | ||||
|  * nfs_follow_referral - set up mountpoint when hitting a referral on moved error | ||||
|  * @mnt_parent - mountpoint of parent directory | ||||
|  * @sb - superblock of parent directory | ||||
|  * @dentry - parent directory | ||||
|  * @locations - array of NFSv4 server location information | ||||
|  * | ||||
|  */ | ||||
| static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | ||||
| 					    const struct dentry *dentry, | ||||
| static struct vfsmount *nfs_follow_referral(struct super_block *sb, | ||||
| 					    struct dentry *dentry, | ||||
| 					    const struct nfs4_fs_locations *locations) | ||||
| { | ||||
| 	struct vfsmount *mnt = ERR_PTR(-ENOENT); | ||||
| 	struct nfs_clone_mount mountdata = { | ||||
| 		.sb = mnt_parent->mnt_sb, | ||||
| 		.sb = sb, | ||||
| 		.dentry = dentry, | ||||
| 		.authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | ||||
| 		.authflavor = NFS_SB(sb)->client->cl_auth->au_flavor, | ||||
| 	}; | ||||
| 	char *page = NULL, *page2 = NULL; | ||||
| 	int loc, error; | ||||
| @ -198,7 +194,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | ||||
| 		goto out; | ||||
| 
 | ||||
| 	/* Ensure fs path is a prefix of current dentry path */ | ||||
| 	error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2); | ||||
| 	error = nfs4_validate_fspath(dentry, locations, page, page2); | ||||
| 	if (error < 0) { | ||||
| 		mnt = ERR_PTR(error); | ||||
| 		goto out; | ||||
| @ -225,11 +221,10 @@ out: | ||||
| 
 | ||||
| /*
 | ||||
|  * nfs_do_refmount - handle crossing a referral on server | ||||
|  * @mnt_parent - mountpoint of referral | ||||
|  * @dentry - dentry of referral | ||||
|  * | ||||
|  */ | ||||
| struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | ||||
| struct vfsmount *nfs_do_refmount(struct super_block *sb, struct dentry *dentry) | ||||
| { | ||||
| 	struct vfsmount *mnt = ERR_PTR(-ENOMEM); | ||||
| 	struct dentry *parent; | ||||
| @ -262,7 +257,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr | ||||
| 	    fs_locations->fs_path.ncomponents <= 0) | ||||
| 		goto out_free; | ||||
| 
 | ||||
| 	mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations); | ||||
| 	mnt = nfs_follow_referral(sb, dentry, fs_locations); | ||||
| out_free: | ||||
| 	__free_page(page); | ||||
| 	kfree(fs_locations); | ||||
|  | ||||
| @ -2771,16 +2771,15 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||||
| 	return root_mnt; | ||||
| } | ||||
| 
 | ||||
| static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | ||||
| static void nfs_fix_devname(struct dentry *dentry, struct vfsmount *mnt) | ||||
| { | ||||
| 	char *page = (char *) __get_free_page(GFP_KERNEL); | ||||
| 	char *devname, *tmp; | ||||
| 	char *dummy; | ||||
| 
 | ||||
| 	if (page == NULL) | ||||
| 		return; | ||||
| 	devname = nfs_path(path->mnt->mnt_devname, | ||||
| 			path->mnt->mnt_root, path->dentry, | ||||
| 			page, PAGE_SIZE); | ||||
| 	devname = nfs_path(&dummy, dentry, page, PAGE_SIZE); | ||||
| 	if (IS_ERR(devname)) | ||||
| 		goto out_freepage; | ||||
| 	tmp = kstrdup(devname, GFP_KERNEL); | ||||
| @ -2894,7 +2893,7 @@ static int nfs_follow_remote_path(struct vfsmount *root_mnt, | ||||
| 	mnt_target->mnt_root = dget(nd->path.dentry); | ||||
| 
 | ||||
| 	/* Correct the device pathname */ | ||||
| 	nfs_fix_devname(&nd->path, mnt_target); | ||||
| 	nfs_fix_devname(nd->path.dentry, mnt_target); | ||||
| 
 | ||||
| 	path_put(&nd->path); | ||||
| 	kfree(nd); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user