diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-10-25 13:56:10 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-11-17 13:08:44 -0500 |
| commit | b09b9417d074e01a4e4ab5c19358f1b3dc76c1b2 (patch) | |
| tree | ed90c600222d35834b045e8a72336621d36f0b2e | |
| parent | 2ffbb8377c7a0713baf6644e285adc27a5654582 (diff) | |
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: Trond Myklebust <Trond.Myklebust@netapp.com>
| -rw-r--r-- | fs/nfs/getroot.c | 81 |
1 files changed, 27 insertions, 54 deletions
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 522e5ad4d8ad..0ee43843f4ec 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
| @@ -43,6 +43,25 @@ | |||
| 43 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 43 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| 46 | * Set the superblock root dentry. | ||
| 47 | * Note that this function frees the inode in case of error. | ||
| 48 | */ | ||
| 49 | static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode) | ||
| 50 | { | ||
| 51 | /* The mntroot acts as the dummy root dentry for this superblock */ | ||
| 52 | if (sb->s_root == NULL) { | ||
| 53 | sb->s_root = d_alloc_root(inode); | ||
| 54 | if (sb->s_root == NULL) { | ||
| 55 | iput(inode); | ||
| 56 | return -ENOMEM; | ||
| 57 | } | ||
| 58 | /* Circumvent igrab(): we know the inode is not being freed */ | ||
| 59 | atomic_inc(&inode->i_count); | ||
| 60 | } | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | /* | ||
| 46 | * get an NFS2/NFS3 root dentry from the root filehandle | 65 | * get an NFS2/NFS3 root dentry from the root filehandle |
| 47 | */ | 66 | */ |
| 48 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 67 | 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) | |||
| 54 | struct inode *inode; | 73 | struct inode *inode; |
| 55 | int error; | 74 | int error; |
| 56 | 75 | ||
| 57 | /* create a dummy root dentry with dummy inode for this superblock */ | ||
| 58 | if (!sb->s_root) { | ||
| 59 | struct nfs_fh dummyfh; | ||
| 60 | struct dentry *root; | ||
| 61 | struct inode *iroot; | ||
| 62 | |||
| 63 | memset(&dummyfh, 0, sizeof(dummyfh)); | ||
| 64 | memset(&fattr, 0, sizeof(fattr)); | ||
| 65 | nfs_fattr_init(&fattr); | ||
| 66 | fattr.valid = NFS_ATTR_FATTR; | ||
| 67 | fattr.type = NFDIR; | ||
| 68 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | ||
| 69 | fattr.nlink = 2; | ||
| 70 | |||
| 71 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | ||
| 72 | if (IS_ERR(iroot)) | ||
| 73 | return ERR_PTR(PTR_ERR(iroot)); | ||
| 74 | |||
| 75 | root = d_alloc_root(iroot); | ||
| 76 | if (!root) { | ||
| 77 | iput(iroot); | ||
| 78 | return ERR_PTR(-ENOMEM); | ||
| 79 | } | ||
| 80 | |||
| 81 | sb->s_root = root; | ||
| 82 | } | ||
| 83 | |||
| 84 | /* get the actual root for this mount */ | 76 | /* get the actual root for this mount */ |
| 85 | fsinfo.fattr = &fattr; | 77 | fsinfo.fattr = &fattr; |
| 86 | 78 | ||
| @@ -96,6 +88,10 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 96 | return ERR_PTR(PTR_ERR(inode)); | 88 | return ERR_PTR(PTR_ERR(inode)); |
| 97 | } | 89 | } |
| 98 | 90 | ||
| 91 | error = nfs_superblock_set_dummy_root(sb, inode); | ||
| 92 | if (error != 0) | ||
| 93 | return ERR_PTR(error); | ||
| 94 | |||
| 99 | /* root dentries normally start off anonymous and get spliced in later | 95 | /* root dentries normally start off anonymous and get spliced in later |
| 100 | * if the dentry tree reaches them; however if the dentry already | 96 | * if the dentry tree reaches them; however if the dentry already |
| 101 | * exists, we'll pick it up at this point and use it as the root | 97 | * 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 | 237 | ||
| 242 | dprintk("--> nfs4_get_root()\n"); | 238 | dprintk("--> nfs4_get_root()\n"); |
| 243 | 239 | ||
| 244 | /* create a dummy root dentry with dummy inode for this superblock */ | ||
| 245 | if (!sb->s_root) { | ||
| 246 | struct nfs_fh dummyfh; | ||
| 247 | struct dentry *root; | ||
| 248 | struct inode *iroot; | ||
| 249 | |||
| 250 | memset(&dummyfh, 0, sizeof(dummyfh)); | ||
| 251 | memset(&fattr, 0, sizeof(fattr)); | ||
| 252 | nfs_fattr_init(&fattr); | ||
| 253 | fattr.valid = NFS_ATTR_FATTR; | ||
| 254 | fattr.type = NFDIR; | ||
| 255 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | ||
| 256 | fattr.nlink = 2; | ||
| 257 | |||
| 258 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | ||
| 259 | if (IS_ERR(iroot)) | ||
| 260 | return ERR_PTR(PTR_ERR(iroot)); | ||
| 261 | |||
| 262 | root = d_alloc_root(iroot); | ||
| 263 | if (!root) { | ||
| 264 | iput(iroot); | ||
| 265 | return ERR_PTR(-ENOMEM); | ||
| 266 | } | ||
| 267 | |||
| 268 | sb->s_root = root; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* get the info about the server and filesystem */ | 240 | /* get the info about the server and filesystem */ |
| 272 | error = nfs4_server_capabilities(server, mntfh); | 241 | error = nfs4_server_capabilities(server, mntfh); |
| 273 | if (error < 0) { | 242 | if (error < 0) { |
| @@ -289,6 +258,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 289 | return ERR_PTR(PTR_ERR(inode)); | 258 | return ERR_PTR(PTR_ERR(inode)); |
| 290 | } | 259 | } |
| 291 | 260 | ||
| 261 | error = nfs_superblock_set_dummy_root(sb, inode); | ||
| 262 | if (error != 0) | ||
| 263 | return ERR_PTR(error); | ||
| 264 | |||
| 292 | /* root dentries normally start off anonymous and get spliced in later | 265 | /* root dentries normally start off anonymous and get spliced in later |
| 293 | * if the dentry tree reaches them; however if the dentry already | 266 | * if the dentry tree reaches them; however if the dentry already |
| 294 | * exists, we'll pick it up at this point and use it as the root | 267 | * exists, we'll pick it up at this point and use it as the root |
