aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2008-07-24 00:30:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:31 -0400
commit2576737873dc1d9ea461a5955a5f6779b569a350 (patch)
treeaad8f5cf52c872f307275328022a3bcb94a6c342
parentcaf7da3d5d4d9dd873eb52d025d8cc63b89f1fdb (diff)
autofs4: use look aside list for lookups
A while ago a patch to resolve a deadlock during directory creation was merged. This delayed the hashing of lookup dentrys until the ->mkdir() (or ->symlink()) operation completed to ensure we always went through ->lookup() instead of also having processes go through ->revalidate() so our VFS locking remained consistent. Now we are seeing a couple of side affects of that change in situations with heavy mount activity. Two cases have been identified: 1) When a mount request is triggered, due to the delayed hashing, the directory created by user space for the mount point doesn't have the DCACHE_AUTOFS_PENDING flag set. In the case of an autofs multi-mount where a tree of mount point directories are created this can lead to the path walk continuing rather than the dentry being sent to the wait queue to wait for request completion. This is because, if the pending flag isn't set, the criteria for deciding this is a mount in progress fails to hold, namely that the dentry is not a mount point and has no subdirectories. 2) A mount request dentry is initially created negative and unhashed. It remains this way until the ->mkdir() callback completes. Since it is unhashed a fresh dentry is used when the user space mount request creates the mount point directory. This leaves the original dentry negative and unhashed. But revalidate has no way to tell the VFS that the dentry has changed, other than to force another ->lookup() by returning false, which is at best wastefull and at worst not possible. This results in an -ENOENT return from the original path walk when in fact the mount succeeded. To resolve this we need to ensure that the same dentry is used in all calls to ->lookup() during the course of a mount request. This patch achieves that by adding the initial dentry to a look aside list and removes it at ->mkdir() or ->symlink() completion (or when the dentry is released), since these are the only create operations autofs4 supports. Signed-off-by: Ian Kent <raven@themaw.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/autofs4/autofs_i.h2
-rw-r--r--fs/autofs4/inode.c25
-rw-r--r--fs/autofs4/root.c169
3 files changed, 156 insertions, 40 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 69b1497b0029..2dce2334737d 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -52,6 +52,7 @@ struct autofs_info {
52 52
53 int flags; 53 int flags;
54 54
55 struct list_head active;
55 struct list_head expiring; 56 struct list_head expiring;
56 57
57 struct autofs_sb_info *sbi; 58 struct autofs_sb_info *sbi;
@@ -113,6 +114,7 @@ struct autofs_sb_info {
113 spinlock_t fs_lock; 114 spinlock_t fs_lock;
114 struct autofs_wait_queue *queues; /* Wait queue pointer */ 115 struct autofs_wait_queue *queues; /* Wait queue pointer */
115 spinlock_t lookup_lock; 116 spinlock_t lookup_lock;
117 struct list_head active_list;
116 struct list_head expiring_list; 118 struct list_head expiring_list;
117}; 119};
118 120
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 94bfc154d7a2..e3e70994ab46 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -24,8 +24,10 @@
24 24
25static void ino_lnkfree(struct autofs_info *ino) 25static void ino_lnkfree(struct autofs_info *ino)
26{ 26{
27 kfree(ino->u.symlink); 27 if (ino->u.symlink) {
28 ino->u.symlink = NULL; 28 kfree(ino->u.symlink);
29 ino->u.symlink = NULL;
30 }
29} 31}
30 32
31struct autofs_info *autofs4_init_ino(struct autofs_info *ino, 33struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
@@ -41,16 +43,18 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
41 if (ino == NULL) 43 if (ino == NULL)
42 return NULL; 44 return NULL;
43 45
44 ino->flags = 0; 46 if (!reinit) {
45 ino->mode = mode; 47 ino->flags = 0;
46 ino->inode = NULL; 48 ino->inode = NULL;
47 ino->dentry = NULL; 49 ino->dentry = NULL;
48 ino->size = 0; 50 ino->size = 0;
49 51 INIT_LIST_HEAD(&ino->active);
50 INIT_LIST_HEAD(&ino->expiring); 52 INIT_LIST_HEAD(&ino->expiring);
53 atomic_set(&ino->count, 0);
54 }
51 55
56 ino->mode = mode;
52 ino->last_used = jiffies; 57 ino->last_used = jiffies;
53 atomic_set(&ino->count, 0);
54 58
55 ino->sbi = sbi; 59 ino->sbi = sbi;
56 60
@@ -339,6 +343,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
339 spin_lock_init(&sbi->fs_lock); 343 spin_lock_init(&sbi->fs_lock);
340 sbi->queues = NULL; 344 sbi->queues = NULL;
341 spin_lock_init(&sbi->lookup_lock); 345 spin_lock_init(&sbi->lookup_lock);
346 INIT_LIST_HEAD(&sbi->active_list);
342 INIT_LIST_HEAD(&sbi->expiring_list); 347 INIT_LIST_HEAD(&sbi->expiring_list);
343 s->s_blocksize = 1024; 348 s->s_blocksize = 1024;
344 s->s_blocksize_bits = 10; 349 s->s_blocksize_bits = 10;
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
502static 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 }
545next:
546 spin_unlock(&dentry->d_lock);
547 }
548 spin_unlock(&sbi->lookup_lock);
549 spin_unlock(&dcache_lock);
550
551 return NULL;
552}
553
500static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) 554static 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:
553static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 607static 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)