diff options
Diffstat (limited to 'fs/nfs/nfs3proc.c')
-rw-r--r-- | fs/nfs/nfs3proc.c | 275 |
1 files changed, 144 insertions, 131 deletions
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index c3523ad03ed1..1e750e4574a9 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -129,6 +129,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
129 | int status; | 129 | int status; |
130 | 130 | ||
131 | dprintk("NFS call setattr\n"); | 131 | dprintk("NFS call setattr\n"); |
132 | if (sattr->ia_valid & ATTR_FILE) | ||
133 | msg.rpc_cred = nfs_file_cred(sattr->ia_file); | ||
132 | nfs_fattr_init(fattr); | 134 | nfs_fattr_init(fattr); |
133 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 135 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
134 | if (status == 0) | 136 | if (status == 0) |
@@ -248,6 +250,53 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, | |||
248 | return status; | 250 | return status; |
249 | } | 251 | } |
250 | 252 | ||
253 | struct nfs3_createdata { | ||
254 | struct rpc_message msg; | ||
255 | union { | ||
256 | struct nfs3_createargs create; | ||
257 | struct nfs3_mkdirargs mkdir; | ||
258 | struct nfs3_symlinkargs symlink; | ||
259 | struct nfs3_mknodargs mknod; | ||
260 | } arg; | ||
261 | struct nfs3_diropres res; | ||
262 | struct nfs_fh fh; | ||
263 | struct nfs_fattr fattr; | ||
264 | struct nfs_fattr dir_attr; | ||
265 | }; | ||
266 | |||
267 | static struct nfs3_createdata *nfs3_alloc_createdata(void) | ||
268 | { | ||
269 | struct nfs3_createdata *data; | ||
270 | |||
271 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
272 | if (data != NULL) { | ||
273 | data->msg.rpc_argp = &data->arg; | ||
274 | data->msg.rpc_resp = &data->res; | ||
275 | data->res.fh = &data->fh; | ||
276 | data->res.fattr = &data->fattr; | ||
277 | data->res.dir_attr = &data->dir_attr; | ||
278 | nfs_fattr_init(data->res.fattr); | ||
279 | nfs_fattr_init(data->res.dir_attr); | ||
280 | } | ||
281 | return data; | ||
282 | } | ||
283 | |||
284 | static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_createdata *data) | ||
285 | { | ||
286 | int status; | ||
287 | |||
288 | status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | ||
289 | nfs_post_op_update_inode(dir, data->res.dir_attr); | ||
290 | if (status == 0) | ||
291 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); | ||
292 | return status; | ||
293 | } | ||
294 | |||
295 | static void nfs3_free_createdata(struct nfs3_createdata *data) | ||
296 | { | ||
297 | kfree(data); | ||
298 | } | ||
299 | |||
251 | /* | 300 | /* |
252 | * Create a regular file. | 301 | * Create a regular file. |
253 | * For now, we don't implement O_EXCL. | 302 | * For now, we don't implement O_EXCL. |
@@ -256,70 +305,60 @@ static int | |||
256 | nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 305 | nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
257 | int flags, struct nameidata *nd) | 306 | int flags, struct nameidata *nd) |
258 | { | 307 | { |
259 | struct nfs_fh fhandle; | 308 | struct nfs3_createdata *data; |
260 | struct nfs_fattr fattr; | ||
261 | struct nfs_fattr dir_attr; | ||
262 | struct nfs3_createargs arg = { | ||
263 | .fh = NFS_FH(dir), | ||
264 | .name = dentry->d_name.name, | ||
265 | .len = dentry->d_name.len, | ||
266 | .sattr = sattr, | ||
267 | }; | ||
268 | struct nfs3_diropres res = { | ||
269 | .dir_attr = &dir_attr, | ||
270 | .fh = &fhandle, | ||
271 | .fattr = &fattr | ||
272 | }; | ||
273 | struct rpc_message msg = { | ||
274 | .rpc_proc = &nfs3_procedures[NFS3PROC_CREATE], | ||
275 | .rpc_argp = &arg, | ||
276 | .rpc_resp = &res, | ||
277 | }; | ||
278 | mode_t mode = sattr->ia_mode; | 309 | mode_t mode = sattr->ia_mode; |
279 | int status; | 310 | int status = -ENOMEM; |
280 | 311 | ||
281 | dprintk("NFS call create %s\n", dentry->d_name.name); | 312 | dprintk("NFS call create %s\n", dentry->d_name.name); |
282 | arg.createmode = NFS3_CREATE_UNCHECKED; | 313 | |
314 | data = nfs3_alloc_createdata(); | ||
315 | if (data == NULL) | ||
316 | goto out; | ||
317 | |||
318 | data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE]; | ||
319 | data->arg.create.fh = NFS_FH(dir); | ||
320 | data->arg.create.name = dentry->d_name.name; | ||
321 | data->arg.create.len = dentry->d_name.len; | ||
322 | data->arg.create.sattr = sattr; | ||
323 | |||
324 | data->arg.create.createmode = NFS3_CREATE_UNCHECKED; | ||
283 | if (flags & O_EXCL) { | 325 | if (flags & O_EXCL) { |
284 | arg.createmode = NFS3_CREATE_EXCLUSIVE; | 326 | data->arg.create.createmode = NFS3_CREATE_EXCLUSIVE; |
285 | arg.verifier[0] = jiffies; | 327 | data->arg.create.verifier[0] = jiffies; |
286 | arg.verifier[1] = current->pid; | 328 | data->arg.create.verifier[1] = current->pid; |
287 | } | 329 | } |
288 | 330 | ||
289 | sattr->ia_mode &= ~current->fs->umask; | 331 | sattr->ia_mode &= ~current->fs->umask; |
290 | 332 | ||
291 | again: | 333 | for (;;) { |
292 | nfs_fattr_init(&dir_attr); | 334 | status = nfs3_do_create(dir, dentry, data); |
293 | nfs_fattr_init(&fattr); | ||
294 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | ||
295 | nfs_refresh_inode(dir, &dir_attr); | ||
296 | 335 | ||
297 | /* If the server doesn't support the exclusive creation semantics, | 336 | if (status != -ENOTSUPP) |
298 | * try again with simple 'guarded' mode. */ | 337 | break; |
299 | if (status == -ENOTSUPP) { | 338 | /* If the server doesn't support the exclusive creation |
300 | switch (arg.createmode) { | 339 | * semantics, try again with simple 'guarded' mode. */ |
340 | switch (data->arg.create.createmode) { | ||
301 | case NFS3_CREATE_EXCLUSIVE: | 341 | case NFS3_CREATE_EXCLUSIVE: |
302 | arg.createmode = NFS3_CREATE_GUARDED; | 342 | data->arg.create.createmode = NFS3_CREATE_GUARDED; |
303 | break; | 343 | break; |
304 | 344 | ||
305 | case NFS3_CREATE_GUARDED: | 345 | case NFS3_CREATE_GUARDED: |
306 | arg.createmode = NFS3_CREATE_UNCHECKED; | 346 | data->arg.create.createmode = NFS3_CREATE_UNCHECKED; |
307 | break; | 347 | break; |
308 | 348 | ||
309 | case NFS3_CREATE_UNCHECKED: | 349 | case NFS3_CREATE_UNCHECKED: |
310 | goto out; | 350 | goto out; |
311 | } | 351 | } |
312 | goto again; | 352 | nfs_fattr_init(data->res.dir_attr); |
353 | nfs_fattr_init(data->res.fattr); | ||
313 | } | 354 | } |
314 | 355 | ||
315 | if (status == 0) | ||
316 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
317 | if (status != 0) | 356 | if (status != 0) |
318 | goto out; | 357 | goto out; |
319 | 358 | ||
320 | /* When we created the file with exclusive semantics, make | 359 | /* When we created the file with exclusive semantics, make |
321 | * sure we set the attributes afterwards. */ | 360 | * sure we set the attributes afterwards. */ |
322 | if (arg.createmode == NFS3_CREATE_EXCLUSIVE) { | 361 | if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) { |
323 | dprintk("NFS call setattr (post-create)\n"); | 362 | dprintk("NFS call setattr (post-create)\n"); |
324 | 363 | ||
325 | if (!(sattr->ia_valid & ATTR_ATIME_SET)) | 364 | if (!(sattr->ia_valid & ATTR_ATIME_SET)) |
@@ -330,14 +369,15 @@ again: | |||
330 | /* Note: we could use a guarded setattr here, but I'm | 369 | /* Note: we could use a guarded setattr here, but I'm |
331 | * not sure this buys us anything (and I'd have | 370 | * not sure this buys us anything (and I'd have |
332 | * to revamp the NFSv3 XDR code) */ | 371 | * to revamp the NFSv3 XDR code) */ |
333 | status = nfs3_proc_setattr(dentry, &fattr, sattr); | 372 | status = nfs3_proc_setattr(dentry, data->res.fattr, sattr); |
334 | nfs_post_op_update_inode(dentry->d_inode, &fattr); | 373 | nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); |
335 | dprintk("NFS reply setattr (post-create): %d\n", status); | 374 | dprintk("NFS reply setattr (post-create): %d\n", status); |
375 | if (status != 0) | ||
376 | goto out; | ||
336 | } | 377 | } |
337 | if (status != 0) | ||
338 | goto out; | ||
339 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | 378 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); |
340 | out: | 379 | out: |
380 | nfs3_free_createdata(data); | ||
341 | dprintk("NFS reply create: %d\n", status); | 381 | dprintk("NFS reply create: %d\n", status); |
342 | return status; | 382 | return status; |
343 | } | 383 | } |
@@ -452,40 +492,28 @@ static int | |||
452 | nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | 492 | nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, |
453 | unsigned int len, struct iattr *sattr) | 493 | unsigned int len, struct iattr *sattr) |
454 | { | 494 | { |
455 | struct nfs_fh fhandle; | 495 | struct nfs3_createdata *data; |
456 | struct nfs_fattr fattr, dir_attr; | 496 | int status = -ENOMEM; |
457 | struct nfs3_symlinkargs arg = { | ||
458 | .fromfh = NFS_FH(dir), | ||
459 | .fromname = dentry->d_name.name, | ||
460 | .fromlen = dentry->d_name.len, | ||
461 | .pages = &page, | ||
462 | .pathlen = len, | ||
463 | .sattr = sattr | ||
464 | }; | ||
465 | struct nfs3_diropres res = { | ||
466 | .dir_attr = &dir_attr, | ||
467 | .fh = &fhandle, | ||
468 | .fattr = &fattr | ||
469 | }; | ||
470 | struct rpc_message msg = { | ||
471 | .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], | ||
472 | .rpc_argp = &arg, | ||
473 | .rpc_resp = &res, | ||
474 | }; | ||
475 | int status; | ||
476 | 497 | ||
477 | if (len > NFS3_MAXPATHLEN) | 498 | if (len > NFS3_MAXPATHLEN) |
478 | return -ENAMETOOLONG; | 499 | return -ENAMETOOLONG; |
479 | 500 | ||
480 | dprintk("NFS call symlink %s\n", dentry->d_name.name); | 501 | dprintk("NFS call symlink %s\n", dentry->d_name.name); |
481 | 502 | ||
482 | nfs_fattr_init(&dir_attr); | 503 | data = nfs3_alloc_createdata(); |
483 | nfs_fattr_init(&fattr); | 504 | if (data == NULL) |
484 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | ||
485 | nfs_post_op_update_inode(dir, &dir_attr); | ||
486 | if (status != 0) | ||
487 | goto out; | 505 | goto out; |
488 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 506 | data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK]; |
507 | data->arg.symlink.fromfh = NFS_FH(dir); | ||
508 | data->arg.symlink.fromname = dentry->d_name.name; | ||
509 | data->arg.symlink.fromlen = dentry->d_name.len; | ||
510 | data->arg.symlink.pages = &page; | ||
511 | data->arg.symlink.pathlen = len; | ||
512 | data->arg.symlink.sattr = sattr; | ||
513 | |||
514 | status = nfs3_do_create(dir, dentry, data); | ||
515 | |||
516 | nfs3_free_createdata(data); | ||
489 | out: | 517 | out: |
490 | dprintk("NFS reply symlink: %d\n", status); | 518 | dprintk("NFS reply symlink: %d\n", status); |
491 | return status; | 519 | return status; |
@@ -494,42 +522,31 @@ out: | |||
494 | static int | 522 | static int |
495 | nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | 523 | nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) |
496 | { | 524 | { |
497 | struct nfs_fh fhandle; | 525 | struct nfs3_createdata *data; |
498 | struct nfs_fattr fattr, dir_attr; | ||
499 | struct nfs3_mkdirargs arg = { | ||
500 | .fh = NFS_FH(dir), | ||
501 | .name = dentry->d_name.name, | ||
502 | .len = dentry->d_name.len, | ||
503 | .sattr = sattr | ||
504 | }; | ||
505 | struct nfs3_diropres res = { | ||
506 | .dir_attr = &dir_attr, | ||
507 | .fh = &fhandle, | ||
508 | .fattr = &fattr | ||
509 | }; | ||
510 | struct rpc_message msg = { | ||
511 | .rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR], | ||
512 | .rpc_argp = &arg, | ||
513 | .rpc_resp = &res, | ||
514 | }; | ||
515 | int mode = sattr->ia_mode; | 526 | int mode = sattr->ia_mode; |
516 | int status; | 527 | int status = -ENOMEM; |
517 | 528 | ||
518 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); | 529 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); |
519 | 530 | ||
520 | sattr->ia_mode &= ~current->fs->umask; | 531 | sattr->ia_mode &= ~current->fs->umask; |
521 | 532 | ||
522 | nfs_fattr_init(&dir_attr); | 533 | data = nfs3_alloc_createdata(); |
523 | nfs_fattr_init(&fattr); | 534 | if (data == NULL) |
524 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | ||
525 | nfs_post_op_update_inode(dir, &dir_attr); | ||
526 | if (status != 0) | ||
527 | goto out; | 535 | goto out; |
528 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 536 | |
537 | data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR]; | ||
538 | data->arg.mkdir.fh = NFS_FH(dir); | ||
539 | data->arg.mkdir.name = dentry->d_name.name; | ||
540 | data->arg.mkdir.len = dentry->d_name.len; | ||
541 | data->arg.mkdir.sattr = sattr; | ||
542 | |||
543 | status = nfs3_do_create(dir, dentry, data); | ||
529 | if (status != 0) | 544 | if (status != 0) |
530 | goto out; | 545 | goto out; |
546 | |||
531 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | 547 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); |
532 | out: | 548 | out: |
549 | nfs3_free_createdata(data); | ||
533 | dprintk("NFS reply mkdir: %d\n", status); | 550 | dprintk("NFS reply mkdir: %d\n", status); |
534 | return status; | 551 | return status; |
535 | } | 552 | } |
@@ -615,52 +632,50 @@ static int | |||
615 | nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 632 | nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
616 | dev_t rdev) | 633 | dev_t rdev) |
617 | { | 634 | { |
618 | struct nfs_fh fh; | 635 | struct nfs3_createdata *data; |
619 | struct nfs_fattr fattr, dir_attr; | ||
620 | struct nfs3_mknodargs arg = { | ||
621 | .fh = NFS_FH(dir), | ||
622 | .name = dentry->d_name.name, | ||
623 | .len = dentry->d_name.len, | ||
624 | .sattr = sattr, | ||
625 | .rdev = rdev | ||
626 | }; | ||
627 | struct nfs3_diropres res = { | ||
628 | .dir_attr = &dir_attr, | ||
629 | .fh = &fh, | ||
630 | .fattr = &fattr | ||
631 | }; | ||
632 | struct rpc_message msg = { | ||
633 | .rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD], | ||
634 | .rpc_argp = &arg, | ||
635 | .rpc_resp = &res, | ||
636 | }; | ||
637 | mode_t mode = sattr->ia_mode; | 636 | mode_t mode = sattr->ia_mode; |
638 | int status; | 637 | int status = -ENOMEM; |
639 | |||
640 | switch (sattr->ia_mode & S_IFMT) { | ||
641 | case S_IFBLK: arg.type = NF3BLK; break; | ||
642 | case S_IFCHR: arg.type = NF3CHR; break; | ||
643 | case S_IFIFO: arg.type = NF3FIFO; break; | ||
644 | case S_IFSOCK: arg.type = NF3SOCK; break; | ||
645 | default: return -EINVAL; | ||
646 | } | ||
647 | 638 | ||
648 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, | 639 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, |
649 | MAJOR(rdev), MINOR(rdev)); | 640 | MAJOR(rdev), MINOR(rdev)); |
650 | 641 | ||
651 | sattr->ia_mode &= ~current->fs->umask; | 642 | sattr->ia_mode &= ~current->fs->umask; |
652 | 643 | ||
653 | nfs_fattr_init(&dir_attr); | 644 | data = nfs3_alloc_createdata(); |
654 | nfs_fattr_init(&fattr); | 645 | if (data == NULL) |
655 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | ||
656 | nfs_post_op_update_inode(dir, &dir_attr); | ||
657 | if (status != 0) | ||
658 | goto out; | 646 | goto out; |
659 | status = nfs_instantiate(dentry, &fh, &fattr); | 647 | |
648 | data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD]; | ||
649 | data->arg.mknod.fh = NFS_FH(dir); | ||
650 | data->arg.mknod.name = dentry->d_name.name; | ||
651 | data->arg.mknod.len = dentry->d_name.len; | ||
652 | data->arg.mknod.sattr = sattr; | ||
653 | data->arg.mknod.rdev = rdev; | ||
654 | |||
655 | switch (sattr->ia_mode & S_IFMT) { | ||
656 | case S_IFBLK: | ||
657 | data->arg.mknod.type = NF3BLK; | ||
658 | break; | ||
659 | case S_IFCHR: | ||
660 | data->arg.mknod.type = NF3CHR; | ||
661 | break; | ||
662 | case S_IFIFO: | ||
663 | data->arg.mknod.type = NF3FIFO; | ||
664 | break; | ||
665 | case S_IFSOCK: | ||
666 | data->arg.mknod.type = NF3SOCK; | ||
667 | break; | ||
668 | default: | ||
669 | status = -EINVAL; | ||
670 | goto out; | ||
671 | } | ||
672 | |||
673 | status = nfs3_do_create(dir, dentry, data); | ||
660 | if (status != 0) | 674 | if (status != 0) |
661 | goto out; | 675 | goto out; |
662 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | 676 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); |
663 | out: | 677 | out: |
678 | nfs3_free_createdata(data); | ||
664 | dprintk("NFS reply mknod: %d\n", status); | 679 | dprintk("NFS reply mknod: %d\n", status); |
665 | return status; | 680 | return status; |
666 | } | 681 | } |
@@ -801,8 +816,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
801 | .write_done = nfs3_write_done, | 816 | .write_done = nfs3_write_done, |
802 | .commit_setup = nfs3_proc_commit_setup, | 817 | .commit_setup = nfs3_proc_commit_setup, |
803 | .commit_done = nfs3_commit_done, | 818 | .commit_done = nfs3_commit_done, |
804 | .file_open = nfs_open, | ||
805 | .file_release = nfs_release, | ||
806 | .lock = nfs3_proc_lock, | 819 | .lock = nfs3_proc_lock, |
807 | .clear_acl_cache = nfs3_forget_cached_acls, | 820 | .clear_acl_cache = nfs3_forget_cached_acls, |
808 | }; | 821 | }; |