diff options
Diffstat (limited to 'net/sunrpc/rpc_pipe.c')
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 685 |
1 files changed, 401 insertions, 284 deletions
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9ced0628d69c..7f676bdf70d3 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/sunrpc/clnt.h> | 26 | #include <linux/sunrpc/clnt.h> |
27 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
28 | #include <linux/sunrpc/rpc_pipe_fs.h> | 28 | #include <linux/sunrpc/rpc_pipe_fs.h> |
29 | #include <linux/sunrpc/cache.h> | ||
29 | 30 | ||
30 | static struct vfsmount *rpc_mount __read_mostly; | 31 | static struct vfsmount *rpc_mount __read_mostly; |
31 | static int rpc_mount_count; | 32 | static int rpc_mount_count; |
@@ -125,7 +126,7 @@ static void | |||
125 | rpc_close_pipes(struct inode *inode) | 126 | rpc_close_pipes(struct inode *inode) |
126 | { | 127 | { |
127 | struct rpc_inode *rpci = RPC_I(inode); | 128 | struct rpc_inode *rpci = RPC_I(inode); |
128 | struct rpc_pipe_ops *ops; | 129 | const struct rpc_pipe_ops *ops; |
129 | int need_release; | 130 | int need_release; |
130 | 131 | ||
131 | mutex_lock(&inode->i_mutex); | 132 | mutex_lock(&inode->i_mutex); |
@@ -398,66 +399,12 @@ static const struct file_operations rpc_info_operations = { | |||
398 | 399 | ||
399 | 400 | ||
400 | /* | 401 | /* |
401 | * We have a single directory with 1 node in it. | ||
402 | */ | ||
403 | enum { | ||
404 | RPCAUTH_Root = 1, | ||
405 | RPCAUTH_lockd, | ||
406 | RPCAUTH_mount, | ||
407 | RPCAUTH_nfs, | ||
408 | RPCAUTH_portmap, | ||
409 | RPCAUTH_statd, | ||
410 | RPCAUTH_nfsd4_cb, | ||
411 | RPCAUTH_RootEOF | ||
412 | }; | ||
413 | |||
414 | /* | ||
415 | * Description of fs contents. | 402 | * Description of fs contents. |
416 | */ | 403 | */ |
417 | struct rpc_filelist { | 404 | struct rpc_filelist { |
418 | char *name; | 405 | const char *name; |
419 | const struct file_operations *i_fop; | 406 | const struct file_operations *i_fop; |
420 | int mode; | 407 | umode_t mode; |
421 | }; | ||
422 | |||
423 | static struct rpc_filelist files[] = { | ||
424 | [RPCAUTH_lockd] = { | ||
425 | .name = "lockd", | ||
426 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
427 | }, | ||
428 | [RPCAUTH_mount] = { | ||
429 | .name = "mount", | ||
430 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
431 | }, | ||
432 | [RPCAUTH_nfs] = { | ||
433 | .name = "nfs", | ||
434 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
435 | }, | ||
436 | [RPCAUTH_portmap] = { | ||
437 | .name = "portmap", | ||
438 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
439 | }, | ||
440 | [RPCAUTH_statd] = { | ||
441 | .name = "statd", | ||
442 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
443 | }, | ||
444 | [RPCAUTH_nfsd4_cb] = { | ||
445 | .name = "nfsd4_cb", | ||
446 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
447 | }, | ||
448 | }; | ||
449 | |||
450 | enum { | ||
451 | RPCAUTH_info = 2, | ||
452 | RPCAUTH_EOF | ||
453 | }; | ||
454 | |||
455 | static struct rpc_filelist authfiles[] = { | ||
456 | [RPCAUTH_info] = { | ||
457 | .name = "info", | ||
458 | .i_fop = &rpc_info_operations, | ||
459 | .mode = S_IFREG | S_IRUSR, | ||
460 | }, | ||
461 | }; | 408 | }; |
462 | 409 | ||
463 | struct vfsmount *rpc_get_mount(void) | 410 | struct vfsmount *rpc_get_mount(void) |
@@ -469,11 +416,13 @@ struct vfsmount *rpc_get_mount(void) | |||
469 | return ERR_PTR(err); | 416 | return ERR_PTR(err); |
470 | return rpc_mount; | 417 | return rpc_mount; |
471 | } | 418 | } |
419 | EXPORT_SYMBOL_GPL(rpc_get_mount); | ||
472 | 420 | ||
473 | void rpc_put_mount(void) | 421 | void rpc_put_mount(void) |
474 | { | 422 | { |
475 | simple_release_fs(&rpc_mount, &rpc_mount_count); | 423 | simple_release_fs(&rpc_mount, &rpc_mount_count); |
476 | } | 424 | } |
425 | EXPORT_SYMBOL_GPL(rpc_put_mount); | ||
477 | 426 | ||
478 | static int rpc_delete_dentry(struct dentry *dentry) | 427 | static int rpc_delete_dentry(struct dentry *dentry) |
479 | { | 428 | { |
@@ -484,39 +433,8 @@ static const struct dentry_operations rpc_dentry_operations = { | |||
484 | .d_delete = rpc_delete_dentry, | 433 | .d_delete = rpc_delete_dentry, |
485 | }; | 434 | }; |
486 | 435 | ||
487 | static int | ||
488 | rpc_lookup_parent(char *path, struct nameidata *nd) | ||
489 | { | ||
490 | struct vfsmount *mnt; | ||
491 | |||
492 | if (path[0] == '\0') | ||
493 | return -ENOENT; | ||
494 | |||
495 | mnt = rpc_get_mount(); | ||
496 | if (IS_ERR(mnt)) { | ||
497 | printk(KERN_WARNING "%s: %s failed to mount " | ||
498 | "pseudofilesystem \n", __FILE__, __func__); | ||
499 | return PTR_ERR(mnt); | ||
500 | } | ||
501 | |||
502 | if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) { | ||
503 | printk(KERN_WARNING "%s: %s failed to find path %s\n", | ||
504 | __FILE__, __func__, path); | ||
505 | rpc_put_mount(); | ||
506 | return -ENOENT; | ||
507 | } | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static void | ||
512 | rpc_release_path(struct nameidata *nd) | ||
513 | { | ||
514 | path_put(&nd->path); | ||
515 | rpc_put_mount(); | ||
516 | } | ||
517 | |||
518 | static struct inode * | 436 | static struct inode * |
519 | rpc_get_inode(struct super_block *sb, int mode) | 437 | rpc_get_inode(struct super_block *sb, umode_t mode) |
520 | { | 438 | { |
521 | struct inode *inode = new_inode(sb); | 439 | struct inode *inode = new_inode(sb); |
522 | if (!inode) | 440 | if (!inode) |
@@ -534,212 +452,274 @@ rpc_get_inode(struct super_block *sb, int mode) | |||
534 | return inode; | 452 | return inode; |
535 | } | 453 | } |
536 | 454 | ||
537 | /* | 455 | static int __rpc_create_common(struct inode *dir, struct dentry *dentry, |
538 | * FIXME: This probably has races. | 456 | umode_t mode, |
539 | */ | 457 | const struct file_operations *i_fop, |
540 | static void rpc_depopulate(struct dentry *parent, | 458 | void *private) |
541 | unsigned long start, unsigned long eof) | ||
542 | { | 459 | { |
543 | struct inode *dir = parent->d_inode; | 460 | struct inode *inode; |
544 | struct list_head *pos, *next; | ||
545 | struct dentry *dentry, *dvec[10]; | ||
546 | int n = 0; | ||
547 | 461 | ||
548 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); | 462 | BUG_ON(!d_unhashed(dentry)); |
549 | repeat: | 463 | inode = rpc_get_inode(dir->i_sb, mode); |
550 | spin_lock(&dcache_lock); | 464 | if (!inode) |
551 | list_for_each_safe(pos, next, &parent->d_subdirs) { | 465 | goto out_err; |
552 | dentry = list_entry(pos, struct dentry, d_u.d_child); | 466 | inode->i_ino = iunique(dir->i_sb, 100); |
553 | if (!dentry->d_inode || | 467 | if (i_fop) |
554 | dentry->d_inode->i_ino < start || | 468 | inode->i_fop = i_fop; |
555 | dentry->d_inode->i_ino >= eof) | 469 | if (private) |
556 | continue; | 470 | rpc_inode_setowner(inode, private); |
557 | spin_lock(&dentry->d_lock); | 471 | d_add(dentry, inode); |
558 | if (!d_unhashed(dentry)) { | 472 | return 0; |
559 | dget_locked(dentry); | 473 | out_err: |
560 | __d_drop(dentry); | 474 | printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", |
561 | spin_unlock(&dentry->d_lock); | 475 | __FILE__, __func__, dentry->d_name.name); |
562 | dvec[n++] = dentry; | 476 | dput(dentry); |
563 | if (n == ARRAY_SIZE(dvec)) | 477 | return -ENOMEM; |
564 | break; | ||
565 | } else | ||
566 | spin_unlock(&dentry->d_lock); | ||
567 | } | ||
568 | spin_unlock(&dcache_lock); | ||
569 | if (n) { | ||
570 | do { | ||
571 | dentry = dvec[--n]; | ||
572 | if (S_ISREG(dentry->d_inode->i_mode)) | ||
573 | simple_unlink(dir, dentry); | ||
574 | else if (S_ISDIR(dentry->d_inode->i_mode)) | ||
575 | simple_rmdir(dir, dentry); | ||
576 | d_delete(dentry); | ||
577 | dput(dentry); | ||
578 | } while (n); | ||
579 | goto repeat; | ||
580 | } | ||
581 | mutex_unlock(&dir->i_mutex); | ||
582 | } | 478 | } |
583 | 479 | ||
584 | static int | 480 | static int __rpc_create(struct inode *dir, struct dentry *dentry, |
585 | rpc_populate(struct dentry *parent, | 481 | umode_t mode, |
586 | struct rpc_filelist *files, | 482 | const struct file_operations *i_fop, |
587 | int start, int eof) | 483 | void *private) |
588 | { | 484 | { |
589 | struct inode *inode, *dir = parent->d_inode; | 485 | int err; |
590 | void *private = RPC_I(dir)->private; | ||
591 | struct dentry *dentry; | ||
592 | int mode, i; | ||
593 | 486 | ||
594 | mutex_lock(&dir->i_mutex); | 487 | err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private); |
595 | for (i = start; i < eof; i++) { | 488 | if (err) |
596 | dentry = d_alloc_name(parent, files[i].name); | 489 | return err; |
597 | if (!dentry) | 490 | fsnotify_create(dir, dentry); |
598 | goto out_bad; | ||
599 | dentry->d_op = &rpc_dentry_operations; | ||
600 | mode = files[i].mode; | ||
601 | inode = rpc_get_inode(dir->i_sb, mode); | ||
602 | if (!inode) { | ||
603 | dput(dentry); | ||
604 | goto out_bad; | ||
605 | } | ||
606 | inode->i_ino = i; | ||
607 | if (files[i].i_fop) | ||
608 | inode->i_fop = files[i].i_fop; | ||
609 | if (private) | ||
610 | rpc_inode_setowner(inode, private); | ||
611 | if (S_ISDIR(mode)) | ||
612 | inc_nlink(dir); | ||
613 | d_add(dentry, inode); | ||
614 | fsnotify_create(dir, dentry); | ||
615 | } | ||
616 | mutex_unlock(&dir->i_mutex); | ||
617 | return 0; | 491 | return 0; |
618 | out_bad: | ||
619 | mutex_unlock(&dir->i_mutex); | ||
620 | printk(KERN_WARNING "%s: %s failed to populate directory %s\n", | ||
621 | __FILE__, __func__, parent->d_name.name); | ||
622 | return -ENOMEM; | ||
623 | } | 492 | } |
624 | 493 | ||
625 | static int | 494 | static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, |
626 | __rpc_mkdir(struct inode *dir, struct dentry *dentry) | 495 | umode_t mode, |
496 | const struct file_operations *i_fop, | ||
497 | void *private) | ||
627 | { | 498 | { |
628 | struct inode *inode; | 499 | int err; |
629 | 500 | ||
630 | inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); | 501 | err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private); |
631 | if (!inode) | 502 | if (err) |
632 | goto out_err; | 503 | return err; |
633 | inode->i_ino = iunique(dir->i_sb, 100); | ||
634 | d_instantiate(dentry, inode); | ||
635 | inc_nlink(dir); | 504 | inc_nlink(dir); |
636 | fsnotify_mkdir(dir, dentry); | 505 | fsnotify_mkdir(dir, dentry); |
637 | return 0; | 506 | return 0; |
638 | out_err: | ||
639 | printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", | ||
640 | __FILE__, __func__, dentry->d_name.name); | ||
641 | return -ENOMEM; | ||
642 | } | 507 | } |
643 | 508 | ||
644 | static int | 509 | static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, |
645 | __rpc_rmdir(struct inode *dir, struct dentry *dentry) | 510 | umode_t mode, |
511 | const struct file_operations *i_fop, | ||
512 | void *private, | ||
513 | const struct rpc_pipe_ops *ops, | ||
514 | int flags) | ||
646 | { | 515 | { |
647 | int error; | 516 | struct rpc_inode *rpci; |
648 | error = simple_rmdir(dir, dentry); | 517 | int err; |
649 | if (!error) | 518 | |
650 | d_delete(dentry); | 519 | err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); |
651 | return error; | 520 | if (err) |
521 | return err; | ||
522 | rpci = RPC_I(dentry->d_inode); | ||
523 | rpci->nkern_readwriters = 1; | ||
524 | rpci->private = private; | ||
525 | rpci->flags = flags; | ||
526 | rpci->ops = ops; | ||
527 | fsnotify_create(dir, dentry); | ||
528 | return 0; | ||
652 | } | 529 | } |
653 | 530 | ||
654 | static struct dentry * | 531 | static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) |
655 | rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive) | 532 | { |
533 | int ret; | ||
534 | |||
535 | dget(dentry); | ||
536 | ret = simple_rmdir(dir, dentry); | ||
537 | d_delete(dentry); | ||
538 | dput(dentry); | ||
539 | return ret; | ||
540 | } | ||
541 | |||
542 | static int __rpc_unlink(struct inode *dir, struct dentry *dentry) | ||
543 | { | ||
544 | int ret; | ||
545 | |||
546 | dget(dentry); | ||
547 | ret = simple_unlink(dir, dentry); | ||
548 | d_delete(dentry); | ||
549 | dput(dentry); | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) | ||
554 | { | ||
555 | struct inode *inode = dentry->d_inode; | ||
556 | struct rpc_inode *rpci = RPC_I(inode); | ||
557 | |||
558 | rpci->nkern_readwriters--; | ||
559 | if (rpci->nkern_readwriters != 0) | ||
560 | return 0; | ||
561 | rpc_close_pipes(inode); | ||
562 | return __rpc_unlink(dir, dentry); | ||
563 | } | ||
564 | |||
565 | static struct dentry *__rpc_lookup_create(struct dentry *parent, | ||
566 | struct qstr *name) | ||
656 | { | 567 | { |
657 | struct inode *dir = parent->d_inode; | ||
658 | struct dentry *dentry; | 568 | struct dentry *dentry; |
659 | 569 | ||
660 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 570 | dentry = d_lookup(parent, name); |
661 | dentry = lookup_one_len(name, parent, len); | 571 | if (!dentry) { |
662 | if (IS_ERR(dentry)) | 572 | dentry = d_alloc(parent, name); |
663 | goto out_err; | 573 | if (!dentry) { |
574 | dentry = ERR_PTR(-ENOMEM); | ||
575 | goto out_err; | ||
576 | } | ||
577 | } | ||
664 | if (!dentry->d_inode) | 578 | if (!dentry->d_inode) |
665 | dentry->d_op = &rpc_dentry_operations; | 579 | dentry->d_op = &rpc_dentry_operations; |
666 | else if (exclusive) { | ||
667 | dput(dentry); | ||
668 | dentry = ERR_PTR(-EEXIST); | ||
669 | goto out_err; | ||
670 | } | ||
671 | return dentry; | ||
672 | out_err: | 580 | out_err: |
673 | mutex_unlock(&dir->i_mutex); | ||
674 | return dentry; | 581 | return dentry; |
675 | } | 582 | } |
676 | 583 | ||
677 | static struct dentry * | 584 | static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, |
678 | rpc_lookup_negative(char *path, struct nameidata *nd) | 585 | struct qstr *name) |
679 | { | 586 | { |
680 | struct dentry *dentry; | 587 | struct dentry *dentry; |
681 | int error; | ||
682 | 588 | ||
683 | if ((error = rpc_lookup_parent(path, nd)) != 0) | 589 | dentry = __rpc_lookup_create(parent, name); |
684 | return ERR_PTR(error); | 590 | if (dentry->d_inode == NULL) |
685 | dentry = rpc_lookup_create(nd->path.dentry, nd->last.name, nd->last.len, | 591 | return dentry; |
686 | 1); | 592 | dput(dentry); |
687 | if (IS_ERR(dentry)) | 593 | return ERR_PTR(-EEXIST); |
688 | rpc_release_path(nd); | ||
689 | return dentry; | ||
690 | } | 594 | } |
691 | 595 | ||
692 | /** | 596 | /* |
693 | * rpc_mkdir - Create a new directory in rpc_pipefs | 597 | * FIXME: This probably has races. |
694 | * @path: path from the rpc_pipefs root to the new directory | ||
695 | * @rpc_client: rpc client to associate with this directory | ||
696 | * | ||
697 | * This creates a directory at the given @path associated with | ||
698 | * @rpc_clnt, which will contain a file named "info" with some basic | ||
699 | * information about the client, together with any "pipes" that may | ||
700 | * later be created using rpc_mkpipe(). | ||
701 | */ | 598 | */ |
702 | struct dentry * | 599 | static void __rpc_depopulate(struct dentry *parent, |
703 | rpc_mkdir(char *path, struct rpc_clnt *rpc_client) | 600 | const struct rpc_filelist *files, |
601 | int start, int eof) | ||
704 | { | 602 | { |
705 | struct nameidata nd; | 603 | struct inode *dir = parent->d_inode; |
706 | struct dentry *dentry; | 604 | struct dentry *dentry; |
707 | struct inode *dir; | 605 | struct qstr name; |
606 | int i; | ||
607 | |||
608 | for (i = start; i < eof; i++) { | ||
609 | name.name = files[i].name; | ||
610 | name.len = strlen(files[i].name); | ||
611 | name.hash = full_name_hash(name.name, name.len); | ||
612 | dentry = d_lookup(parent, &name); | ||
613 | |||
614 | if (dentry == NULL) | ||
615 | continue; | ||
616 | if (dentry->d_inode == NULL) | ||
617 | goto next; | ||
618 | switch (dentry->d_inode->i_mode & S_IFMT) { | ||
619 | default: | ||
620 | BUG(); | ||
621 | case S_IFREG: | ||
622 | __rpc_unlink(dir, dentry); | ||
623 | break; | ||
624 | case S_IFDIR: | ||
625 | __rpc_rmdir(dir, dentry); | ||
626 | } | ||
627 | next: | ||
628 | dput(dentry); | ||
629 | } | ||
630 | } | ||
631 | |||
632 | static void rpc_depopulate(struct dentry *parent, | ||
633 | const struct rpc_filelist *files, | ||
634 | int start, int eof) | ||
635 | { | ||
636 | struct inode *dir = parent->d_inode; | ||
637 | |||
638 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); | ||
639 | __rpc_depopulate(parent, files, start, eof); | ||
640 | mutex_unlock(&dir->i_mutex); | ||
641 | } | ||
642 | |||
643 | static int rpc_populate(struct dentry *parent, | ||
644 | const struct rpc_filelist *files, | ||
645 | int start, int eof, | ||
646 | void *private) | ||
647 | { | ||
648 | struct inode *dir = parent->d_inode; | ||
649 | struct dentry *dentry; | ||
650 | int i, err; | ||
651 | |||
652 | mutex_lock(&dir->i_mutex); | ||
653 | for (i = start; i < eof; i++) { | ||
654 | struct qstr q; | ||
655 | |||
656 | q.name = files[i].name; | ||
657 | q.len = strlen(files[i].name); | ||
658 | q.hash = full_name_hash(q.name, q.len); | ||
659 | dentry = __rpc_lookup_create_exclusive(parent, &q); | ||
660 | err = PTR_ERR(dentry); | ||
661 | if (IS_ERR(dentry)) | ||
662 | goto out_bad; | ||
663 | switch (files[i].mode & S_IFMT) { | ||
664 | default: | ||
665 | BUG(); | ||
666 | case S_IFREG: | ||
667 | err = __rpc_create(dir, dentry, | ||
668 | files[i].mode, | ||
669 | files[i].i_fop, | ||
670 | private); | ||
671 | break; | ||
672 | case S_IFDIR: | ||
673 | err = __rpc_mkdir(dir, dentry, | ||
674 | files[i].mode, | ||
675 | NULL, | ||
676 | private); | ||
677 | } | ||
678 | if (err != 0) | ||
679 | goto out_bad; | ||
680 | } | ||
681 | mutex_unlock(&dir->i_mutex); | ||
682 | return 0; | ||
683 | out_bad: | ||
684 | __rpc_depopulate(parent, files, start, eof); | ||
685 | mutex_unlock(&dir->i_mutex); | ||
686 | printk(KERN_WARNING "%s: %s failed to populate directory %s\n", | ||
687 | __FILE__, __func__, parent->d_name.name); | ||
688 | return err; | ||
689 | } | ||
690 | |||
691 | static struct dentry *rpc_mkdir_populate(struct dentry *parent, | ||
692 | struct qstr *name, umode_t mode, void *private, | ||
693 | int (*populate)(struct dentry *, void *), void *args_populate) | ||
694 | { | ||
695 | struct dentry *dentry; | ||
696 | struct inode *dir = parent->d_inode; | ||
708 | int error; | 697 | int error; |
709 | 698 | ||
710 | dentry = rpc_lookup_negative(path, &nd); | 699 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
700 | dentry = __rpc_lookup_create_exclusive(parent, name); | ||
711 | if (IS_ERR(dentry)) | 701 | if (IS_ERR(dentry)) |
712 | return dentry; | 702 | goto out; |
713 | dir = nd.path.dentry->d_inode; | 703 | error = __rpc_mkdir(dir, dentry, mode, NULL, private); |
714 | if ((error = __rpc_mkdir(dir, dentry)) != 0) | 704 | if (error != 0) |
715 | goto err_dput; | 705 | goto out_err; |
716 | RPC_I(dentry->d_inode)->private = rpc_client; | 706 | if (populate != NULL) { |
717 | error = rpc_populate(dentry, authfiles, | 707 | error = populate(dentry, args_populate); |
718 | RPCAUTH_info, RPCAUTH_EOF); | 708 | if (error) |
719 | if (error) | 709 | goto err_rmdir; |
720 | goto err_depopulate; | 710 | } |
721 | dget(dentry); | ||
722 | out: | 711 | out: |
723 | mutex_unlock(&dir->i_mutex); | 712 | mutex_unlock(&dir->i_mutex); |
724 | rpc_release_path(&nd); | ||
725 | return dentry; | 713 | return dentry; |
726 | err_depopulate: | 714 | err_rmdir: |
727 | rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); | ||
728 | __rpc_rmdir(dir, dentry); | 715 | __rpc_rmdir(dir, dentry); |
729 | err_dput: | 716 | out_err: |
730 | dput(dentry); | ||
731 | printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", | ||
732 | __FILE__, __func__, path, error); | ||
733 | dentry = ERR_PTR(error); | 717 | dentry = ERR_PTR(error); |
734 | goto out; | 718 | goto out; |
735 | } | 719 | } |
736 | 720 | ||
737 | /** | 721 | static int rpc_rmdir_depopulate(struct dentry *dentry, |
738 | * rpc_rmdir - Remove a directory created with rpc_mkdir() | 722 | void (*depopulate)(struct dentry *)) |
739 | * @dentry: directory to remove | ||
740 | */ | ||
741 | int | ||
742 | rpc_rmdir(struct dentry *dentry) | ||
743 | { | 723 | { |
744 | struct dentry *parent; | 724 | struct dentry *parent; |
745 | struct inode *dir; | 725 | struct inode *dir; |
@@ -748,9 +728,9 @@ rpc_rmdir(struct dentry *dentry) | |||
748 | parent = dget_parent(dentry); | 728 | parent = dget_parent(dentry); |
749 | dir = parent->d_inode; | 729 | dir = parent->d_inode; |
750 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 730 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
751 | rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); | 731 | if (depopulate != NULL) |
732 | depopulate(dentry); | ||
752 | error = __rpc_rmdir(dir, dentry); | 733 | error = __rpc_rmdir(dir, dentry); |
753 | dput(dentry); | ||
754 | mutex_unlock(&dir->i_mutex); | 734 | mutex_unlock(&dir->i_mutex); |
755 | dput(parent); | 735 | dput(parent); |
756 | return error; | 736 | return error; |
@@ -776,50 +756,54 @@ rpc_rmdir(struct dentry *dentry) | |||
776 | * The @private argument passed here will be available to all these methods | 756 | * The @private argument passed here will be available to all these methods |
777 | * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. | 757 | * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. |
778 | */ | 758 | */ |
779 | struct dentry * | 759 | struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, |
780 | rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags) | 760 | void *private, const struct rpc_pipe_ops *ops, |
761 | int flags) | ||
781 | { | 762 | { |
782 | struct dentry *dentry; | 763 | struct dentry *dentry; |
783 | struct inode *dir, *inode; | 764 | struct inode *dir = parent->d_inode; |
784 | struct rpc_inode *rpci; | 765 | umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR; |
766 | struct qstr q; | ||
767 | int err; | ||
768 | |||
769 | if (ops->upcall == NULL) | ||
770 | umode &= ~S_IRUGO; | ||
771 | if (ops->downcall == NULL) | ||
772 | umode &= ~S_IWUGO; | ||
773 | |||
774 | q.name = name; | ||
775 | q.len = strlen(name); | ||
776 | q.hash = full_name_hash(q.name, q.len), | ||
785 | 777 | ||
786 | dentry = rpc_lookup_create(parent, name, strlen(name), 0); | 778 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
779 | dentry = __rpc_lookup_create(parent, &q); | ||
787 | if (IS_ERR(dentry)) | 780 | if (IS_ERR(dentry)) |
788 | return dentry; | 781 | goto out; |
789 | dir = parent->d_inode; | ||
790 | if (dentry->d_inode) { | 782 | if (dentry->d_inode) { |
791 | rpci = RPC_I(dentry->d_inode); | 783 | struct rpc_inode *rpci = RPC_I(dentry->d_inode); |
792 | if (rpci->private != private || | 784 | if (rpci->private != private || |
793 | rpci->ops != ops || | 785 | rpci->ops != ops || |
794 | rpci->flags != flags) { | 786 | rpci->flags != flags) { |
795 | dput (dentry); | 787 | dput (dentry); |
796 | dentry = ERR_PTR(-EBUSY); | 788 | err = -EBUSY; |
789 | goto out_err; | ||
797 | } | 790 | } |
798 | rpci->nkern_readwriters++; | 791 | rpci->nkern_readwriters++; |
799 | goto out; | 792 | goto out; |
800 | } | 793 | } |
801 | inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR); | 794 | |
802 | if (!inode) | 795 | err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, |
803 | goto err_dput; | 796 | private, ops, flags); |
804 | inode->i_ino = iunique(dir->i_sb, 100); | 797 | if (err) |
805 | inode->i_fop = &rpc_pipe_fops; | 798 | goto out_err; |
806 | d_instantiate(dentry, inode); | ||
807 | rpci = RPC_I(inode); | ||
808 | rpci->private = private; | ||
809 | rpci->flags = flags; | ||
810 | rpci->ops = ops; | ||
811 | rpci->nkern_readwriters = 1; | ||
812 | fsnotify_create(dir, dentry); | ||
813 | dget(dentry); | ||
814 | out: | 799 | out: |
815 | mutex_unlock(&dir->i_mutex); | 800 | mutex_unlock(&dir->i_mutex); |
816 | return dentry; | 801 | return dentry; |
817 | err_dput: | 802 | out_err: |
818 | dput(dentry); | 803 | dentry = ERR_PTR(err); |
819 | dentry = ERR_PTR(-ENOMEM); | ||
820 | printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", | 804 | printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", |
821 | __FILE__, __func__, parent->d_name.name, name, | 805 | __FILE__, __func__, parent->d_name.name, name, |
822 | -ENOMEM); | 806 | err); |
823 | goto out; | 807 | goto out; |
824 | } | 808 | } |
825 | EXPORT_SYMBOL_GPL(rpc_mkpipe); | 809 | EXPORT_SYMBOL_GPL(rpc_mkpipe); |
@@ -842,19 +826,107 @@ rpc_unlink(struct dentry *dentry) | |||
842 | parent = dget_parent(dentry); | 826 | parent = dget_parent(dentry); |
843 | dir = parent->d_inode; | 827 | dir = parent->d_inode; |
844 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 828 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
845 | if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) { | 829 | error = __rpc_rmpipe(dir, dentry); |
846 | rpc_close_pipes(dentry->d_inode); | ||
847 | error = simple_unlink(dir, dentry); | ||
848 | if (!error) | ||
849 | d_delete(dentry); | ||
850 | } | ||
851 | dput(dentry); | ||
852 | mutex_unlock(&dir->i_mutex); | 830 | mutex_unlock(&dir->i_mutex); |
853 | dput(parent); | 831 | dput(parent); |
854 | return error; | 832 | return error; |
855 | } | 833 | } |
856 | EXPORT_SYMBOL_GPL(rpc_unlink); | 834 | EXPORT_SYMBOL_GPL(rpc_unlink); |
857 | 835 | ||
836 | enum { | ||
837 | RPCAUTH_info, | ||
838 | RPCAUTH_EOF | ||
839 | }; | ||
840 | |||
841 | static const struct rpc_filelist authfiles[] = { | ||
842 | [RPCAUTH_info] = { | ||
843 | .name = "info", | ||
844 | .i_fop = &rpc_info_operations, | ||
845 | .mode = S_IFREG | S_IRUSR, | ||
846 | }, | ||
847 | }; | ||
848 | |||
849 | static int rpc_clntdir_populate(struct dentry *dentry, void *private) | ||
850 | { | ||
851 | return rpc_populate(dentry, | ||
852 | authfiles, RPCAUTH_info, RPCAUTH_EOF, | ||
853 | private); | ||
854 | } | ||
855 | |||
856 | static void rpc_clntdir_depopulate(struct dentry *dentry) | ||
857 | { | ||
858 | rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); | ||
859 | } | ||
860 | |||
861 | /** | ||
862 | * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs | ||
863 | * @path: path from the rpc_pipefs root to the new directory | ||
864 | * @rpc_client: rpc client to associate with this directory | ||
865 | * | ||
866 | * This creates a directory at the given @path associated with | ||
867 | * @rpc_clnt, which will contain a file named "info" with some basic | ||
868 | * information about the client, together with any "pipes" that may | ||
869 | * later be created using rpc_mkpipe(). | ||
870 | */ | ||
871 | struct dentry *rpc_create_client_dir(struct dentry *dentry, | ||
872 | struct qstr *name, | ||
873 | struct rpc_clnt *rpc_client) | ||
874 | { | ||
875 | return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL, | ||
876 | rpc_clntdir_populate, rpc_client); | ||
877 | } | ||
878 | |||
879 | /** | ||
880 | * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() | ||
881 | * @dentry: directory to remove | ||
882 | */ | ||
883 | int rpc_remove_client_dir(struct dentry *dentry) | ||
884 | { | ||
885 | return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); | ||
886 | } | ||
887 | |||
888 | static const struct rpc_filelist cache_pipefs_files[3] = { | ||
889 | [0] = { | ||
890 | .name = "channel", | ||
891 | .i_fop = &cache_file_operations_pipefs, | ||
892 | .mode = S_IFREG|S_IRUSR|S_IWUSR, | ||
893 | }, | ||
894 | [1] = { | ||
895 | .name = "content", | ||
896 | .i_fop = &content_file_operations_pipefs, | ||
897 | .mode = S_IFREG|S_IRUSR, | ||
898 | }, | ||
899 | [2] = { | ||
900 | .name = "flush", | ||
901 | .i_fop = &cache_flush_operations_pipefs, | ||
902 | .mode = S_IFREG|S_IRUSR|S_IWUSR, | ||
903 | }, | ||
904 | }; | ||
905 | |||
906 | static int rpc_cachedir_populate(struct dentry *dentry, void *private) | ||
907 | { | ||
908 | return rpc_populate(dentry, | ||
909 | cache_pipefs_files, 0, 3, | ||
910 | private); | ||
911 | } | ||
912 | |||
913 | static void rpc_cachedir_depopulate(struct dentry *dentry) | ||
914 | { | ||
915 | rpc_depopulate(dentry, cache_pipefs_files, 0, 3); | ||
916 | } | ||
917 | |||
918 | struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name, | ||
919 | mode_t umode, struct cache_detail *cd) | ||
920 | { | ||
921 | return rpc_mkdir_populate(parent, name, umode, NULL, | ||
922 | rpc_cachedir_populate, cd); | ||
923 | } | ||
924 | |||
925 | void rpc_remove_cache_dir(struct dentry *dentry) | ||
926 | { | ||
927 | rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate); | ||
928 | } | ||
929 | |||
858 | /* | 930 | /* |
859 | * populate the filesystem | 931 | * populate the filesystem |
860 | */ | 932 | */ |
@@ -866,6 +938,51 @@ static struct super_operations s_ops = { | |||
866 | 938 | ||
867 | #define RPCAUTH_GSSMAGIC 0x67596969 | 939 | #define RPCAUTH_GSSMAGIC 0x67596969 |
868 | 940 | ||
941 | /* | ||
942 | * We have a single directory with 1 node in it. | ||
943 | */ | ||
944 | enum { | ||
945 | RPCAUTH_lockd, | ||
946 | RPCAUTH_mount, | ||
947 | RPCAUTH_nfs, | ||
948 | RPCAUTH_portmap, | ||
949 | RPCAUTH_statd, | ||
950 | RPCAUTH_nfsd4_cb, | ||
951 | RPCAUTH_cache, | ||
952 | RPCAUTH_RootEOF | ||
953 | }; | ||
954 | |||
955 | static const struct rpc_filelist files[] = { | ||
956 | [RPCAUTH_lockd] = { | ||
957 | .name = "lockd", | ||
958 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
959 | }, | ||
960 | [RPCAUTH_mount] = { | ||
961 | .name = "mount", | ||
962 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
963 | }, | ||
964 | [RPCAUTH_nfs] = { | ||
965 | .name = "nfs", | ||
966 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
967 | }, | ||
968 | [RPCAUTH_portmap] = { | ||
969 | .name = "portmap", | ||
970 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
971 | }, | ||
972 | [RPCAUTH_statd] = { | ||
973 | .name = "statd", | ||
974 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
975 | }, | ||
976 | [RPCAUTH_nfsd4_cb] = { | ||
977 | .name = "nfsd4_cb", | ||
978 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
979 | }, | ||
980 | [RPCAUTH_cache] = { | ||
981 | .name = "cache", | ||
982 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
983 | }, | ||
984 | }; | ||
985 | |||
869 | static int | 986 | static int |
870 | rpc_fill_super(struct super_block *sb, void *data, int silent) | 987 | rpc_fill_super(struct super_block *sb, void *data, int silent) |
871 | { | 988 | { |
@@ -886,7 +1003,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) | |||
886 | iput(inode); | 1003 | iput(inode); |
887 | return -ENOMEM; | 1004 | return -ENOMEM; |
888 | } | 1005 | } |
889 | if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF)) | 1006 | if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) |
890 | goto out; | 1007 | goto out; |
891 | sb->s_root = root; | 1008 | sb->s_root = root; |
892 | return 0; | 1009 | return 0; |