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 |