aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-06-20 17:00:23 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-07-09 12:08:38 -0400
commit0b4aae7aad162ad175ba8a65708332f888066b26 (patch)
treecae60e1ff20f52cea8785a37a6ca9dfeb5cf1784
parent57dc9a5747942f131a1a8b36d661fec6e6a5e9f6 (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.c271
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
251struct 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
265static 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
282static 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
293static 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
256nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, 303nfs3_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
291again: 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);
340out: 377out:
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
452nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, 490nfs3_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);
489out: 515out:
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:
494static int 520static int
495nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) 521nfs3_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);
532out: 546out:
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
615nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, 630nfs3_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);
663out: 675out:
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}