diff options
Diffstat (limited to 'fs/nfs/getroot.c')
| -rw-r--r-- | fs/nfs/getroot.c | 152 | 
1 files changed, 24 insertions, 128 deletions
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index ac7b814ce16..b94f80420a5 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -23,20 +23,15 @@  #include <linux/sunrpc/stats.h>  #include <linux/nfs_fs.h>  #include <linux/nfs_mount.h> -#include <linux/nfs4_mount.h>  #include <linux/lockd/bind.h>  #include <linux/seq_file.h>  #include <linux/mount.h> -#include <linux/nfs_idmap.h>  #include <linux/vfs.h>  #include <linux/namei.h>  #include <linux/security.h> -#include <asm/system.h>  #include <asm/uaccess.h> -#include "nfs4_fs.h" -#include "delegation.h"  #include "internal.h"  #define NFSDBG_FACILITY		NFSDBG_CLIENT @@ -49,11 +44,9 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i  {  	/* The mntroot acts as the dummy root dentry for this superblock */  	if (sb->s_root == NULL) { -		sb->s_root = d_alloc_root(inode); -		if (sb->s_root == NULL) { -			iput(inode); +		sb->s_root = d_make_root(inode); +		if (sb->s_root == NULL)  			return -ENOMEM; -		}  		ihold(inode);  		/*  		 * Ensure that this dentry is invisible to d_find_alias(). @@ -63,9 +56,11 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i  		 * This again causes shrink_dcache_for_umount_subtree() to  		 * Oops, since the test for IS_ROOT() will fail.  		 */ -		spin_lock(&dcache_lock); -		list_del_init(&sb->s_root->d_alias); -		spin_unlock(&dcache_lock); +		spin_lock(&sb->s_root->d_inode->i_lock); +		spin_lock(&sb->s_root->d_lock); +		hlist_del_init(&sb->s_root->d_alias); +		spin_unlock(&sb->s_root->d_lock); +		spin_unlock(&sb->s_root->d_inode->i_lock);  	}  	return 0;  } @@ -73,18 +68,25 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i  /*   * get an NFS2/NFS3 root dentry from the root filehandle   */ -struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) +struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, +			    const char *devname)  {  	struct nfs_server *server = NFS_SB(sb);  	struct nfs_fsinfo fsinfo;  	struct dentry *ret;  	struct inode *inode; +	void *name = kstrdup(devname, GFP_KERNEL);  	int error; +	if (!name) +		return ERR_PTR(-ENOMEM); +  	/* get the actual root for this mount */  	fsinfo.fattr = nfs_alloc_fattr(); -	if (fsinfo.fattr == NULL) +	if (fsinfo.fattr == NULL) { +		kfree(name);  		return ERR_PTR(-ENOMEM); +	}  	error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);  	if (error < 0) { @@ -93,7 +95,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)  		goto out;  	} -	inode = nfs_fhget(sb, mntfh, fsinfo.fattr); +	inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);  	if (IS_ERR(inode)) {  		dprintk("nfs_get_root: get root inode failed\n");  		ret = ERR_CAST(inode); @@ -117,121 +119,15 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)  	}  	security_d_instantiate(ret, inode); - -	if (ret->d_op == NULL) -		ret->d_op = server->nfs_client->rpc_ops->dentry_ops; -out: -	nfs_free_fattr(fsinfo.fattr); -	return ret; -} - -#ifdef CONFIG_NFS_V4 - -int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) -{ -	struct nfs_fsinfo fsinfo; -	int ret = -ENOMEM; - -	dprintk("--> nfs4_get_rootfh()\n"); - -	fsinfo.fattr = nfs_alloc_fattr(); -	if (fsinfo.fattr == NULL) -		goto out; - -	/* Start by getting the root filehandle from the server */ -	ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); -	if (ret < 0) { -		dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret); -		goto out; -	} - -	if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE) -			|| !S_ISDIR(fsinfo.fattr->mode)) { -		printk(KERN_ERR "nfs4_get_rootfh:" -		       " getroot encountered non-directory\n"); -		ret = -ENOTDIR; -		goto out; -	} - -	if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { -		printk(KERN_ERR "nfs4_get_rootfh:" -		       " getroot obtained referral\n"); -		ret = -EREMOTE; -		goto out; +	spin_lock(&ret->d_lock); +	if (IS_ROOT(ret) && !ret->d_fsdata && +	    !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { +		ret->d_fsdata = name; +		name = NULL;  	} - -	memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid)); +	spin_unlock(&ret->d_lock);  out: +	kfree(name);  	nfs_free_fattr(fsinfo.fattr); -	dprintk("<-- nfs4_get_rootfh() = %d\n", ret);  	return ret;  } - -/* - * get an NFS4 root dentry from the root filehandle - */ -struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) -{ -	struct nfs_server *server = NFS_SB(sb); -	struct nfs_fattr *fattr = NULL; -	struct dentry *ret; -	struct inode *inode; -	int error; - -	dprintk("--> nfs4_get_root()\n"); - -	/* get the info about the server and filesystem */ -	error = nfs4_server_capabilities(server, mntfh); -	if (error < 0) { -		dprintk("nfs_get_root: getcaps error = %d\n", -			-error); -		return ERR_PTR(error); -	} - -	fattr = nfs_alloc_fattr(); -	if (fattr == NULL) -		return ERR_PTR(-ENOMEM);; - -	/* get the actual root for this mount */ -	error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); -	if (error < 0) { -		dprintk("nfs_get_root: getattr error = %d\n", -error); -		ret = ERR_PTR(error); -		goto out; -	} - -	inode = nfs_fhget(sb, mntfh, fattr); -	if (IS_ERR(inode)) { -		dprintk("nfs_get_root: get root inode failed\n"); -		ret = ERR_CAST(inode); -		goto out; -	} - -	error = nfs_superblock_set_dummy_root(sb, inode); -	if (error != 0) { -		ret = ERR_PTR(error); -		goto out; -	} - -	/* root dentries normally start off anonymous and get spliced in later -	 * if the dentry tree reaches them; however if the dentry already -	 * exists, we'll pick it up at this point and use it as the root -	 */ -	ret = d_obtain_alias(inode); -	if (IS_ERR(ret)) { -		dprintk("nfs_get_root: get root dentry failed\n"); -		goto out; -	} - -	security_d_instantiate(ret, inode); - -	if (ret->d_op == NULL) -		ret->d_op = server->nfs_client->rpc_ops->dentry_ops; - -out: -	nfs_free_fattr(fattr); -	dprintk("<-- nfs4_get_root()\n"); -	return ret; -} - -#endif /* CONFIG_NFS_V4 */  | 
