diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-06-20 17:00:23 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-07-09 12:08:38 -0400 |
commit | 0b4aae7aad162ad175ba8a65708332f888066b26 (patch) | |
tree | cae60e1ff20f52cea8785a37a6ca9dfeb5cf1784 | |
parent | 57dc9a5747942f131a1a8b36d661fec6e6a5e9f6 (diff) |
NFS: Reduce the stack usage in NFSv3 create operations
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs3proc.c | 271 |
1 files changed, 142 insertions, 129 deletions
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index c3523ad03ed1..cf7d4e5927d6 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -248,6 +248,53 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, | |||
248 | return status; | 248 | return status; |
249 | } | 249 | } |
250 | 250 | ||
251 | struct nfs3_createdata { | ||
252 | struct rpc_message msg; | ||
253 | union { | ||
254 | struct nfs3_createargs create; | ||
255 | struct nfs3_mkdirargs mkdir; | ||
256 | struct nfs3_symlinkargs symlink; | ||
257 | struct nfs3_mknodargs mknod; | ||
258 | } arg; | ||
259 | struct nfs3_diropres res; | ||
260 | struct nfs_fh fh; | ||
261 | struct nfs_fattr fattr; | ||
262 | struct nfs_fattr dir_attr; | ||
263 | }; | ||
264 | |||
265 | static struct nfs3_createdata *nfs3_alloc_createdata(void) | ||
266 | { | ||
267 | struct nfs3_createdata *data; | ||
268 | |||
269 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
270 | if (data != NULL) { | ||
271 | data->msg.rpc_argp = &data->arg; | ||
272 | data->msg.rpc_resp = &data->res; | ||
273 | data->res.fh = &data->fh; | ||
274 | data->res.fattr = &data->fattr; | ||
275 | data->res.dir_attr = &data->dir_attr; | ||
276 | nfs_fattr_init(data->res.fattr); | ||
277 | nfs_fattr_init(data->res.dir_attr); | ||
278 | } | ||
279 | return data; | ||
280 | } | ||
281 | |||
282 | static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_createdata *data) | ||
283 | { | ||
284 | int status; | ||
285 | |||
286 | status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | ||
287 | nfs_post_op_update_inode(dir, data->res.dir_attr); | ||
288 | if (status == 0) | ||
289 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); | ||
290 | return status; | ||
291 | } | ||
292 | |||
293 | static void nfs3_free_createdata(struct nfs3_createdata *data) | ||
294 | { | ||
295 | kfree(data); | ||
296 | } | ||
297 | |||
251 | /* | 298 | /* |
252 | * Create a regular file. | 299 | * Create a regular file. |
253 | * For now, we don't implement O_EXCL. | 300 | * For now, we don't implement O_EXCL. |
@@ -256,70 +303,60 @@ static int | |||
256 | nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 303 | nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
257 | int flags, struct nameidata *nd) | 304 | int flags, struct nameidata *nd) |
258 | { | 305 | { |
259 | struct nfs_fh fhandle; | 306 | 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; | 307 | mode_t mode = sattr->ia_mode; |
279 | int status; | 308 | int status = -ENOMEM; |
280 | 309 | ||
281 | dprintk("NFS call create %s\n", dentry->d_name.name); | 310 | dprintk("NFS call create %s\n", dentry->d_name.name); |
282 | arg.createmode = NFS3_CREATE_UNCHECKED; | 311 | |
312 | data = nfs3_alloc_createdata(); | ||
313 | if (data == NULL) | ||
314 | goto out; | ||
315 | |||
316 | data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE]; | ||
317 | data->arg.create.fh = NFS_FH(dir); | ||
318 | data->arg.create.name = dentry->d_name.name; | ||
319 | data->arg.create.len = dentry->d_name.len; | ||
320 | data->arg.create.sattr = sattr; | ||
321 | |||
322 | data->arg.create.createmode = NFS3_CREATE_UNCHECKED; | ||
283 | if (flags & O_EXCL) { | 323 | if (flags & O_EXCL) { |
284 | arg.createmode = NFS3_CREATE_EXCLUSIVE; | 324 | data->arg.create.createmode = NFS3_CREATE_EXCLUSIVE; |
285 | arg.verifier[0] = jiffies; | 325 | data->arg.create.verifier[0] = jiffies; |
286 | arg.verifier[1] = current->pid; | 326 | data->arg.create.verifier[1] = current->pid; |
287 | } | 327 | } |
288 | 328 | ||
289 | sattr->ia_mode &= ~current->fs->umask; | 329 | sattr->ia_mode &= ~current->fs->umask; |
290 | 330 | ||
291 | again: | 331 | for (;;) { |
292 | nfs_fattr_init(&dir_attr); | 332 | 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 | 333 | ||
297 | /* If the server doesn't support the exclusive creation semantics, | 334 | if (status != -ENOTSUPP) |
298 | * try again with simple 'guarded' mode. */ | 335 | break; |
299 | if (status == -ENOTSUPP) { | 336 | /* If the server doesn't support the exclusive creation |
300 | switch (arg.createmode) { | 337 | * semantics, try again with simple 'guarded' mode. */ |
338 | switch (data->arg.create.createmode) { | ||
301 | case NFS3_CREATE_EXCLUSIVE: | 339 | case NFS3_CREATE_EXCLUSIVE: |
302 | arg.createmode = NFS3_CREATE_GUARDED; | 340 | data->arg.create.createmode = NFS3_CREATE_GUARDED; |
303 | break; | 341 | break; |
304 | 342 | ||
305 | case NFS3_CREATE_GUARDED: | 343 | case NFS3_CREATE_GUARDED: |
306 | arg.createmode = NFS3_CREATE_UNCHECKED; | 344 | data->arg.create.createmode = NFS3_CREATE_UNCHECKED; |
307 | break; | 345 | break; |
308 | 346 | ||
309 | case NFS3_CREATE_UNCHECKED: | 347 | case NFS3_CREATE_UNCHECKED: |
310 | goto out; | 348 | goto out; |
311 | } | 349 | } |
312 | goto again; | 350 | nfs_fattr_init(data->res.dir_attr); |
351 | nfs_fattr_init(data->res.fattr); | ||
313 | } | 352 | } |
314 | 353 | ||
315 | if (status == 0) | ||
316 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
317 | if (status != 0) | 354 | if (status != 0) |
318 | goto out; | 355 | goto out; |
319 | 356 | ||
320 | /* When we created the file with exclusive semantics, make | 357 | /* When we created the file with exclusive semantics, make |
321 | * sure we set the attributes afterwards. */ | 358 | * sure we set the attributes afterwards. */ |
322 | if (arg.createmode == NFS3_CREATE_EXCLUSIVE) { | 359 | if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) { |
323 | dprintk("NFS call setattr (post-create)\n"); | 360 | dprintk("NFS call setattr (post-create)\n"); |
324 | 361 | ||
325 | if (!(sattr->ia_valid & ATTR_ATIME_SET)) | 362 | if (!(sattr->ia_valid & ATTR_ATIME_SET)) |
@@ -330,14 +367,15 @@ again: | |||
330 | /* Note: we could use a guarded setattr here, but I'm | 367 | /* Note: we could use a guarded setattr here, but I'm |
331 | * not sure this buys us anything (and I'd have | 368 | * not sure this buys us anything (and I'd have |
332 | * to revamp the NFSv3 XDR code) */ | 369 | * to revamp the NFSv3 XDR code) */ |
333 | status = nfs3_proc_setattr(dentry, &fattr, sattr); | 370 | status = nfs3_proc_setattr(dentry, data->res.fattr, sattr); |
334 | nfs_post_op_update_inode(dentry->d_inode, &fattr); | 371 | nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); |
335 | dprintk("NFS reply setattr (post-create): %d\n", status); | 372 | dprintk("NFS reply setattr (post-create): %d\n", status); |
373 | if (status != 0) | ||
374 | goto out; | ||
336 | } | 375 | } |
337 | if (status != 0) | ||
338 | goto out; | ||
339 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | 376 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); |
340 | out: | 377 | out: |
378 | nfs3_free_createdata(data); | ||
341 | dprintk("NFS reply create: %d\n", status); | 379 | dprintk("NFS reply create: %d\n", status); |
342 | return status; | 380 | return status; |
343 | } | 381 | } |
@@ -452,40 +490,28 @@ static int | |||
452 | nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | 490 | nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, |
453 | unsigned int len, struct iattr *sattr) | 491 | unsigned int len, struct iattr *sattr) |
454 | { | 492 | { |
455 | struct nfs_fh fhandle; | 493 | struct nfs3_createdata *data; |
456 | struct nfs_fattr fattr, dir_attr; | 494 | 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 | 495 | ||
477 | if (len > NFS3_MAXPATHLEN) | 496 | if (len > NFS3_MAXPATHLEN) |
478 | return -ENAMETOOLONG; | 497 | return -ENAMETOOLONG; |
479 | 498 | ||
480 | dprintk("NFS call symlink %s\n", dentry->d_name.name); | 499 | dprintk("NFS call symlink %s\n", dentry->d_name.name); |
481 | 500 | ||
482 | nfs_fattr_init(&dir_attr); | 501 | data = nfs3_alloc_createdata(); |
483 | nfs_fattr_init(&fattr); | 502 | 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; | 503 | goto out; |
488 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 504 | data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK]; |
505 | data->arg.symlink.fromfh = NFS_FH(dir); | ||
506 | data->arg.symlink.fromname = dentry->d_name.name; | ||
507 | data->arg.symlink.fromlen = dentry->d_name.len; | ||
508 | data->arg.symlink.pages = &page; | ||
509 | data->arg.symlink.pathlen = len; | ||
510 | data->arg.symlink.sattr = sattr; | ||
511 | |||
512 | status = nfs3_do_create(dir, dentry, data); | ||
513 | |||
514 | nfs3_free_createdata(data); | ||
489 | out: | 515 | out: |
490 | dprintk("NFS reply symlink: %d\n", status); | 516 | dprintk("NFS reply symlink: %d\n", status); |
491 | return status; | 517 | return status; |
@@ -494,42 +520,31 @@ out: | |||
494 | static int | 520 | static int |
495 | nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | 521 | nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) |
496 | { | 522 | { |
497 | struct nfs_fh fhandle; | 523 | 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; | 524 | int mode = sattr->ia_mode; |
516 | int status; | 525 | int status = -ENOMEM; |
517 | 526 | ||
518 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); | 527 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); |
519 | 528 | ||
520 | sattr->ia_mode &= ~current->fs->umask; | 529 | sattr->ia_mode &= ~current->fs->umask; |
521 | 530 | ||
522 | nfs_fattr_init(&dir_attr); | 531 | data = nfs3_alloc_createdata(); |
523 | nfs_fattr_init(&fattr); | 532 | 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; | 533 | goto out; |
528 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 534 | |
535 | data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR]; | ||
536 | data->arg.mkdir.fh = NFS_FH(dir); | ||
537 | data->arg.mkdir.name = dentry->d_name.name; | ||
538 | data->arg.mkdir.len = dentry->d_name.len; | ||
539 | data->arg.mkdir.sattr = sattr; | ||
540 | |||
541 | status = nfs3_do_create(dir, dentry, data); | ||
529 | if (status != 0) | 542 | if (status != 0) |
530 | goto out; | 543 | goto out; |
544 | |||
531 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | 545 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); |
532 | out: | 546 | out: |
547 | nfs3_free_createdata(data); | ||
533 | dprintk("NFS reply mkdir: %d\n", status); | 548 | dprintk("NFS reply mkdir: %d\n", status); |
534 | return status; | 549 | return status; |
535 | } | 550 | } |
@@ -615,52 +630,50 @@ static int | |||
615 | nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 630 | nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
616 | dev_t rdev) | 631 | dev_t rdev) |
617 | { | 632 | { |
618 | struct nfs_fh fh; | 633 | 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; | 634 | mode_t mode = sattr->ia_mode; |
638 | int status; | 635 | 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 | 636 | ||
648 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, | 637 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, |
649 | MAJOR(rdev), MINOR(rdev)); | 638 | MAJOR(rdev), MINOR(rdev)); |
650 | 639 | ||
651 | sattr->ia_mode &= ~current->fs->umask; | 640 | sattr->ia_mode &= ~current->fs->umask; |
652 | 641 | ||
653 | nfs_fattr_init(&dir_attr); | 642 | data = nfs3_alloc_createdata(); |
654 | nfs_fattr_init(&fattr); | 643 | 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; | 644 | goto out; |
659 | status = nfs_instantiate(dentry, &fh, &fattr); | 645 | |
646 | data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD]; | ||
647 | data->arg.mknod.fh = NFS_FH(dir); | ||
648 | data->arg.mknod.name = dentry->d_name.name; | ||
649 | data->arg.mknod.len = dentry->d_name.len; | ||
650 | data->arg.mknod.sattr = sattr; | ||
651 | data->arg.mknod.rdev = rdev; | ||
652 | |||
653 | switch (sattr->ia_mode & S_IFMT) { | ||
654 | case S_IFBLK: | ||
655 | data->arg.mknod.type = NF3BLK; | ||
656 | break; | ||
657 | case S_IFCHR: | ||
658 | data->arg.mknod.type = NF3CHR; | ||
659 | break; | ||
660 | case S_IFIFO: | ||
661 | data->arg.mknod.type = NF3FIFO; | ||
662 | break; | ||
663 | case S_IFSOCK: | ||
664 | data->arg.mknod.type = NF3SOCK; | ||
665 | break; | ||
666 | default: | ||
667 | status = -EINVAL; | ||
668 | goto out; | ||
669 | } | ||
670 | |||
671 | status = nfs3_do_create(dir, dentry, data); | ||
660 | if (status != 0) | 672 | if (status != 0) |
661 | goto out; | 673 | goto out; |
662 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | 674 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); |
663 | out: | 675 | out: |
676 | nfs3_free_createdata(data); | ||
664 | dprintk("NFS reply mknod: %d\n", status); | 677 | dprintk("NFS reply mknod: %d\n", status); |
665 | return status; | 678 | return status; |
666 | } | 679 | } |