diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 625 |
1 files changed, 345 insertions, 280 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 50bc94243ca1..8522729830db 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -33,13 +33,6 @@ | |||
33 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 33 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
34 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 34 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
35 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | * | ||
37 | * Note: some routines in this file are just trivial wrappers | ||
38 | * (e.g. nfsd4_lookup()) defined solely for the sake of consistent | ||
39 | * naming. Since all such routines have been declared "inline", | ||
40 | * there shouldn't be any associated overhead. At some point in | ||
41 | * the future, I might inline these "by hand" to clean up a | ||
42 | * little. | ||
43 | */ | 36 | */ |
44 | 37 | ||
45 | #include <linux/param.h> | 38 | #include <linux/param.h> |
@@ -161,8 +154,9 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ | |||
161 | } | 154 | } |
162 | 155 | ||
163 | 156 | ||
164 | static inline __be32 | 157 | static __be32 |
165 | nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) | 158 | nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
159 | struct nfsd4_open *open) | ||
166 | { | 160 | { |
167 | __be32 status; | 161 | __be32 status; |
168 | dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", | 162 | dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", |
@@ -179,11 +173,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
179 | status = nfsd4_process_open1(open); | 173 | status = nfsd4_process_open1(open); |
180 | if (status == nfserr_replay_me) { | 174 | if (status == nfserr_replay_me) { |
181 | struct nfs4_replay *rp = &open->op_stateowner->so_replay; | 175 | struct nfs4_replay *rp = &open->op_stateowner->so_replay; |
182 | fh_put(current_fh); | 176 | fh_put(&cstate->current_fh); |
183 | current_fh->fh_handle.fh_size = rp->rp_openfh_len; | 177 | cstate->current_fh.fh_handle.fh_size = rp->rp_openfh_len; |
184 | memcpy(¤t_fh->fh_handle.fh_base, rp->rp_openfh, | 178 | memcpy(&cstate->current_fh.fh_handle.fh_base, rp->rp_openfh, |
185 | rp->rp_openfh_len); | 179 | rp->rp_openfh_len); |
186 | status = fh_verify(rqstp, current_fh, 0, MAY_NOP); | 180 | status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); |
187 | if (status) | 181 | if (status) |
188 | dprintk("nfsd4_open: replay failed" | 182 | dprintk("nfsd4_open: replay failed" |
189 | " restoring previous filehandle\n"); | 183 | " restoring previous filehandle\n"); |
@@ -215,7 +209,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
215 | * (3) set open->op_truncate if the file is to be | 209 | * (3) set open->op_truncate if the file is to be |
216 | * truncated after opening, (4) do permission checking. | 210 | * truncated after opening, (4) do permission checking. |
217 | */ | 211 | */ |
218 | status = do_open_lookup(rqstp, current_fh, open); | 212 | status = do_open_lookup(rqstp, &cstate->current_fh, |
213 | open); | ||
219 | if (status) | 214 | if (status) |
220 | goto out; | 215 | goto out; |
221 | break; | 216 | break; |
@@ -227,7 +222,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
227 | * open->op_truncate if the file is to be truncated | 222 | * open->op_truncate if the file is to be truncated |
228 | * after opening, (3) do permission checking. | 223 | * after opening, (3) do permission checking. |
229 | */ | 224 | */ |
230 | status = do_open_fhandle(rqstp, current_fh, open); | 225 | status = do_open_fhandle(rqstp, &cstate->current_fh, |
226 | open); | ||
231 | if (status) | 227 | if (status) |
232 | goto out; | 228 | goto out; |
233 | break; | 229 | break; |
@@ -248,11 +244,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
248 | * successful, it (1) truncates the file if open->op_truncate was | 244 | * successful, it (1) truncates the file if open->op_truncate was |
249 | * set, (2) sets open->op_stateid, (3) sets open->op_delegation. | 245 | * set, (2) sets open->op_stateid, (3) sets open->op_delegation. |
250 | */ | 246 | */ |
251 | status = nfsd4_process_open2(rqstp, current_fh, open); | 247 | status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); |
252 | out: | 248 | out: |
253 | if (open->op_stateowner) { | 249 | if (open->op_stateowner) { |
254 | nfs4_get_stateowner(open->op_stateowner); | 250 | nfs4_get_stateowner(open->op_stateowner); |
255 | *replay_owner = open->op_stateowner; | 251 | cstate->replay_owner = open->op_stateowner; |
256 | } | 252 | } |
257 | nfs4_unlock_state(); | 253 | nfs4_unlock_state(); |
258 | return status; | 254 | return status; |
@@ -261,71 +257,80 @@ out: | |||
261 | /* | 257 | /* |
262 | * filehandle-manipulating ops. | 258 | * filehandle-manipulating ops. |
263 | */ | 259 | */ |
264 | static inline __be32 | 260 | static __be32 |
265 | nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh) | 261 | nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
262 | struct svc_fh **getfh) | ||
266 | { | 263 | { |
267 | if (!current_fh->fh_dentry) | 264 | if (!cstate->current_fh.fh_dentry) |
268 | return nfserr_nofilehandle; | 265 | return nfserr_nofilehandle; |
269 | 266 | ||
270 | *getfh = current_fh; | 267 | *getfh = &cstate->current_fh; |
271 | return nfs_ok; | 268 | return nfs_ok; |
272 | } | 269 | } |
273 | 270 | ||
274 | static inline __be32 | 271 | static __be32 |
275 | nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh) | 272 | nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
273 | struct nfsd4_putfh *putfh) | ||
276 | { | 274 | { |
277 | fh_put(current_fh); | 275 | fh_put(&cstate->current_fh); |
278 | current_fh->fh_handle.fh_size = putfh->pf_fhlen; | 276 | cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; |
279 | memcpy(¤t_fh->fh_handle.fh_base, putfh->pf_fhval, putfh->pf_fhlen); | 277 | memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, |
280 | return fh_verify(rqstp, current_fh, 0, MAY_NOP); | 278 | putfh->pf_fhlen); |
279 | return fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); | ||
281 | } | 280 | } |
282 | 281 | ||
283 | static inline __be32 | 282 | static __be32 |
284 | nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) | 283 | nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
284 | void *arg) | ||
285 | { | 285 | { |
286 | __be32 status; | 286 | __be32 status; |
287 | 287 | ||
288 | fh_put(current_fh); | 288 | fh_put(&cstate->current_fh); |
289 | status = exp_pseudoroot(rqstp->rq_client, current_fh, | 289 | status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh, |
290 | &rqstp->rq_chandle); | 290 | &rqstp->rq_chandle); |
291 | return status; | 291 | return status; |
292 | } | 292 | } |
293 | 293 | ||
294 | static inline __be32 | 294 | static __be32 |
295 | nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh) | 295 | nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
296 | void *arg) | ||
296 | { | 297 | { |
297 | if (!save_fh->fh_dentry) | 298 | if (!cstate->save_fh.fh_dentry) |
298 | return nfserr_restorefh; | 299 | return nfserr_restorefh; |
299 | 300 | ||
300 | fh_dup2(current_fh, save_fh); | 301 | fh_dup2(&cstate->current_fh, &cstate->save_fh); |
301 | return nfs_ok; | 302 | return nfs_ok; |
302 | } | 303 | } |
303 | 304 | ||
304 | static inline __be32 | 305 | static __be32 |
305 | nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh) | 306 | nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
307 | void *arg) | ||
306 | { | 308 | { |
307 | if (!current_fh->fh_dentry) | 309 | if (!cstate->current_fh.fh_dentry) |
308 | return nfserr_nofilehandle; | 310 | return nfserr_nofilehandle; |
309 | 311 | ||
310 | fh_dup2(save_fh, current_fh); | 312 | fh_dup2(&cstate->save_fh, &cstate->current_fh); |
311 | return nfs_ok; | 313 | return nfs_ok; |
312 | } | 314 | } |
313 | 315 | ||
314 | /* | 316 | /* |
315 | * misc nfsv4 ops | 317 | * misc nfsv4 ops |
316 | */ | 318 | */ |
317 | static inline __be32 | 319 | static __be32 |
318 | nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access) | 320 | nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
321 | struct nfsd4_access *access) | ||
319 | { | 322 | { |
320 | if (access->ac_req_access & ~NFS3_ACCESS_FULL) | 323 | if (access->ac_req_access & ~NFS3_ACCESS_FULL) |
321 | return nfserr_inval; | 324 | return nfserr_inval; |
322 | 325 | ||
323 | access->ac_resp_access = access->ac_req_access; | 326 | access->ac_resp_access = access->ac_req_access; |
324 | return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported); | 327 | return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access, |
328 | &access->ac_supported); | ||
325 | } | 329 | } |
326 | 330 | ||
327 | static inline __be32 | 331 | static __be32 |
328 | nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit) | 332 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
333 | struct nfsd4_commit *commit) | ||
329 | { | 334 | { |
330 | __be32 status; | 335 | __be32 status; |
331 | 336 | ||
@@ -333,14 +338,16 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com | |||
333 | *p++ = nfssvc_boot.tv_sec; | 338 | *p++ = nfssvc_boot.tv_sec; |
334 | *p++ = nfssvc_boot.tv_usec; | 339 | *p++ = nfssvc_boot.tv_usec; |
335 | 340 | ||
336 | status = nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count); | 341 | status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, |
342 | commit->co_count); | ||
337 | if (status == nfserr_symlink) | 343 | if (status == nfserr_symlink) |
338 | status = nfserr_inval; | 344 | status = nfserr_inval; |
339 | return status; | 345 | return status; |
340 | } | 346 | } |
341 | 347 | ||
342 | static __be32 | 348 | static __be32 |
343 | nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create) | 349 | nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
350 | struct nfsd4_create *create) | ||
344 | { | 351 | { |
345 | struct svc_fh resfh; | 352 | struct svc_fh resfh; |
346 | __be32 status; | 353 | __be32 status; |
@@ -348,7 +355,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre | |||
348 | 355 | ||
349 | fh_init(&resfh, NFS4_FHSIZE); | 356 | fh_init(&resfh, NFS4_FHSIZE); |
350 | 357 | ||
351 | status = fh_verify(rqstp, current_fh, S_IFDIR, MAY_CREATE); | 358 | status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, MAY_CREATE); |
352 | if (status == nfserr_symlink) | 359 | if (status == nfserr_symlink) |
353 | status = nfserr_notdir; | 360 | status = nfserr_notdir; |
354 | if (status) | 361 | if (status) |
@@ -365,9 +372,10 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre | |||
365 | */ | 372 | */ |
366 | create->cr_linkname[create->cr_linklen] = 0; | 373 | create->cr_linkname[create->cr_linklen] = 0; |
367 | 374 | ||
368 | status = nfsd_symlink(rqstp, current_fh, create->cr_name, | 375 | status = nfsd_symlink(rqstp, &cstate->current_fh, |
369 | create->cr_namelen, create->cr_linkname, | 376 | create->cr_name, create->cr_namelen, |
370 | create->cr_linklen, &resfh, &create->cr_iattr); | 377 | create->cr_linkname, create->cr_linklen, |
378 | &resfh, &create->cr_iattr); | ||
371 | break; | 379 | break; |
372 | 380 | ||
373 | case NF4BLK: | 381 | case NF4BLK: |
@@ -375,9 +383,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre | |||
375 | if (MAJOR(rdev) != create->cr_specdata1 || | 383 | if (MAJOR(rdev) != create->cr_specdata1 || |
376 | MINOR(rdev) != create->cr_specdata2) | 384 | MINOR(rdev) != create->cr_specdata2) |
377 | return nfserr_inval; | 385 | return nfserr_inval; |
378 | status = nfsd_create(rqstp, current_fh, create->cr_name, | 386 | status = nfsd_create(rqstp, &cstate->current_fh, |
379 | create->cr_namelen, &create->cr_iattr, | 387 | create->cr_name, create->cr_namelen, |
380 | S_IFBLK, rdev, &resfh); | 388 | &create->cr_iattr, S_IFBLK, rdev, &resfh); |
381 | break; | 389 | break; |
382 | 390 | ||
383 | case NF4CHR: | 391 | case NF4CHR: |
@@ -385,28 +393,28 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre | |||
385 | if (MAJOR(rdev) != create->cr_specdata1 || | 393 | if (MAJOR(rdev) != create->cr_specdata1 || |
386 | MINOR(rdev) != create->cr_specdata2) | 394 | MINOR(rdev) != create->cr_specdata2) |
387 | return nfserr_inval; | 395 | return nfserr_inval; |
388 | status = nfsd_create(rqstp, current_fh, create->cr_name, | 396 | status = nfsd_create(rqstp, &cstate->current_fh, |
389 | create->cr_namelen, &create->cr_iattr, | 397 | create->cr_name, create->cr_namelen, |
390 | S_IFCHR, rdev, &resfh); | 398 | &create->cr_iattr,S_IFCHR, rdev, &resfh); |
391 | break; | 399 | break; |
392 | 400 | ||
393 | case NF4SOCK: | 401 | case NF4SOCK: |
394 | status = nfsd_create(rqstp, current_fh, create->cr_name, | 402 | status = nfsd_create(rqstp, &cstate->current_fh, |
395 | create->cr_namelen, &create->cr_iattr, | 403 | create->cr_name, create->cr_namelen, |
396 | S_IFSOCK, 0, &resfh); | 404 | &create->cr_iattr, S_IFSOCK, 0, &resfh); |
397 | break; | 405 | break; |
398 | 406 | ||
399 | case NF4FIFO: | 407 | case NF4FIFO: |
400 | status = nfsd_create(rqstp, current_fh, create->cr_name, | 408 | status = nfsd_create(rqstp, &cstate->current_fh, |
401 | create->cr_namelen, &create->cr_iattr, | 409 | create->cr_name, create->cr_namelen, |
402 | S_IFIFO, 0, &resfh); | 410 | &create->cr_iattr, S_IFIFO, 0, &resfh); |
403 | break; | 411 | break; |
404 | 412 | ||
405 | case NF4DIR: | 413 | case NF4DIR: |
406 | create->cr_iattr.ia_valid &= ~ATTR_SIZE; | 414 | create->cr_iattr.ia_valid &= ~ATTR_SIZE; |
407 | status = nfsd_create(rqstp, current_fh, create->cr_name, | 415 | status = nfsd_create(rqstp, &cstate->current_fh, |
408 | create->cr_namelen, &create->cr_iattr, | 416 | create->cr_name, create->cr_namelen, |
409 | S_IFDIR, 0, &resfh); | 417 | &create->cr_iattr, S_IFDIR, 0, &resfh); |
410 | break; | 418 | break; |
411 | 419 | ||
412 | default: | 420 | default: |
@@ -414,21 +422,22 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre | |||
414 | } | 422 | } |
415 | 423 | ||
416 | if (!status) { | 424 | if (!status) { |
417 | fh_unlock(current_fh); | 425 | fh_unlock(&cstate->current_fh); |
418 | set_change_info(&create->cr_cinfo, current_fh); | 426 | set_change_info(&create->cr_cinfo, &cstate->current_fh); |
419 | fh_dup2(current_fh, &resfh); | 427 | fh_dup2(&cstate->current_fh, &resfh); |
420 | } | 428 | } |
421 | 429 | ||
422 | fh_put(&resfh); | 430 | fh_put(&resfh); |
423 | return status; | 431 | return status; |
424 | } | 432 | } |
425 | 433 | ||
426 | static inline __be32 | 434 | static __be32 |
427 | nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr) | 435 | nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
436 | struct nfsd4_getattr *getattr) | ||
428 | { | 437 | { |
429 | __be32 status; | 438 | __be32 status; |
430 | 439 | ||
431 | status = fh_verify(rqstp, current_fh, 0, MAY_NOP); | 440 | status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); |
432 | if (status) | 441 | if (status) |
433 | return status; | 442 | return status; |
434 | 443 | ||
@@ -438,26 +447,28 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ge | |||
438 | getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0; | 447 | getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0; |
439 | getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1; | 448 | getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1; |
440 | 449 | ||
441 | getattr->ga_fhp = current_fh; | 450 | getattr->ga_fhp = &cstate->current_fh; |
442 | return nfs_ok; | 451 | return nfs_ok; |
443 | } | 452 | } |
444 | 453 | ||
445 | static inline __be32 | 454 | static __be32 |
446 | nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, | 455 | nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
447 | struct svc_fh *save_fh, struct nfsd4_link *link) | 456 | struct nfsd4_link *link) |
448 | { | 457 | { |
449 | __be32 status = nfserr_nofilehandle; | 458 | __be32 status = nfserr_nofilehandle; |
450 | 459 | ||
451 | if (!save_fh->fh_dentry) | 460 | if (!cstate->save_fh.fh_dentry) |
452 | return status; | 461 | return status; |
453 | status = nfsd_link(rqstp, current_fh, link->li_name, link->li_namelen, save_fh); | 462 | status = nfsd_link(rqstp, &cstate->current_fh, |
463 | link->li_name, link->li_namelen, &cstate->save_fh); | ||
454 | if (!status) | 464 | if (!status) |
455 | set_change_info(&link->li_cinfo, current_fh); | 465 | set_change_info(&link->li_cinfo, &cstate->current_fh); |
456 | return status; | 466 | return status; |
457 | } | 467 | } |
458 | 468 | ||
459 | static __be32 | 469 | static __be32 |
460 | nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) | 470 | nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
471 | void *arg) | ||
461 | { | 472 | { |
462 | struct svc_fh tmp_fh; | 473 | struct svc_fh tmp_fh; |
463 | __be32 ret; | 474 | __be32 ret; |
@@ -466,22 +477,27 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) | |||
466 | if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, | 477 | if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, |
467 | &rqstp->rq_chandle)) != 0) | 478 | &rqstp->rq_chandle)) != 0) |
468 | return ret; | 479 | return ret; |
469 | if (tmp_fh.fh_dentry == current_fh->fh_dentry) { | 480 | if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { |
470 | fh_put(&tmp_fh); | 481 | fh_put(&tmp_fh); |
471 | return nfserr_noent; | 482 | return nfserr_noent; |
472 | } | 483 | } |
473 | fh_put(&tmp_fh); | 484 | fh_put(&tmp_fh); |
474 | return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh); | 485 | return nfsd_lookup(rqstp, &cstate->current_fh, |
486 | "..", 2, &cstate->current_fh); | ||
475 | } | 487 | } |
476 | 488 | ||
477 | static inline __be32 | 489 | static __be32 |
478 | nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup) | 490 | nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
491 | struct nfsd4_lookup *lookup) | ||
479 | { | 492 | { |
480 | return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh); | 493 | return nfsd_lookup(rqstp, &cstate->current_fh, |
494 | lookup->lo_name, lookup->lo_len, | ||
495 | &cstate->current_fh); | ||
481 | } | 496 | } |
482 | 497 | ||
483 | static inline __be32 | 498 | static __be32 |
484 | nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) | 499 | nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
500 | struct nfsd4_read *read) | ||
485 | { | 501 | { |
486 | __be32 status; | 502 | __be32 status; |
487 | 503 | ||
@@ -493,7 +509,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read | |||
493 | 509 | ||
494 | nfs4_lock_state(); | 510 | nfs4_lock_state(); |
495 | /* check stateid */ | 511 | /* check stateid */ |
496 | if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, | 512 | if ((status = nfs4_preprocess_stateid_op(&cstate->current_fh, |
513 | &read->rd_stateid, | ||
497 | CHECK_FH | RD_STATE, &read->rd_filp))) { | 514 | CHECK_FH | RD_STATE, &read->rd_filp))) { |
498 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); | 515 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); |
499 | goto out; | 516 | goto out; |
@@ -504,12 +521,13 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read | |||
504 | out: | 521 | out: |
505 | nfs4_unlock_state(); | 522 | nfs4_unlock_state(); |
506 | read->rd_rqstp = rqstp; | 523 | read->rd_rqstp = rqstp; |
507 | read->rd_fhp = current_fh; | 524 | read->rd_fhp = &cstate->current_fh; |
508 | return status; | 525 | return status; |
509 | } | 526 | } |
510 | 527 | ||
511 | static inline __be32 | 528 | static __be32 |
512 | nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir) | 529 | nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
530 | struct nfsd4_readdir *readdir) | ||
513 | { | 531 | { |
514 | u64 cookie = readdir->rd_cookie; | 532 | u64 cookie = readdir->rd_cookie; |
515 | static const nfs4_verifier zeroverf; | 533 | static const nfs4_verifier zeroverf; |
@@ -527,48 +545,51 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_re | |||
527 | return nfserr_bad_cookie; | 545 | return nfserr_bad_cookie; |
528 | 546 | ||
529 | readdir->rd_rqstp = rqstp; | 547 | readdir->rd_rqstp = rqstp; |
530 | readdir->rd_fhp = current_fh; | 548 | readdir->rd_fhp = &cstate->current_fh; |
531 | return nfs_ok; | 549 | return nfs_ok; |
532 | } | 550 | } |
533 | 551 | ||
534 | static inline __be32 | 552 | static __be32 |
535 | nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink) | 553 | nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
554 | struct nfsd4_readlink *readlink) | ||
536 | { | 555 | { |
537 | readlink->rl_rqstp = rqstp; | 556 | readlink->rl_rqstp = rqstp; |
538 | readlink->rl_fhp = current_fh; | 557 | readlink->rl_fhp = &cstate->current_fh; |
539 | return nfs_ok; | 558 | return nfs_ok; |
540 | } | 559 | } |
541 | 560 | ||
542 | static inline __be32 | 561 | static __be32 |
543 | nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove) | 562 | nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
563 | struct nfsd4_remove *remove) | ||
544 | { | 564 | { |
545 | __be32 status; | 565 | __be32 status; |
546 | 566 | ||
547 | if (nfs4_in_grace()) | 567 | if (nfs4_in_grace()) |
548 | return nfserr_grace; | 568 | return nfserr_grace; |
549 | status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen); | 569 | status = nfsd_unlink(rqstp, &cstate->current_fh, 0, |
570 | remove->rm_name, remove->rm_namelen); | ||
550 | if (status == nfserr_symlink) | 571 | if (status == nfserr_symlink) |
551 | return nfserr_notdir; | 572 | return nfserr_notdir; |
552 | if (!status) { | 573 | if (!status) { |
553 | fh_unlock(current_fh); | 574 | fh_unlock(&cstate->current_fh); |
554 | set_change_info(&remove->rm_cinfo, current_fh); | 575 | set_change_info(&remove->rm_cinfo, &cstate->current_fh); |
555 | } | 576 | } |
556 | return status; | 577 | return status; |
557 | } | 578 | } |
558 | 579 | ||
559 | static inline __be32 | 580 | static __be32 |
560 | nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, | 581 | nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
561 | struct svc_fh *save_fh, struct nfsd4_rename *rename) | 582 | struct nfsd4_rename *rename) |
562 | { | 583 | { |
563 | __be32 status = nfserr_nofilehandle; | 584 | __be32 status = nfserr_nofilehandle; |
564 | 585 | ||
565 | if (!save_fh->fh_dentry) | 586 | if (!cstate->save_fh.fh_dentry) |
566 | return status; | 587 | return status; |
567 | if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags | 588 | if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags |
568 | & NFSEXP_NOSUBTREECHECK)) | 589 | & NFSEXP_NOSUBTREECHECK)) |
569 | return nfserr_grace; | 590 | return nfserr_grace; |
570 | status = nfsd_rename(rqstp, save_fh, rename->rn_sname, | 591 | status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, |
571 | rename->rn_snamelen, current_fh, | 592 | rename->rn_snamelen, &cstate->current_fh, |
572 | rename->rn_tname, rename->rn_tnamelen); | 593 | rename->rn_tname, rename->rn_tnamelen); |
573 | 594 | ||
574 | /* the underlying filesystem returns different error's than required | 595 | /* the underlying filesystem returns different error's than required |
@@ -576,27 +597,28 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, | |||
576 | if (status == nfserr_isdir) | 597 | if (status == nfserr_isdir) |
577 | status = nfserr_exist; | 598 | status = nfserr_exist; |
578 | else if ((status == nfserr_notdir) && | 599 | else if ((status == nfserr_notdir) && |
579 | (S_ISDIR(save_fh->fh_dentry->d_inode->i_mode) && | 600 | (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && |
580 | S_ISDIR(current_fh->fh_dentry->d_inode->i_mode))) | 601 | S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) |
581 | status = nfserr_exist; | 602 | status = nfserr_exist; |
582 | else if (status == nfserr_symlink) | 603 | else if (status == nfserr_symlink) |
583 | status = nfserr_notdir; | 604 | status = nfserr_notdir; |
584 | 605 | ||
585 | if (!status) { | 606 | if (!status) { |
586 | set_change_info(&rename->rn_sinfo, current_fh); | 607 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); |
587 | set_change_info(&rename->rn_tinfo, save_fh); | 608 | set_change_info(&rename->rn_tinfo, &cstate->save_fh); |
588 | } | 609 | } |
589 | return status; | 610 | return status; |
590 | } | 611 | } |
591 | 612 | ||
592 | static inline __be32 | 613 | static __be32 |
593 | nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr) | 614 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
615 | struct nfsd4_setattr *setattr) | ||
594 | { | 616 | { |
595 | __be32 status = nfs_ok; | 617 | __be32 status = nfs_ok; |
596 | 618 | ||
597 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { | 619 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { |
598 | nfs4_lock_state(); | 620 | nfs4_lock_state(); |
599 | status = nfs4_preprocess_stateid_op(current_fh, | 621 | status = nfs4_preprocess_stateid_op(&cstate->current_fh, |
600 | &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); | 622 | &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); |
601 | nfs4_unlock_state(); | 623 | nfs4_unlock_state(); |
602 | if (status) { | 624 | if (status) { |
@@ -606,16 +628,18 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se | |||
606 | } | 628 | } |
607 | status = nfs_ok; | 629 | status = nfs_ok; |
608 | if (setattr->sa_acl != NULL) | 630 | if (setattr->sa_acl != NULL) |
609 | status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); | 631 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, |
632 | setattr->sa_acl); | ||
610 | if (status) | 633 | if (status) |
611 | return status; | 634 | return status; |
612 | status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, | 635 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, |
613 | 0, (time_t)0); | 636 | 0, (time_t)0); |
614 | return status; | 637 | return status; |
615 | } | 638 | } |
616 | 639 | ||
617 | static inline __be32 | 640 | static __be32 |
618 | nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write) | 641 | nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
642 | struct nfsd4_write *write) | ||
619 | { | 643 | { |
620 | stateid_t *stateid = &write->wr_stateid; | 644 | stateid_t *stateid = &write->wr_stateid; |
621 | struct file *filp = NULL; | 645 | struct file *filp = NULL; |
@@ -628,7 +652,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
628 | return nfserr_inval; | 652 | return nfserr_inval; |
629 | 653 | ||
630 | nfs4_lock_state(); | 654 | nfs4_lock_state(); |
631 | status = nfs4_preprocess_stateid_op(current_fh, stateid, | 655 | status = nfs4_preprocess_stateid_op(&cstate->current_fh, stateid, |
632 | CHECK_FH | WR_STATE, &filp); | 656 | CHECK_FH | WR_STATE, &filp); |
633 | if (filp) | 657 | if (filp) |
634 | get_file(filp); | 658 | get_file(filp); |
@@ -645,9 +669,9 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
645 | *p++ = nfssvc_boot.tv_sec; | 669 | *p++ = nfssvc_boot.tv_sec; |
646 | *p++ = nfssvc_boot.tv_usec; | 670 | *p++ = nfssvc_boot.tv_usec; |
647 | 671 | ||
648 | status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, | 672 | status = nfsd_write(rqstp, &cstate->current_fh, filp, |
649 | rqstp->rq_vec, write->wr_vlen, write->wr_buflen, | 673 | write->wr_offset, rqstp->rq_vec, write->wr_vlen, |
650 | &write->wr_how_written); | 674 | write->wr_buflen, &write->wr_how_written); |
651 | if (filp) | 675 | if (filp) |
652 | fput(filp); | 676 | fput(filp); |
653 | 677 | ||
@@ -662,13 +686,14 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
662 | * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. | 686 | * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. |
663 | */ | 687 | */ |
664 | static __be32 | 688 | static __be32 |
665 | nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify) | 689 | _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
690 | struct nfsd4_verify *verify) | ||
666 | { | 691 | { |
667 | __be32 *buf, *p; | 692 | __be32 *buf, *p; |
668 | int count; | 693 | int count; |
669 | __be32 status; | 694 | __be32 status; |
670 | 695 | ||
671 | status = fh_verify(rqstp, current_fh, 0, MAY_NOP); | 696 | status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); |
672 | if (status) | 697 | if (status) |
673 | return status; | 698 | return status; |
674 | 699 | ||
@@ -689,8 +714,9 @@ nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ver | |||
689 | if (!buf) | 714 | if (!buf) |
690 | return nfserr_resource; | 715 | return nfserr_resource; |
691 | 716 | ||
692 | status = nfsd4_encode_fattr(current_fh, current_fh->fh_export, | 717 | status = nfsd4_encode_fattr(&cstate->current_fh, |
693 | current_fh->fh_dentry, buf, | 718 | cstate->current_fh.fh_export, |
719 | cstate->current_fh.fh_dentry, buf, | ||
694 | &count, verify->ve_bmval, | 720 | &count, verify->ve_bmval, |
695 | rqstp); | 721 | rqstp); |
696 | 722 | ||
@@ -712,6 +738,26 @@ out_kfree: | |||
712 | return status; | 738 | return status; |
713 | } | 739 | } |
714 | 740 | ||
741 | static __be32 | ||
742 | nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
743 | struct nfsd4_verify *verify) | ||
744 | { | ||
745 | __be32 status; | ||
746 | |||
747 | status = _nfsd4_verify(rqstp, cstate, verify); | ||
748 | return status == nfserr_not_same ? nfs_ok : status; | ||
749 | } | ||
750 | |||
751 | static __be32 | ||
752 | nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
753 | struct nfsd4_verify *verify) | ||
754 | { | ||
755 | __be32 status; | ||
756 | |||
757 | status = _nfsd4_verify(rqstp, cstate, verify); | ||
758 | return status == nfserr_same ? nfs_ok : status; | ||
759 | } | ||
760 | |||
715 | /* | 761 | /* |
716 | * NULL call. | 762 | * NULL call. |
717 | */ | 763 | */ |
@@ -727,6 +773,42 @@ static inline void nfsd4_increment_op_stats(u32 opnum) | |||
727 | nfsdstats.nfs4_opcount[opnum]++; | 773 | nfsdstats.nfs4_opcount[opnum]++; |
728 | } | 774 | } |
729 | 775 | ||
776 | static void cstate_free(struct nfsd4_compound_state *cstate) | ||
777 | { | ||
778 | if (cstate == NULL) | ||
779 | return; | ||
780 | fh_put(&cstate->current_fh); | ||
781 | fh_put(&cstate->save_fh); | ||
782 | BUG_ON(cstate->replay_owner); | ||
783 | kfree(cstate); | ||
784 | } | ||
785 | |||
786 | static struct nfsd4_compound_state *cstate_alloc(void) | ||
787 | { | ||
788 | struct nfsd4_compound_state *cstate; | ||
789 | |||
790 | cstate = kmalloc(sizeof(struct nfsd4_compound_state), GFP_KERNEL); | ||
791 | if (cstate == NULL) | ||
792 | return NULL; | ||
793 | fh_init(&cstate->current_fh, NFS4_FHSIZE); | ||
794 | fh_init(&cstate->save_fh, NFS4_FHSIZE); | ||
795 | cstate->replay_owner = NULL; | ||
796 | return cstate; | ||
797 | } | ||
798 | |||
799 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, | ||
800 | void *); | ||
801 | |||
802 | struct nfsd4_operation { | ||
803 | nfsd4op_func op_func; | ||
804 | u32 op_flags; | ||
805 | /* Most ops require a valid current filehandle; a few don't: */ | ||
806 | #define ALLOWED_WITHOUT_FH 1 | ||
807 | /* GETATTR and ops not listed as returning NFS4ERR_MOVED: */ | ||
808 | #define ALLOWED_ON_ABSENT_FS 2 | ||
809 | }; | ||
810 | |||
811 | static struct nfsd4_operation nfsd4_ops[]; | ||
730 | 812 | ||
731 | /* | 813 | /* |
732 | * COMPOUND call. | 814 | * COMPOUND call. |
@@ -737,21 +819,15 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
737 | struct nfsd4_compoundres *resp) | 819 | struct nfsd4_compoundres *resp) |
738 | { | 820 | { |
739 | struct nfsd4_op *op; | 821 | struct nfsd4_op *op; |
740 | struct svc_fh *current_fh = NULL; | 822 | struct nfsd4_operation *opdesc; |
741 | struct svc_fh *save_fh = NULL; | 823 | struct nfsd4_compound_state *cstate = NULL; |
742 | struct nfs4_stateowner *replay_owner = NULL; | 824 | int slack_bytes; |
743 | int slack_space; /* in words, not bytes! */ | ||
744 | __be32 status; | 825 | __be32 status; |
745 | 826 | ||
746 | status = nfserr_resource; | 827 | status = nfserr_resource; |
747 | current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL); | 828 | cstate = cstate_alloc(); |
748 | if (current_fh == NULL) | 829 | if (cstate == NULL) |
749 | goto out; | ||
750 | fh_init(current_fh, NFS4_FHSIZE); | ||
751 | save_fh = kmalloc(sizeof(*save_fh), GFP_KERNEL); | ||
752 | if (save_fh == NULL) | ||
753 | goto out; | 830 | goto out; |
754 | fh_init(save_fh, NFS4_FHSIZE); | ||
755 | 831 | ||
756 | resp->xbuf = &rqstp->rq_res; | 832 | resp->xbuf = &rqstp->rq_res; |
757 | resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; | 833 | resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; |
@@ -790,164 +866,44 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
790 | * failed response to the next operation. If we don't | 866 | * failed response to the next operation. If we don't |
791 | * have enough room, fail with ERR_RESOURCE. | 867 | * have enough room, fail with ERR_RESOURCE. |
792 | */ | 868 | */ |
793 | /* FIXME - is slack_space *really* words, or bytes??? - neilb */ | 869 | slack_bytes = (char *)resp->end - (char *)resp->p; |
794 | slack_space = (char *)resp->end - (char *)resp->p; | 870 | if (slack_bytes < COMPOUND_SLACK_SPACE |
795 | if (slack_space < COMPOUND_SLACK_SPACE + COMPOUND_ERR_SLACK_SPACE) { | 871 | + COMPOUND_ERR_SLACK_SPACE) { |
796 | BUG_ON(slack_space < COMPOUND_ERR_SLACK_SPACE); | 872 | BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE); |
797 | op->status = nfserr_resource; | 873 | op->status = nfserr_resource; |
798 | goto encode_op; | 874 | goto encode_op; |
799 | } | 875 | } |
800 | 876 | ||
801 | /* All operations except RENEW, SETCLIENTID, RESTOREFH | 877 | opdesc = &nfsd4_ops[op->opnum]; |
802 | * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH | 878 | |
803 | * require a valid current filehandle | 879 | if (!cstate->current_fh.fh_dentry) { |
804 | */ | 880 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { |
805 | if (!current_fh->fh_dentry) { | ||
806 | if (!((op->opnum == OP_PUTFH) || | ||
807 | (op->opnum == OP_PUTROOTFH) || | ||
808 | (op->opnum == OP_SETCLIENTID) || | ||
809 | (op->opnum == OP_SETCLIENTID_CONFIRM) || | ||
810 | (op->opnum == OP_RENEW) || | ||
811 | (op->opnum == OP_RESTOREFH) || | ||
812 | (op->opnum == OP_RELEASE_LOCKOWNER))) { | ||
813 | op->status = nfserr_nofilehandle; | 881 | op->status = nfserr_nofilehandle; |
814 | goto encode_op; | 882 | goto encode_op; |
815 | } | 883 | } |
816 | } | 884 | } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && |
817 | /* Check must be done at start of each operation, except | 885 | !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { |
818 | * for GETATTR and ops not listed as returning NFS4ERR_MOVED | ||
819 | */ | ||
820 | else if (current_fh->fh_export->ex_fslocs.migrated && | ||
821 | !((op->opnum == OP_GETATTR) || | ||
822 | (op->opnum == OP_PUTROOTFH) || | ||
823 | (op->opnum == OP_PUTPUBFH) || | ||
824 | (op->opnum == OP_RENEW) || | ||
825 | (op->opnum == OP_SETCLIENTID) || | ||
826 | (op->opnum == OP_RELEASE_LOCKOWNER))) { | ||
827 | op->status = nfserr_moved; | 886 | op->status = nfserr_moved; |
828 | goto encode_op; | 887 | goto encode_op; |
829 | } | 888 | } |
830 | switch (op->opnum) { | 889 | |
831 | case OP_ACCESS: | 890 | if (opdesc->op_func) |
832 | op->status = nfsd4_access(rqstp, current_fh, &op->u.access); | 891 | op->status = opdesc->op_func(rqstp, cstate, &op->u); |
833 | break; | 892 | else |
834 | case OP_CLOSE: | ||
835 | op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner); | ||
836 | break; | ||
837 | case OP_COMMIT: | ||
838 | op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit); | ||
839 | break; | ||
840 | case OP_CREATE: | ||
841 | op->status = nfsd4_create(rqstp, current_fh, &op->u.create); | ||
842 | break; | ||
843 | case OP_DELEGRETURN: | ||
844 | op->status = nfsd4_delegreturn(rqstp, current_fh, &op->u.delegreturn); | ||
845 | break; | ||
846 | case OP_GETATTR: | ||
847 | op->status = nfsd4_getattr(rqstp, current_fh, &op->u.getattr); | ||
848 | break; | ||
849 | case OP_GETFH: | ||
850 | op->status = nfsd4_getfh(current_fh, &op->u.getfh); | ||
851 | break; | ||
852 | case OP_LINK: | ||
853 | op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); | ||
854 | break; | ||
855 | case OP_LOCK: | ||
856 | op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner); | ||
857 | break; | ||
858 | case OP_LOCKT: | ||
859 | op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt); | ||
860 | break; | ||
861 | case OP_LOCKU: | ||
862 | op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner); | ||
863 | break; | ||
864 | case OP_LOOKUP: | ||
865 | op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup); | ||
866 | break; | ||
867 | case OP_LOOKUPP: | ||
868 | op->status = nfsd4_lookupp(rqstp, current_fh); | ||
869 | break; | ||
870 | case OP_NVERIFY: | ||
871 | op->status = nfsd4_verify(rqstp, current_fh, &op->u.nverify); | ||
872 | if (op->status == nfserr_not_same) | ||
873 | op->status = nfs_ok; | ||
874 | break; | ||
875 | case OP_OPEN: | ||
876 | op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner); | ||
877 | break; | ||
878 | case OP_OPEN_CONFIRM: | ||
879 | op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner); | ||
880 | break; | ||
881 | case OP_OPEN_DOWNGRADE: | ||
882 | op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner); | ||
883 | break; | ||
884 | case OP_PUTFH: | ||
885 | op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh); | ||
886 | break; | ||
887 | case OP_PUTROOTFH: | ||
888 | op->status = nfsd4_putrootfh(rqstp, current_fh); | ||
889 | break; | ||
890 | case OP_READ: | ||
891 | op->status = nfsd4_read(rqstp, current_fh, &op->u.read); | ||
892 | break; | ||
893 | case OP_READDIR: | ||
894 | op->status = nfsd4_readdir(rqstp, current_fh, &op->u.readdir); | ||
895 | break; | ||
896 | case OP_READLINK: | ||
897 | op->status = nfsd4_readlink(rqstp, current_fh, &op->u.readlink); | ||
898 | break; | ||
899 | case OP_REMOVE: | ||
900 | op->status = nfsd4_remove(rqstp, current_fh, &op->u.remove); | ||
901 | break; | ||
902 | case OP_RENAME: | ||
903 | op->status = nfsd4_rename(rqstp, current_fh, save_fh, &op->u.rename); | ||
904 | break; | ||
905 | case OP_RENEW: | ||
906 | op->status = nfsd4_renew(&op->u.renew); | ||
907 | break; | ||
908 | case OP_RESTOREFH: | ||
909 | op->status = nfsd4_restorefh(current_fh, save_fh); | ||
910 | break; | ||
911 | case OP_SAVEFH: | ||
912 | op->status = nfsd4_savefh(current_fh, save_fh); | ||
913 | break; | ||
914 | case OP_SETATTR: | ||
915 | op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr); | ||
916 | break; | ||
917 | case OP_SETCLIENTID: | ||
918 | op->status = nfsd4_setclientid(rqstp, &op->u.setclientid); | ||
919 | break; | ||
920 | case OP_SETCLIENTID_CONFIRM: | ||
921 | op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm); | ||
922 | break; | ||
923 | case OP_VERIFY: | ||
924 | op->status = nfsd4_verify(rqstp, current_fh, &op->u.verify); | ||
925 | if (op->status == nfserr_same) | ||
926 | op->status = nfs_ok; | ||
927 | break; | ||
928 | case OP_WRITE: | ||
929 | op->status = nfsd4_write(rqstp, current_fh, &op->u.write); | ||
930 | break; | ||
931 | case OP_RELEASE_LOCKOWNER: | ||
932 | op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner); | ||
933 | break; | ||
934 | default: | ||
935 | BUG_ON(op->status == nfs_ok); | 893 | BUG_ON(op->status == nfs_ok); |
936 | break; | ||
937 | } | ||
938 | 894 | ||
939 | encode_op: | 895 | encode_op: |
940 | if (op->status == nfserr_replay_me) { | 896 | if (op->status == nfserr_replay_me) { |
941 | op->replay = &replay_owner->so_replay; | 897 | op->replay = &cstate->replay_owner->so_replay; |
942 | nfsd4_encode_replay(resp, op); | 898 | nfsd4_encode_replay(resp, op); |
943 | status = op->status = op->replay->rp_status; | 899 | status = op->status = op->replay->rp_status; |
944 | } else { | 900 | } else { |
945 | nfsd4_encode_operation(resp, op); | 901 | nfsd4_encode_operation(resp, op); |
946 | status = op->status; | 902 | status = op->status; |
947 | } | 903 | } |
948 | if (replay_owner && (replay_owner != (void *)(-1))) { | 904 | if (cstate->replay_owner) { |
949 | nfs4_put_stateowner(replay_owner); | 905 | nfs4_put_stateowner(cstate->replay_owner); |
950 | replay_owner = NULL; | 906 | cstate->replay_owner = NULL; |
951 | } | 907 | } |
952 | /* XXX Ugh, we need to get rid of this kind of special case: */ | 908 | /* XXX Ugh, we need to get rid of this kind of special case: */ |
953 | if (op->opnum == OP_READ && op->u.read.rd_filp) | 909 | if (op->opnum == OP_READ && op->u.read.rd_filp) |
@@ -958,15 +914,124 @@ encode_op: | |||
958 | 914 | ||
959 | out: | 915 | out: |
960 | nfsd4_release_compoundargs(args); | 916 | nfsd4_release_compoundargs(args); |
961 | if (current_fh) | 917 | cstate_free(cstate); |
962 | fh_put(current_fh); | ||
963 | kfree(current_fh); | ||
964 | if (save_fh) | ||
965 | fh_put(save_fh); | ||
966 | kfree(save_fh); | ||
967 | return status; | 918 | return status; |
968 | } | 919 | } |
969 | 920 | ||
921 | static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { | ||
922 | [OP_ACCESS] = { | ||
923 | .op_func = (nfsd4op_func)nfsd4_access, | ||
924 | }, | ||
925 | [OP_CLOSE] = { | ||
926 | .op_func = (nfsd4op_func)nfsd4_close, | ||
927 | }, | ||
928 | [OP_COMMIT] = { | ||
929 | .op_func = (nfsd4op_func)nfsd4_commit, | ||
930 | }, | ||
931 | [OP_CREATE] = { | ||
932 | .op_func = (nfsd4op_func)nfsd4_create, | ||
933 | }, | ||
934 | [OP_DELEGRETURN] = { | ||
935 | .op_func = (nfsd4op_func)nfsd4_delegreturn, | ||
936 | }, | ||
937 | [OP_GETATTR] = { | ||
938 | .op_func = (nfsd4op_func)nfsd4_getattr, | ||
939 | .op_flags = ALLOWED_ON_ABSENT_FS, | ||
940 | }, | ||
941 | [OP_GETFH] = { | ||
942 | .op_func = (nfsd4op_func)nfsd4_getfh, | ||
943 | }, | ||
944 | [OP_LINK] = { | ||
945 | .op_func = (nfsd4op_func)nfsd4_link, | ||
946 | }, | ||
947 | [OP_LOCK] = { | ||
948 | .op_func = (nfsd4op_func)nfsd4_lock, | ||
949 | }, | ||
950 | [OP_LOCKT] = { | ||
951 | .op_func = (nfsd4op_func)nfsd4_lockt, | ||
952 | }, | ||
953 | [OP_LOCKU] = { | ||
954 | .op_func = (nfsd4op_func)nfsd4_locku, | ||
955 | }, | ||
956 | [OP_LOOKUP] = { | ||
957 | .op_func = (nfsd4op_func)nfsd4_lookup, | ||
958 | }, | ||
959 | [OP_LOOKUPP] = { | ||
960 | .op_func = (nfsd4op_func)nfsd4_lookupp, | ||
961 | }, | ||
962 | [OP_NVERIFY] = { | ||
963 | .op_func = (nfsd4op_func)nfsd4_nverify, | ||
964 | }, | ||
965 | [OP_OPEN] = { | ||
966 | .op_func = (nfsd4op_func)nfsd4_open, | ||
967 | }, | ||
968 | [OP_OPEN_CONFIRM] = { | ||
969 | .op_func = (nfsd4op_func)nfsd4_open_confirm, | ||
970 | }, | ||
971 | [OP_OPEN_DOWNGRADE] = { | ||
972 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, | ||
973 | }, | ||
974 | [OP_PUTFH] = { | ||
975 | .op_func = (nfsd4op_func)nfsd4_putfh, | ||
976 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | ||
977 | }, | ||
978 | [OP_PUTPUBFH] = { | ||
979 | /* unsupported; just for future reference: */ | ||
980 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | ||
981 | }, | ||
982 | [OP_PUTROOTFH] = { | ||
983 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | ||
984 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | ||
985 | }, | ||
986 | [OP_READ] = { | ||
987 | .op_func = (nfsd4op_func)nfsd4_read, | ||
988 | }, | ||
989 | [OP_READDIR] = { | ||
990 | .op_func = (nfsd4op_func)nfsd4_readdir, | ||
991 | }, | ||
992 | [OP_READLINK] = { | ||
993 | .op_func = (nfsd4op_func)nfsd4_readlink, | ||
994 | }, | ||
995 | [OP_REMOVE] = { | ||
996 | .op_func = (nfsd4op_func)nfsd4_remove, | ||
997 | }, | ||
998 | [OP_RENAME] = { | ||
999 | .op_func = (nfsd4op_func)nfsd4_rename, | ||
1000 | }, | ||
1001 | [OP_RENEW] = { | ||
1002 | .op_func = (nfsd4op_func)nfsd4_renew, | ||
1003 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | ||
1004 | }, | ||
1005 | [OP_RESTOREFH] = { | ||
1006 | .op_func = (nfsd4op_func)nfsd4_restorefh, | ||
1007 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | ||
1008 | }, | ||
1009 | [OP_SAVEFH] = { | ||
1010 | .op_func = (nfsd4op_func)nfsd4_savefh, | ||
1011 | }, | ||
1012 | [OP_SETATTR] = { | ||
1013 | .op_func = (nfsd4op_func)nfsd4_setattr, | ||
1014 | }, | ||
1015 | [OP_SETCLIENTID] = { | ||
1016 | .op_func = (nfsd4op_func)nfsd4_setclientid, | ||
1017 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | ||
1018 | }, | ||
1019 | [OP_SETCLIENTID_CONFIRM] = { | ||
1020 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, | ||
1021 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | ||
1022 | }, | ||
1023 | [OP_VERIFY] = { | ||
1024 | .op_func = (nfsd4op_func)nfsd4_verify, | ||
1025 | }, | ||
1026 | [OP_WRITE] = { | ||
1027 | .op_func = (nfsd4op_func)nfsd4_write, | ||
1028 | }, | ||
1029 | [OP_RELEASE_LOCKOWNER] = { | ||
1030 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, | ||
1031 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | ||
1032 | }, | ||
1033 | }; | ||
1034 | |||
970 | #define nfs4svc_decode_voidargs NULL | 1035 | #define nfs4svc_decode_voidargs NULL |
971 | #define nfs4svc_release_void NULL | 1036 | #define nfs4svc_release_void NULL |
972 | #define nfsd4_voidres nfsd4_voidargs | 1037 | #define nfsd4_voidres nfsd4_voidargs |