diff options
Diffstat (limited to 'fs/autofs4/root.c')
-rw-r--r-- | fs/autofs4/root.c | 169 |
1 files changed, 139 insertions, 30 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 53dabe8d5b8b..dbb70d5a4882 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -473,6 +473,8 @@ void autofs4_dentry_release(struct dentry *de) | |||
473 | 473 | ||
474 | if (sbi) { | 474 | if (sbi) { |
475 | spin_lock(&sbi->lookup_lock); | 475 | spin_lock(&sbi->lookup_lock); |
476 | if (!list_empty(&inf->active)) | ||
477 | list_del(&inf->active); | ||
476 | if (!list_empty(&inf->expiring)) | 478 | if (!list_empty(&inf->expiring)) |
477 | list_del(&inf->expiring); | 479 | list_del(&inf->expiring); |
478 | spin_unlock(&sbi->lookup_lock); | 480 | spin_unlock(&sbi->lookup_lock); |
@@ -497,6 +499,58 @@ static struct dentry_operations autofs4_dentry_operations = { | |||
497 | .d_release = autofs4_dentry_release, | 499 | .d_release = autofs4_dentry_release, |
498 | }; | 500 | }; |
499 | 501 | ||
502 | static struct dentry *autofs4_lookup_active(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) | ||
503 | { | ||
504 | unsigned int len = name->len; | ||
505 | unsigned int hash = name->hash; | ||
506 | const unsigned char *str = name->name; | ||
507 | struct list_head *p, *head; | ||
508 | |||
509 | spin_lock(&dcache_lock); | ||
510 | spin_lock(&sbi->lookup_lock); | ||
511 | head = &sbi->active_list; | ||
512 | list_for_each(p, head) { | ||
513 | struct autofs_info *ino; | ||
514 | struct dentry *dentry; | ||
515 | struct qstr *qstr; | ||
516 | |||
517 | ino = list_entry(p, struct autofs_info, active); | ||
518 | dentry = ino->dentry; | ||
519 | |||
520 | spin_lock(&dentry->d_lock); | ||
521 | |||
522 | /* Already gone? */ | ||
523 | if (atomic_read(&dentry->d_count) == 0) | ||
524 | goto next; | ||
525 | |||
526 | qstr = &dentry->d_name; | ||
527 | |||
528 | if (dentry->d_name.hash != hash) | ||
529 | goto next; | ||
530 | if (dentry->d_parent != parent) | ||
531 | goto next; | ||
532 | |||
533 | if (qstr->len != len) | ||
534 | goto next; | ||
535 | if (memcmp(qstr->name, str, len)) | ||
536 | goto next; | ||
537 | |||
538 | if (d_unhashed(dentry)) { | ||
539 | dget(dentry); | ||
540 | spin_unlock(&dentry->d_lock); | ||
541 | spin_unlock(&sbi->lookup_lock); | ||
542 | spin_unlock(&dcache_lock); | ||
543 | return dentry; | ||
544 | } | ||
545 | next: | ||
546 | spin_unlock(&dentry->d_lock); | ||
547 | } | ||
548 | spin_unlock(&sbi->lookup_lock); | ||
549 | spin_unlock(&dcache_lock); | ||
550 | |||
551 | return NULL; | ||
552 | } | ||
553 | |||
500 | static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) | 554 | static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) |
501 | { | 555 | { |
502 | unsigned int len = name->len; | 556 | unsigned int len = name->len; |
@@ -553,7 +607,8 @@ next: | |||
553 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 607 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
554 | { | 608 | { |
555 | struct autofs_sb_info *sbi; | 609 | struct autofs_sb_info *sbi; |
556 | struct dentry *expiring; | 610 | struct autofs_info *ino; |
611 | struct dentry *expiring, *unhashed; | ||
557 | int oz_mode; | 612 | int oz_mode; |
558 | 613 | ||
559 | DPRINTK("name = %.*s", | 614 | DPRINTK("name = %.*s", |
@@ -571,12 +626,12 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
571 | 626 | ||
572 | expiring = autofs4_lookup_expiring(sbi, dentry->d_parent, &dentry->d_name); | 627 | expiring = autofs4_lookup_expiring(sbi, dentry->d_parent, &dentry->d_name); |
573 | if (expiring) { | 628 | if (expiring) { |
574 | struct autofs_info *ino = autofs4_dentry_ino(expiring); | ||
575 | /* | 629 | /* |
576 | * If we are racing with expire the request might not | 630 | * If we are racing with expire the request might not |
577 | * be quite complete but the directory has been removed | 631 | * be quite complete but the directory has been removed |
578 | * so it must have been successful, so just wait for it. | 632 | * so it must have been successful, so just wait for it. |
579 | */ | 633 | */ |
634 | ino = autofs4_dentry_ino(expiring); | ||
580 | while (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { | 635 | while (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { |
581 | DPRINTK("wait for incomplete expire %p name=%.*s", | 636 | DPRINTK("wait for incomplete expire %p name=%.*s", |
582 | expiring, expiring->d_name.len, | 637 | expiring, expiring->d_name.len, |
@@ -591,21 +646,41 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
591 | dput(expiring); | 646 | dput(expiring); |
592 | } | 647 | } |
593 | 648 | ||
594 | /* | 649 | unhashed = autofs4_lookup_active(sbi, dentry->d_parent, &dentry->d_name); |
595 | * Mark the dentry incomplete but don't hash it. We do this | 650 | if (unhashed) |
596 | * to serialize our inode creation operations (symlink and | 651 | dentry = unhashed; |
597 | * mkdir) which prevents deadlock during the callback to | 652 | else { |
598 | * the daemon. Subsequent user space lookups for the same | 653 | /* |
599 | * dentry are placed on the wait queue while the daemon | 654 | * Mark the dentry incomplete but don't hash it. We do this |
600 | * itself is allowed passage unresticted so the create | 655 | * to serialize our inode creation operations (symlink and |
601 | * operation itself can then hash the dentry. Finally, | 656 | * mkdir) which prevents deadlock during the callback to |
602 | * we check for the hashed dentry and return the newly | 657 | * the daemon. Subsequent user space lookups for the same |
603 | * hashed dentry. | 658 | * dentry are placed on the wait queue while the daemon |
604 | */ | 659 | * itself is allowed passage unresticted so the create |
605 | dentry->d_op = &autofs4_root_dentry_operations; | 660 | * operation itself can then hash the dentry. Finally, |
661 | * we check for the hashed dentry and return the newly | ||
662 | * hashed dentry. | ||
663 | */ | ||
664 | dentry->d_op = &autofs4_root_dentry_operations; | ||
665 | |||
666 | /* | ||
667 | * And we need to ensure that the same dentry is used for | ||
668 | * all following lookup calls until it is hashed so that | ||
669 | * the dentry flags are persistent throughout the request. | ||
670 | */ | ||
671 | ino = autofs4_init_ino(NULL, sbi, 0555); | ||
672 | if (!ino) | ||
673 | return ERR_PTR(-ENOMEM); | ||
674 | |||
675 | dentry->d_fsdata = ino; | ||
676 | ino->dentry = dentry; | ||
677 | |||
678 | spin_lock(&sbi->lookup_lock); | ||
679 | list_add(&ino->active, &sbi->active_list); | ||
680 | spin_unlock(&sbi->lookup_lock); | ||
606 | 681 | ||
607 | dentry->d_fsdata = NULL; | 682 | d_instantiate(dentry, NULL); |
608 | d_instantiate(dentry, NULL); | 683 | } |
609 | 684 | ||
610 | if (!oz_mode) { | 685 | if (!oz_mode) { |
611 | spin_lock(&dentry->d_lock); | 686 | spin_lock(&dentry->d_lock); |
@@ -630,12 +705,16 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
630 | if (sigismember (sigset, SIGKILL) || | 705 | if (sigismember (sigset, SIGKILL) || |
631 | sigismember (sigset, SIGQUIT) || | 706 | sigismember (sigset, SIGQUIT) || |
632 | sigismember (sigset, SIGINT)) { | 707 | sigismember (sigset, SIGINT)) { |
708 | if (unhashed) | ||
709 | dput(unhashed); | ||
633 | return ERR_PTR(-ERESTARTNOINTR); | 710 | return ERR_PTR(-ERESTARTNOINTR); |
634 | } | 711 | } |
635 | } | 712 | } |
636 | spin_lock(&dentry->d_lock); | 713 | if (!oz_mode) { |
637 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 714 | spin_lock(&dentry->d_lock); |
638 | spin_unlock(&dentry->d_lock); | 715 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; |
716 | spin_unlock(&dentry->d_lock); | ||
717 | } | ||
639 | } | 718 | } |
640 | 719 | ||
641 | /* | 720 | /* |
@@ -659,9 +738,15 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
659 | else | 738 | else |
660 | dentry = ERR_PTR(-ENOENT); | 739 | dentry = ERR_PTR(-ENOENT); |
661 | 740 | ||
741 | if (unhashed) | ||
742 | dput(unhashed); | ||
743 | |||
662 | return dentry; | 744 | return dentry; |
663 | } | 745 | } |
664 | 746 | ||
747 | if (unhashed) | ||
748 | return unhashed; | ||
749 | |||
665 | return NULL; | 750 | return NULL; |
666 | } | 751 | } |
667 | 752 | ||
@@ -682,20 +767,30 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
682 | return -EACCES; | 767 | return -EACCES; |
683 | 768 | ||
684 | ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555); | 769 | ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555); |
685 | if (ino == NULL) | 770 | if (!ino) |
686 | return -ENOSPC; | 771 | return -ENOMEM; |
687 | 772 | ||
688 | ino->size = strlen(symname); | 773 | spin_lock(&sbi->lookup_lock); |
689 | ino->u.symlink = cp = kmalloc(ino->size + 1, GFP_KERNEL); | 774 | if (!list_empty(&ino->active)) |
775 | list_del_init(&ino->active); | ||
776 | spin_unlock(&sbi->lookup_lock); | ||
690 | 777 | ||
691 | if (cp == NULL) { | 778 | cp = kmalloc(ino->size + 1, GFP_KERNEL); |
692 | kfree(ino); | 779 | if (!cp) { |
693 | return -ENOSPC; | 780 | if (!dentry->d_fsdata) |
781 | kfree(ino); | ||
782 | return -ENOMEM; | ||
694 | } | 783 | } |
695 | 784 | ||
696 | strcpy(cp, symname); | 785 | strcpy(cp, symname); |
697 | 786 | ||
698 | inode = autofs4_get_inode(dir->i_sb, ino); | 787 | inode = autofs4_get_inode(dir->i_sb, ino); |
788 | if (!inode) { | ||
789 | kfree(cp); | ||
790 | if (!dentry->d_fsdata) | ||
791 | kfree(ino); | ||
792 | return -ENOMEM; | ||
793 | } | ||
699 | d_add(dentry, inode); | 794 | d_add(dentry, inode); |
700 | 795 | ||
701 | if (dir == dir->i_sb->s_root->d_inode) | 796 | if (dir == dir->i_sb->s_root->d_inode) |
@@ -711,6 +806,8 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
711 | atomic_inc(&p_ino->count); | 806 | atomic_inc(&p_ino->count); |
712 | ino->inode = inode; | 807 | ino->inode = inode; |
713 | 808 | ||
809 | ino->size = strlen(symname); | ||
810 | ino->u.symlink = cp; | ||
714 | dir->i_mtime = CURRENT_TIME; | 811 | dir->i_mtime = CURRENT_TIME; |
715 | 812 | ||
716 | return 0; | 813 | return 0; |
@@ -755,7 +852,8 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
755 | 852 | ||
756 | spin_lock(&dcache_lock); | 853 | spin_lock(&dcache_lock); |
757 | spin_lock(&sbi->lookup_lock); | 854 | spin_lock(&sbi->lookup_lock); |
758 | list_add(&ino->expiring, &sbi->expiring_list); | 855 | if (list_empty(&ino->expiring)) |
856 | list_add(&ino->expiring, &sbi->expiring_list); | ||
759 | spin_unlock(&sbi->lookup_lock); | 857 | spin_unlock(&sbi->lookup_lock); |
760 | spin_lock(&dentry->d_lock); | 858 | spin_lock(&dentry->d_lock); |
761 | __d_drop(dentry); | 859 | __d_drop(dentry); |
@@ -783,7 +881,8 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
783 | return -ENOTEMPTY; | 881 | return -ENOTEMPTY; |
784 | } | 882 | } |
785 | spin_lock(&sbi->lookup_lock); | 883 | spin_lock(&sbi->lookup_lock); |
786 | list_add(&ino->expiring, &sbi->expiring_list); | 884 | if (list_empty(&ino->expiring)) |
885 | list_add(&ino->expiring, &sbi->expiring_list); | ||
787 | spin_unlock(&sbi->lookup_lock); | 886 | spin_unlock(&sbi->lookup_lock); |
788 | spin_lock(&dentry->d_lock); | 887 | spin_lock(&dentry->d_lock); |
789 | __d_drop(dentry); | 888 | __d_drop(dentry); |
@@ -819,10 +918,20 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
819 | dentry, dentry->d_name.len, dentry->d_name.name); | 918 | dentry, dentry->d_name.len, dentry->d_name.name); |
820 | 919 | ||
821 | ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555); | 920 | ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555); |
822 | if (ino == NULL) | 921 | if (!ino) |
823 | return -ENOSPC; | 922 | return -ENOMEM; |
923 | |||
924 | spin_lock(&sbi->lookup_lock); | ||
925 | if (!list_empty(&ino->active)) | ||
926 | list_del_init(&ino->active); | ||
927 | spin_unlock(&sbi->lookup_lock); | ||
824 | 928 | ||
825 | inode = autofs4_get_inode(dir->i_sb, ino); | 929 | inode = autofs4_get_inode(dir->i_sb, ino); |
930 | if (!inode) { | ||
931 | if (!dentry->d_fsdata) | ||
932 | kfree(ino); | ||
933 | return -ENOMEM; | ||
934 | } | ||
826 | d_add(dentry, inode); | 935 | d_add(dentry, inode); |
827 | 936 | ||
828 | if (dir == dir->i_sb->s_root->d_inode) | 937 | if (dir == dir->i_sb->s_root->d_inode) |