Commit b09b9417 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Fix the ustat() regression

Since 2.6.18, the superblock sb->s_root has been a dummy dentry with a
dummy inode. This breaks ustat(), which actually uses sb->s_root in a
vfstat() call.

Fix this by making the s_root a dummy alias to the directory inode that was
used when creating the superblock.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 2ffbb837
...@@ -42,6 +42,25 @@ ...@@ -42,6 +42,25 @@
#define NFSDBG_FACILITY NFSDBG_CLIENT #define NFSDBG_FACILITY NFSDBG_CLIENT
/*
* Set the superblock root dentry.
* Note that this function frees the inode in case of error.
*/
static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode)
{
/* 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);
return -ENOMEM;
}
/* Circumvent igrab(): we know the inode is not being freed */
atomic_inc(&inode->i_count);
}
return 0;
}
/* /*
* get an NFS2/NFS3 root dentry from the root filehandle * get an NFS2/NFS3 root dentry from the root filehandle
*/ */
...@@ -54,33 +73,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) ...@@ -54,33 +73,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
struct inode *inode; struct inode *inode;
int error; int error;
/* create a dummy root dentry with dummy inode for this superblock */
if (!sb->s_root) {
struct nfs_fh dummyfh;
struct dentry *root;
struct inode *iroot;
memset(&dummyfh, 0, sizeof(dummyfh));
memset(&fattr, 0, sizeof(fattr));
nfs_fattr_init(&fattr);
fattr.valid = NFS_ATTR_FATTR;
fattr.type = NFDIR;
fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
fattr.nlink = 2;
iroot = nfs_fhget(sb, &dummyfh, &fattr);
if (IS_ERR(iroot))
return ERR_PTR(PTR_ERR(iroot));
root = d_alloc_root(iroot);
if (!root) {
iput(iroot);
return ERR_PTR(-ENOMEM);
}
sb->s_root = root;
}
/* get the actual root for this mount */ /* get the actual root for this mount */
fsinfo.fattr = &fattr; fsinfo.fattr = &fattr;
...@@ -96,6 +88,10 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) ...@@ -96,6 +88,10 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
return ERR_PTR(PTR_ERR(inode)); return ERR_PTR(PTR_ERR(inode));
} }
error = nfs_superblock_set_dummy_root(sb, inode);
if (error != 0)
return ERR_PTR(error);
/* root dentries normally start off anonymous and get spliced in later /* root dentries normally start off anonymous and get spliced in later
* if the dentry tree reaches them; however if the dentry already * 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 * exists, we'll pick it up at this point and use it as the root
...@@ -241,33 +237,6 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) ...@@ -241,33 +237,6 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
dprintk("--> nfs4_get_root()\n"); dprintk("--> nfs4_get_root()\n");
/* create a dummy root dentry with dummy inode for this superblock */
if (!sb->s_root) {
struct nfs_fh dummyfh;
struct dentry *root;
struct inode *iroot;
memset(&dummyfh, 0, sizeof(dummyfh));
memset(&fattr, 0, sizeof(fattr));
nfs_fattr_init(&fattr);
fattr.valid = NFS_ATTR_FATTR;
fattr.type = NFDIR;
fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
fattr.nlink = 2;
iroot = nfs_fhget(sb, &dummyfh, &fattr);
if (IS_ERR(iroot))
return ERR_PTR(PTR_ERR(iroot));
root = d_alloc_root(iroot);
if (!root) {
iput(iroot);
return ERR_PTR(-ENOMEM);
}
sb->s_root = root;
}
/* get the info about the server and filesystem */ /* get the info about the server and filesystem */
error = nfs4_server_capabilities(server, mntfh); error = nfs4_server_capabilities(server, mntfh);
if (error < 0) { if (error < 0) {
...@@ -289,6 +258,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) ...@@ -289,6 +258,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
return ERR_PTR(PTR_ERR(inode)); return ERR_PTR(PTR_ERR(inode));
} }
error = nfs_superblock_set_dummy_root(sb, inode);
if (error != 0)
return ERR_PTR(error);
/* root dentries normally start off anonymous and get spliced in later /* root dentries normally start off anonymous and get spliced in later
* if the dentry tree reaches them; however if the dentry already * 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 * exists, we'll pick it up at this point and use it as the root
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment