Commit 03550fac06c4f0c39a1885d46015c28794413c82
1 parent
c3bb257d2d
Exists in
master
and in
7 other branches
nfsd: move most of fh_verify to separate function
Move the code that actually parses the filehandle and looks up the dentry and export to a separate function. This simplifies the reference counting a little and moves fh_verify() a little closer to the kernel ideal of small, minimally-indentended functions. Clean up a few other minor style sins along the way. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Cc: Neil Brown <neilb@suse.de>
Showing 1 changed file with 123 additions and 105 deletions Side-by-side Diff
fs/nfsd/nfsfh.c
... | ... | @@ -113,6 +113,124 @@ |
113 | 113 | } |
114 | 114 | |
115 | 115 | /* |
116 | + * Use the given filehandle to look up the corresponding export and | |
117 | + * dentry. On success, the results are used to set fh_export and | |
118 | + * fh_dentry. | |
119 | + */ | |
120 | +static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) | |
121 | +{ | |
122 | + struct knfsd_fh *fh = &fhp->fh_handle; | |
123 | + struct fid *fid = NULL, sfid; | |
124 | + struct svc_export *exp; | |
125 | + struct dentry *dentry; | |
126 | + int fileid_type; | |
127 | + int data_left = fh->fh_size/4; | |
128 | + __be32 error; | |
129 | + | |
130 | + error = nfserr_stale; | |
131 | + if (rqstp->rq_vers > 2) | |
132 | + error = nfserr_badhandle; | |
133 | + if (rqstp->rq_vers == 4 && fh->fh_size == 0) | |
134 | + return nfserr_nofilehandle; | |
135 | + | |
136 | + if (fh->fh_version == 1) { | |
137 | + int len; | |
138 | + | |
139 | + if (--data_left < 0) | |
140 | + return error; | |
141 | + if (fh->fh_auth_type != 0) | |
142 | + return error; | |
143 | + len = key_len(fh->fh_fsid_type) / 4; | |
144 | + if (len == 0) | |
145 | + return error; | |
146 | + if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { | |
147 | + /* deprecated, convert to type 3 */ | |
148 | + len = key_len(FSID_ENCODE_DEV)/4; | |
149 | + fh->fh_fsid_type = FSID_ENCODE_DEV; | |
150 | + fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); | |
151 | + fh->fh_fsid[1] = fh->fh_fsid[2]; | |
152 | + } | |
153 | + data_left -= len; | |
154 | + if (data_left < 0) | |
155 | + return error; | |
156 | + exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth); | |
157 | + fid = (struct fid *)(fh->fh_auth + len); | |
158 | + } else { | |
159 | + __u32 tfh[2]; | |
160 | + dev_t xdev; | |
161 | + ino_t xino; | |
162 | + | |
163 | + if (fh->fh_size != NFS_FHSIZE) | |
164 | + return error; | |
165 | + /* assume old filehandle format */ | |
166 | + xdev = old_decode_dev(fh->ofh_xdev); | |
167 | + xino = u32_to_ino_t(fh->ofh_xino); | |
168 | + mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); | |
169 | + exp = rqst_exp_find(rqstp, FSID_DEV, tfh); | |
170 | + } | |
171 | + | |
172 | + error = nfserr_stale; | |
173 | + if (PTR_ERR(exp) == -ENOENT) | |
174 | + return error; | |
175 | + | |
176 | + if (IS_ERR(exp)) | |
177 | + return nfserrno(PTR_ERR(exp)); | |
178 | + | |
179 | + error = nfsd_setuser_and_check_port(rqstp, exp); | |
180 | + if (error) | |
181 | + goto out; | |
182 | + | |
183 | + /* | |
184 | + * Look up the dentry using the NFS file handle. | |
185 | + */ | |
186 | + error = nfserr_stale; | |
187 | + if (rqstp->rq_vers > 2) | |
188 | + error = nfserr_badhandle; | |
189 | + | |
190 | + if (fh->fh_version != 1) { | |
191 | + sfid.i32.ino = fh->ofh_ino; | |
192 | + sfid.i32.gen = fh->ofh_generation; | |
193 | + sfid.i32.parent_ino = fh->ofh_dirino; | |
194 | + fid = &sfid; | |
195 | + data_left = 3; | |
196 | + if (fh->ofh_dirino == 0) | |
197 | + fileid_type = FILEID_INO32_GEN; | |
198 | + else | |
199 | + fileid_type = FILEID_INO32_GEN_PARENT; | |
200 | + } else | |
201 | + fileid_type = fh->fh_fileid_type; | |
202 | + | |
203 | + if (fileid_type == FILEID_ROOT) | |
204 | + dentry = dget(exp->ex_path.dentry); | |
205 | + else { | |
206 | + dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, | |
207 | + data_left, fileid_type, | |
208 | + nfsd_acceptable, exp); | |
209 | + } | |
210 | + if (dentry == NULL) | |
211 | + goto out; | |
212 | + if (IS_ERR(dentry)) { | |
213 | + if (PTR_ERR(dentry) != -EINVAL) | |
214 | + error = nfserrno(PTR_ERR(dentry)); | |
215 | + goto out; | |
216 | + } | |
217 | + | |
218 | + if (S_ISDIR(dentry->d_inode->i_mode) && | |
219 | + (dentry->d_flags & DCACHE_DISCONNECTED)) { | |
220 | + printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", | |
221 | + dentry->d_parent->d_name.name, dentry->d_name.name); | |
222 | + } | |
223 | + | |
224 | + fhp->fh_dentry = dentry; | |
225 | + fhp->fh_export = exp; | |
226 | + nfsd_nr_verified++; | |
227 | + return 0; | |
228 | +out: | |
229 | + exp_put(exp); | |
230 | + return error; | |
231 | +} | |
232 | + | |
233 | +/* | |
116 | 234 | * Perform sanity checks on the dentry in a client's file handle. |
117 | 235 | * |
118 | 236 | * Note that the file handle dentry may need to be freed even after |
119 | 237 | |
120 | 238 | |
121 | 239 | |
... | ... | @@ -124,115 +242,18 @@ |
124 | 242 | __be32 |
125 | 243 | fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) |
126 | 244 | { |
127 | - struct knfsd_fh *fh = &fhp->fh_handle; | |
128 | - struct svc_export *exp = NULL; | |
245 | + struct svc_export *exp; | |
129 | 246 | struct dentry *dentry; |
130 | - __be32 error = 0; | |
247 | + __be32 error; | |
131 | 248 | |
132 | 249 | dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); |
133 | 250 | |
134 | 251 | if (!fhp->fh_dentry) { |
135 | - struct fid *fid = NULL, sfid; | |
136 | - int fileid_type; | |
137 | - int data_left = fh->fh_size/4; | |
138 | - | |
139 | - error = nfserr_stale; | |
140 | - if (rqstp->rq_vers > 2) | |
141 | - error = nfserr_badhandle; | |
142 | - if (rqstp->rq_vers == 4 && fh->fh_size == 0) | |
143 | - return nfserr_nofilehandle; | |
144 | - | |
145 | - if (fh->fh_version == 1) { | |
146 | - int len; | |
147 | - if (--data_left<0) goto out; | |
148 | - switch (fh->fh_auth_type) { | |
149 | - case 0: break; | |
150 | - default: goto out; | |
151 | - } | |
152 | - len = key_len(fh->fh_fsid_type) / 4; | |
153 | - if (len == 0) goto out; | |
154 | - if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { | |
155 | - /* deprecated, convert to type 3 */ | |
156 | - len = key_len(FSID_ENCODE_DEV)/4; | |
157 | - fh->fh_fsid_type = FSID_ENCODE_DEV; | |
158 | - fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); | |
159 | - fh->fh_fsid[1] = fh->fh_fsid[2]; | |
160 | - } | |
161 | - if ((data_left -= len)<0) goto out; | |
162 | - exp = rqst_exp_find(rqstp, fh->fh_fsid_type, | |
163 | - fh->fh_auth); | |
164 | - fid = (struct fid *)(fh->fh_auth + len); | |
165 | - } else { | |
166 | - __u32 tfh[2]; | |
167 | - dev_t xdev; | |
168 | - ino_t xino; | |
169 | - if (fh->fh_size != NFS_FHSIZE) | |
170 | - goto out; | |
171 | - /* assume old filehandle format */ | |
172 | - xdev = old_decode_dev(fh->ofh_xdev); | |
173 | - xino = u32_to_ino_t(fh->ofh_xino); | |
174 | - mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); | |
175 | - exp = rqst_exp_find(rqstp, FSID_DEV, tfh); | |
176 | - } | |
177 | - | |
178 | - error = nfserr_stale; | |
179 | - if (PTR_ERR(exp) == -ENOENT) | |
180 | - goto out; | |
181 | - | |
182 | - if (IS_ERR(exp)) { | |
183 | - error = nfserrno(PTR_ERR(exp)); | |
184 | - goto out; | |
185 | - } | |
186 | - | |
187 | - error = nfsd_setuser_and_check_port(rqstp, exp); | |
252 | + error = nfsd_set_fh_dentry(rqstp, fhp); | |
188 | 253 | if (error) |
189 | 254 | goto out; |
190 | - | |
191 | - /* | |
192 | - * Look up the dentry using the NFS file handle. | |
193 | - */ | |
194 | - error = nfserr_stale; | |
195 | - if (rqstp->rq_vers > 2) | |
196 | - error = nfserr_badhandle; | |
197 | - | |
198 | - if (fh->fh_version != 1) { | |
199 | - sfid.i32.ino = fh->ofh_ino; | |
200 | - sfid.i32.gen = fh->ofh_generation; | |
201 | - sfid.i32.parent_ino = fh->ofh_dirino; | |
202 | - fid = &sfid; | |
203 | - data_left = 3; | |
204 | - if (fh->ofh_dirino == 0) | |
205 | - fileid_type = FILEID_INO32_GEN; | |
206 | - else | |
207 | - fileid_type = FILEID_INO32_GEN_PARENT; | |
208 | - } else | |
209 | - fileid_type = fh->fh_fileid_type; | |
210 | - | |
211 | - if (fileid_type == FILEID_ROOT) | |
212 | - dentry = dget(exp->ex_path.dentry); | |
213 | - else { | |
214 | - dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, | |
215 | - data_left, fileid_type, | |
216 | - nfsd_acceptable, exp); | |
217 | - } | |
218 | - if (dentry == NULL) | |
219 | - goto out; | |
220 | - if (IS_ERR(dentry)) { | |
221 | - if (PTR_ERR(dentry) != -EINVAL) | |
222 | - error = nfserrno(PTR_ERR(dentry)); | |
223 | - goto out; | |
224 | - } | |
225 | - | |
226 | - if (S_ISDIR(dentry->d_inode->i_mode) && | |
227 | - (dentry->d_flags & DCACHE_DISCONNECTED)) { | |
228 | - printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", | |
229 | - dentry->d_parent->d_name.name, dentry->d_name.name); | |
230 | - } | |
231 | - | |
232 | - fhp->fh_dentry = dentry; | |
233 | - fhp->fh_export = exp; | |
234 | - nfsd_nr_verified++; | |
235 | - cache_get(&exp->h); | |
255 | + dentry = fhp->fh_dentry; | |
256 | + exp = fhp->fh_export; | |
236 | 257 | } else { |
237 | 258 | /* |
238 | 259 | * just rechecking permissions |
... | ... | @@ -242,7 +263,6 @@ |
242 | 263 | dprintk("nfsd: fh_verify - just checking\n"); |
243 | 264 | dentry = fhp->fh_dentry; |
244 | 265 | exp = fhp->fh_export; |
245 | - cache_get(&exp->h); | |
246 | 266 | /* |
247 | 267 | * Set user creds for this exportpoint; necessary even |
248 | 268 | * in the "just checking" case because this may be a |
... | ... | @@ -281,8 +301,6 @@ |
281 | 301 | access, ntohl(error)); |
282 | 302 | } |
283 | 303 | out: |
284 | - if (exp && !IS_ERR(exp)) | |
285 | - exp_put(exp); | |
286 | 304 | if (error == nfserr_stale) |
287 | 305 | nfsdstats.fh_stale++; |
288 | 306 | return error; |