diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-16 05:44:14 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-16 16:44:24 -0400 |
commit | b1942c5f8cf3bea3a3c88a7498ae4c4361f31afe (patch) | |
tree | 0ff98cbdf75b23104df97344dcd6a35a86bbe9ec /fs/nfs/getroot.c | |
parent | 0d5839ad05acd0fe2a84a39f33ac5efdf634a5a5 (diff) |
nfs: store devname at disconnected NFS roots
part 2: make sure that disconnected roots have corresponding mnt_devname
values stashed into them.
Have nfs*_get_root() stuff a copy of devname into ->d_fsdata of the
found root, provided that it is disconnected.
Have ->d_release() free it when dentry goes away.
Have the places where NFS uses ->d_fsdata for sillyrename (and that
can *never* happen to a disconnected root - dentry will be attached
to its parent) free old devname copies if they find those.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/nfs/getroot.c')
-rw-r--r-- | fs/nfs/getroot.c | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 4d6e5a317e6d..1084792bc0fe 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -82,12 +82,18 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, | |||
82 | struct nfs_fsinfo fsinfo; | 82 | struct nfs_fsinfo fsinfo; |
83 | struct dentry *ret; | 83 | struct dentry *ret; |
84 | struct inode *inode; | 84 | struct inode *inode; |
85 | void *name = kstrdup(devname, GFP_KERNEL); | ||
85 | int error; | 86 | int error; |
86 | 87 | ||
88 | if (!name) | ||
89 | return ERR_PTR(-ENOMEM); | ||
90 | |||
87 | /* get the actual root for this mount */ | 91 | /* get the actual root for this mount */ |
88 | fsinfo.fattr = nfs_alloc_fattr(); | 92 | fsinfo.fattr = nfs_alloc_fattr(); |
89 | if (fsinfo.fattr == NULL) | 93 | if (fsinfo.fattr == NULL) { |
94 | kfree(name); | ||
90 | return ERR_PTR(-ENOMEM); | 95 | return ERR_PTR(-ENOMEM); |
96 | } | ||
91 | 97 | ||
92 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 98 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
93 | if (error < 0) { | 99 | if (error < 0) { |
@@ -120,7 +126,15 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, | |||
120 | } | 126 | } |
121 | 127 | ||
122 | security_d_instantiate(ret, inode); | 128 | security_d_instantiate(ret, inode); |
129 | spin_lock(&ret->d_lock); | ||
130 | if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { | ||
131 | ret->d_fsdata = name; | ||
132 | name = NULL; | ||
133 | } | ||
134 | spin_unlock(&ret->d_lock); | ||
123 | out: | 135 | out: |
136 | if (name) | ||
137 | kfree(name); | ||
124 | nfs_free_fattr(fsinfo.fattr); | 138 | nfs_free_fattr(fsinfo.fattr); |
125 | return ret; | 139 | return ret; |
126 | } | 140 | } |
@@ -177,21 +191,28 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh, | |||
177 | struct nfs_fattr *fattr = NULL; | 191 | struct nfs_fattr *fattr = NULL; |
178 | struct dentry *ret; | 192 | struct dentry *ret; |
179 | struct inode *inode; | 193 | struct inode *inode; |
194 | void *name = kstrdup(devname, GFP_KERNEL); | ||
180 | int error; | 195 | int error; |
181 | 196 | ||
182 | dprintk("--> nfs4_get_root()\n"); | 197 | dprintk("--> nfs4_get_root()\n"); |
183 | 198 | ||
199 | if (!name) | ||
200 | return ERR_PTR(-ENOMEM); | ||
201 | |||
184 | /* get the info about the server and filesystem */ | 202 | /* get the info about the server and filesystem */ |
185 | error = nfs4_server_capabilities(server, mntfh); | 203 | error = nfs4_server_capabilities(server, mntfh); |
186 | if (error < 0) { | 204 | if (error < 0) { |
187 | dprintk("nfs_get_root: getcaps error = %d\n", | 205 | dprintk("nfs_get_root: getcaps error = %d\n", |
188 | -error); | 206 | -error); |
207 | kfree(name); | ||
189 | return ERR_PTR(error); | 208 | return ERR_PTR(error); |
190 | } | 209 | } |
191 | 210 | ||
192 | fattr = nfs_alloc_fattr(); | 211 | fattr = nfs_alloc_fattr(); |
193 | if (fattr == NULL) | 212 | if (fattr == NULL) { |
194 | return ERR_PTR(-ENOMEM);; | 213 | kfree(name); |
214 | return ERR_PTR(-ENOMEM); | ||
215 | } | ||
195 | 216 | ||
196 | /* get the actual root for this mount */ | 217 | /* get the actual root for this mount */ |
197 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); | 218 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); |
@@ -225,8 +246,15 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh, | |||
225 | } | 246 | } |
226 | 247 | ||
227 | security_d_instantiate(ret, inode); | 248 | security_d_instantiate(ret, inode); |
228 | 249 | spin_lock(&ret->d_lock); | |
250 | if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { | ||
251 | ret->d_fsdata = name; | ||
252 | name = NULL; | ||
253 | } | ||
254 | spin_unlock(&ret->d_lock); | ||
229 | out: | 255 | out: |
256 | if (name) | ||
257 | kfree(name); | ||
230 | nfs_free_fattr(fattr); | 258 | nfs_free_fattr(fattr); |
231 | dprintk("<-- nfs4_get_root()\n"); | 259 | dprintk("<-- nfs4_get_root()\n"); |
232 | return ret; | 260 | return ret; |