diff options
Diffstat (limited to 'fs/nfs/getroot.c')
-rw-r--r-- | fs/nfs/getroot.c | 92 |
1 files changed, 38 insertions, 54 deletions
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 522e5ad4d8ad..e6242cdbaf91 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -43,6 +43,36 @@ | |||
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 | * Ensure that this dentry is invisible to d_find_alias(). | ||
62 | * Otherwise, it may be spliced into the tree by | ||
63 | * d_materialise_unique if a parent directory from the same | ||
64 | * filesystem gets mounted at a later time. | ||
65 | * This again causes shrink_dcache_for_umount_subtree() to | ||
66 | * Oops, since the test for IS_ROOT() will fail. | ||
67 | */ | ||
68 | spin_lock(&dcache_lock); | ||
69 | list_del_init(&sb->s_root->d_alias); | ||
70 | spin_unlock(&dcache_lock); | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | /* | ||
46 | * get an NFS2/NFS3 root dentry from the root filehandle | 76 | * get an NFS2/NFS3 root dentry from the root filehandle |
47 | */ | 77 | */ |
48 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 78 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) |
@@ -54,33 +84,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
54 | struct inode *inode; | 84 | struct inode *inode; |
55 | int error; | 85 | int error; |
56 | 86 | ||
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 */ | 87 | /* get the actual root for this mount */ |
85 | fsinfo.fattr = &fattr; | 88 | fsinfo.fattr = &fattr; |
86 | 89 | ||
@@ -96,6 +99,10 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
96 | return ERR_PTR(PTR_ERR(inode)); | 99 | return ERR_PTR(PTR_ERR(inode)); |
97 | } | 100 | } |
98 | 101 | ||
102 | error = nfs_superblock_set_dummy_root(sb, inode); | ||
103 | if (error != 0) | ||
104 | return ERR_PTR(error); | ||
105 | |||
99 | /* root dentries normally start off anonymous and get spliced in later | 106 | /* root dentries normally start off anonymous and get spliced in later |
100 | * if the dentry tree reaches them; however if the dentry already | 107 | * 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 | 108 | * exists, we'll pick it up at this point and use it as the root |
@@ -241,33 +248,6 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
241 | 248 | ||
242 | dprintk("--> nfs4_get_root()\n"); | 249 | dprintk("--> nfs4_get_root()\n"); |
243 | 250 | ||
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 */ | 251 | /* get the info about the server and filesystem */ |
272 | error = nfs4_server_capabilities(server, mntfh); | 252 | error = nfs4_server_capabilities(server, mntfh); |
273 | if (error < 0) { | 253 | if (error < 0) { |
@@ -289,6 +269,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
289 | return ERR_PTR(PTR_ERR(inode)); | 269 | return ERR_PTR(PTR_ERR(inode)); |
290 | } | 270 | } |
291 | 271 | ||
272 | error = nfs_superblock_set_dummy_root(sb, inode); | ||
273 | if (error != 0) | ||
274 | return ERR_PTR(error); | ||
275 | |||
292 | /* root dentries normally start off anonymous and get spliced in later | 276 | /* root dentries normally start off anonymous and get spliced in later |
293 | * if the dentry tree reaches them; however if the dentry already | 277 | * 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 | 278 | * exists, we'll pick it up at this point and use it as the root |