diff options
Diffstat (limited to 'net/sunrpc/rpc_pipe.c')
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 268 |
1 files changed, 174 insertions, 94 deletions
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index b382809726d8..ded6c63f11ec 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -414,6 +414,38 @@ rpc_put_mount(void) | |||
414 | simple_release_fs(&rpc_mount, &rpc_mount_count); | 414 | simple_release_fs(&rpc_mount, &rpc_mount_count); |
415 | } | 415 | } |
416 | 416 | ||
417 | static int | ||
418 | rpc_lookup_parent(char *path, struct nameidata *nd) | ||
419 | { | ||
420 | if (path[0] == '\0') | ||
421 | return -ENOENT; | ||
422 | if (rpc_get_mount()) { | ||
423 | printk(KERN_WARNING "%s: %s failed to mount " | ||
424 | "pseudofilesystem \n", __FILE__, __FUNCTION__); | ||
425 | return -ENODEV; | ||
426 | } | ||
427 | nd->mnt = mntget(rpc_mount); | ||
428 | nd->dentry = dget(rpc_mount->mnt_root); | ||
429 | nd->last_type = LAST_ROOT; | ||
430 | nd->flags = LOOKUP_PARENT; | ||
431 | nd->depth = 0; | ||
432 | |||
433 | if (path_walk(path, nd)) { | ||
434 | printk(KERN_WARNING "%s: %s failed to find path %s\n", | ||
435 | __FILE__, __FUNCTION__, path); | ||
436 | rpc_put_mount(); | ||
437 | return -ENOENT; | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static void | ||
443 | rpc_release_path(struct nameidata *nd) | ||
444 | { | ||
445 | path_release(nd); | ||
446 | rpc_put_mount(); | ||
447 | } | ||
448 | |||
417 | static struct inode * | 449 | static struct inode * |
418 | rpc_get_inode(struct super_block *sb, int mode) | 450 | rpc_get_inode(struct super_block *sb, int mode) |
419 | { | 451 | { |
@@ -518,149 +550,197 @@ out_bad: | |||
518 | return -ENOMEM; | 550 | return -ENOMEM; |
519 | } | 551 | } |
520 | 552 | ||
521 | struct dentry * | 553 | static int |
522 | rpc_mkdir(struct dentry *parent, char *name, struct rpc_clnt *rpc_client) | 554 | __rpc_mkdir(struct inode *dir, struct dentry *dentry) |
523 | { | 555 | { |
524 | struct inode *dir; | ||
525 | struct dentry *dentry; | ||
526 | struct inode *inode; | 556 | struct inode *inode; |
557 | |||
558 | inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUSR | S_IXUSR); | ||
559 | if (!inode) | ||
560 | goto out_err; | ||
561 | inode->i_ino = iunique(dir->i_sb, 100); | ||
562 | d_instantiate(dentry, inode); | ||
563 | dir->i_nlink++; | ||
564 | inode_dir_notify(dir, DN_CREATE); | ||
565 | rpc_get_mount(); | ||
566 | return 0; | ||
567 | out_err: | ||
568 | printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", | ||
569 | __FILE__, __FUNCTION__, dentry->d_name.name); | ||
570 | return -ENOMEM; | ||
571 | } | ||
572 | |||
573 | static int | ||
574 | __rpc_rmdir(struct inode *dir, struct dentry *dentry) | ||
575 | { | ||
527 | int error; | 576 | int error; |
528 | 577 | ||
529 | if (!parent) | 578 | shrink_dcache_parent(dentry); |
530 | parent = rpc_mount->mnt_root; | 579 | if (dentry->d_inode) { |
580 | rpc_close_pipes(dentry->d_inode); | ||
581 | rpc_inode_setowner(dentry->d_inode, NULL); | ||
582 | } | ||
583 | if ((error = simple_rmdir(dir, dentry)) != 0) | ||
584 | return error; | ||
585 | if (!error) { | ||
586 | inode_dir_notify(dir, DN_DELETE); | ||
587 | d_drop(dentry); | ||
588 | rpc_put_mount(); | ||
589 | } | ||
590 | return 0; | ||
591 | } | ||
531 | 592 | ||
532 | dir = parent->d_inode; | 593 | static struct dentry * |
533 | 594 | rpc_lookup_negative(char *path, struct nameidata *nd) | |
534 | error = rpc_get_mount(); | 595 | { |
535 | if (error) | 596 | struct dentry *dentry; |
536 | return ERR_PTR(error); | 597 | struct inode *dir; |
598 | int error; | ||
537 | 599 | ||
600 | if ((error = rpc_lookup_parent(path, nd)) != 0) | ||
601 | return ERR_PTR(error); | ||
602 | dir = nd->dentry->d_inode; | ||
538 | down(&dir->i_sem); | 603 | down(&dir->i_sem); |
539 | dentry = lookup_one_len(name, parent, strlen(name)); | 604 | dentry = lookup_hash(&nd->last, nd->dentry); |
540 | if (IS_ERR(dentry)) | 605 | if (IS_ERR(dentry)) |
541 | goto out_unlock; | 606 | goto out_err; |
542 | if (dentry->d_inode) { | 607 | if (dentry->d_inode) { |
608 | dput(dentry); | ||
543 | dentry = ERR_PTR(-EEXIST); | 609 | dentry = ERR_PTR(-EEXIST); |
544 | goto out_dput; | 610 | goto out_err; |
545 | } | 611 | } |
546 | 612 | return dentry; | |
547 | inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUSR | S_IXUSR); | 613 | out_err: |
548 | if (!inode) | ||
549 | goto out_dput; | ||
550 | inode->i_ino = iunique(dir->i_sb, 100); | ||
551 | dir->i_nlink++; | ||
552 | RPC_I(dentry->d_inode)->private = rpc_client; | ||
553 | |||
554 | d_instantiate(dentry, inode); | ||
555 | dget(dentry); | ||
556 | up(&dir->i_sem); | 614 | up(&dir->i_sem); |
615 | rpc_release_path(nd); | ||
616 | return dentry; | ||
617 | } | ||
557 | 618 | ||
558 | inode_dir_notify(dir, DN_CREATE); | ||
559 | 619 | ||
620 | struct dentry * | ||
621 | rpc_mkdir(char *path, struct rpc_clnt *rpc_client) | ||
622 | { | ||
623 | struct nameidata nd; | ||
624 | struct dentry *dentry; | ||
625 | struct inode *dir; | ||
626 | int error; | ||
627 | |||
628 | dentry = rpc_lookup_negative(path, &nd); | ||
629 | if (IS_ERR(dentry)) | ||
630 | return dentry; | ||
631 | dir = nd.dentry->d_inode; | ||
632 | if ((error = __rpc_mkdir(dir, dentry)) != 0) | ||
633 | goto err_dput; | ||
634 | RPC_I(dentry->d_inode)->private = rpc_client; | ||
560 | error = rpc_populate(dentry, authfiles, | 635 | error = rpc_populate(dentry, authfiles, |
561 | RPCAUTH_info, RPCAUTH_EOF); | 636 | RPCAUTH_info, RPCAUTH_EOF); |
562 | if (error) | 637 | if (error) |
563 | goto out_depopulate; | 638 | goto err_depopulate; |
564 | 639 | out: | |
565 | return dentry; | ||
566 | |||
567 | out_depopulate: | ||
568 | rpc_rmdir(dentry); | ||
569 | out_dput: | ||
570 | dput(dentry); | ||
571 | out_unlock: | ||
572 | up(&dir->i_sem); | 640 | up(&dir->i_sem); |
573 | rpc_put_mount(); | 641 | rpc_release_path(&nd); |
574 | return dentry; | 642 | return dentry; |
643 | err_depopulate: | ||
644 | rpc_depopulate(dentry); | ||
645 | __rpc_rmdir(dir, dentry); | ||
646 | err_dput: | ||
647 | dput(dentry); | ||
648 | printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", | ||
649 | __FILE__, __FUNCTION__, path, error); | ||
650 | dentry = ERR_PTR(error); | ||
651 | goto out; | ||
575 | } | 652 | } |
576 | 653 | ||
577 | void | 654 | int |
578 | rpc_rmdir(struct dentry *dentry) | 655 | rpc_rmdir(char *path) |
579 | { | 656 | { |
580 | struct dentry *parent = dentry->d_parent; | 657 | struct nameidata nd; |
581 | 658 | struct dentry *dentry; | |
582 | rpc_depopulate(dentry); | 659 | struct inode *dir; |
660 | int error; | ||
583 | 661 | ||
584 | down(&parent->d_inode->i_sem); | 662 | if ((error = rpc_lookup_parent(path, &nd)) != 0) |
585 | if (dentry->d_inode) { | 663 | return error; |
586 | rpc_close_pipes(dentry->d_inode); | 664 | dir = nd.dentry->d_inode; |
587 | rpc_inode_setowner(dentry->d_inode, NULL); | 665 | down(&dir->i_sem); |
588 | simple_rmdir(parent->d_inode, dentry); | 666 | dentry = lookup_hash(&nd.last, nd.dentry); |
667 | if (IS_ERR(dentry)) { | ||
668 | error = PTR_ERR(dentry); | ||
669 | goto out_release; | ||
589 | } | 670 | } |
590 | up(&parent->d_inode->i_sem); | 671 | rpc_depopulate(dentry); |
591 | 672 | error = __rpc_rmdir(dir, dentry); | |
592 | inode_dir_notify(parent->d_inode, DN_DELETE); | 673 | dput(dentry); |
593 | rpc_put_mount(); | 674 | out_release: |
675 | up(&dir->i_sem); | ||
676 | rpc_release_path(&nd); | ||
677 | return error; | ||
594 | } | 678 | } |
595 | 679 | ||
596 | struct dentry * | 680 | struct dentry * |
597 | rpc_mkpipe(struct dentry *parent, char *name, void *private, | 681 | rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags) |
598 | struct rpc_pipe_ops *ops, int flags) | ||
599 | { | 682 | { |
600 | struct inode *dir = parent->d_inode; | 683 | struct nameidata nd; |
601 | struct dentry *dentry; | 684 | struct dentry *dentry; |
602 | struct inode *inode; | 685 | struct inode *dir, *inode; |
603 | struct rpc_inode *rpci; | 686 | struct rpc_inode *rpci; |
604 | int error; | ||
605 | |||
606 | error = rpc_get_mount(); | ||
607 | if (error) | ||
608 | return ERR_PTR(error); | ||
609 | 687 | ||
610 | down(&parent->d_inode->i_sem); | 688 | dentry = rpc_lookup_negative(path, &nd); |
611 | dentry = lookup_one_len(name, parent, strlen(name)); | ||
612 | if (IS_ERR(dentry)) | 689 | if (IS_ERR(dentry)) |
613 | goto out_unlock; | 690 | return dentry; |
614 | if (dentry->d_inode) { | 691 | dir = nd.dentry->d_inode; |
615 | dentry = ERR_PTR(-EEXIST); | 692 | inode = rpc_get_inode(dir->i_sb, S_IFSOCK | S_IRUSR | S_IWUSR); |
616 | goto out_dput; | 693 | if (!inode) |
617 | } | 694 | goto err_dput; |
618 | |||
619 | inode = rpc_get_inode(parent->d_inode->i_sb, | ||
620 | S_IFSOCK | S_IRUSR | S_IWUSR); | ||
621 | if (!inode) { | ||
622 | dentry = ERR_PTR(-ENOMEM); | ||
623 | goto out_dput; | ||
624 | } | ||
625 | |||
626 | inode->i_ino = iunique(dir->i_sb, 100); | 695 | inode->i_ino = iunique(dir->i_sb, 100); |
627 | inode->i_fop = &rpc_pipe_fops; | 696 | inode->i_fop = &rpc_pipe_fops; |
628 | 697 | d_instantiate(dentry, inode); | |
629 | rpci = RPC_I(inode); | 698 | rpci = RPC_I(inode); |
630 | rpci->private = private; | 699 | rpci->private = private; |
631 | rpci->flags = flags; | 700 | rpci->flags = flags; |
632 | rpci->ops = ops; | 701 | rpci->ops = ops; |
633 | |||
634 | d_instantiate(dentry, inode); | ||
635 | dget(dentry); | ||
636 | up(&parent->d_inode->i_sem); | ||
637 | |||
638 | inode_dir_notify(dir, DN_CREATE); | 702 | inode_dir_notify(dir, DN_CREATE); |
703 | out: | ||
704 | up(&dir->i_sem); | ||
705 | rpc_release_path(&nd); | ||
639 | return dentry; | 706 | return dentry; |
640 | 707 | err_dput: | |
641 | out_dput: | ||
642 | dput(dentry); | 708 | dput(dentry); |
643 | out_unlock: | 709 | dentry = ERR_PTR(-ENOMEM); |
644 | up(&parent->d_inode->i_sem); | 710 | printk(KERN_WARNING "%s: %s() failed to create pipe %s (errno = %d)\n", |
645 | rpc_put_mount(); | 711 | __FILE__, __FUNCTION__, path, -ENOMEM); |
646 | return dentry; | 712 | goto out; |
647 | } | 713 | } |
648 | 714 | ||
649 | void | 715 | int |
650 | rpc_unlink(struct dentry *dentry) | 716 | rpc_unlink(char *path) |
651 | { | 717 | { |
652 | struct dentry *parent = dentry->d_parent; | 718 | struct nameidata nd; |
719 | struct dentry *dentry; | ||
720 | struct inode *dir; | ||
721 | int error; | ||
653 | 722 | ||
654 | down(&parent->d_inode->i_sem); | 723 | if ((error = rpc_lookup_parent(path, &nd)) != 0) |
724 | return error; | ||
725 | dir = nd.dentry->d_inode; | ||
726 | down(&dir->i_sem); | ||
727 | dentry = lookup_hash(&nd.last, nd.dentry); | ||
728 | if (IS_ERR(dentry)) { | ||
729 | error = PTR_ERR(dentry); | ||
730 | goto out_release; | ||
731 | } | ||
732 | d_drop(dentry); | ||
655 | if (dentry->d_inode) { | 733 | if (dentry->d_inode) { |
656 | rpc_close_pipes(dentry->d_inode); | 734 | rpc_close_pipes(dentry->d_inode); |
657 | rpc_inode_setowner(dentry->d_inode, NULL); | 735 | rpc_inode_setowner(dentry->d_inode, NULL); |
658 | simple_unlink(parent->d_inode, dentry); | 736 | error = simple_unlink(dir, dentry); |
659 | } | 737 | } |
660 | up(&parent->d_inode->i_sem); | 738 | dput(dentry); |
661 | 739 | inode_dir_notify(dir, DN_DELETE); | |
662 | inode_dir_notify(parent->d_inode, DN_DELETE); | 740 | out_release: |
663 | rpc_put_mount(); | 741 | up(&dir->i_sem); |
742 | rpc_release_path(&nd); | ||
743 | return error; | ||
664 | } | 744 | } |
665 | 745 | ||
666 | /* | 746 | /* |