diff options
-rw-r--r-- | fs/autofs4/root.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 8315565ed7d4..9194e274f849 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -630,6 +630,58 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
630 | return 0; | 630 | return 0; |
631 | } | 631 | } |
632 | 632 | ||
633 | /* | ||
634 | * Version 4 of autofs provides a pseudo direct mount implementation | ||
635 | * that relies on directories at the leaves of a directory tree under | ||
636 | * an indirect mount to trigger mounts. To allow for this we need to | ||
637 | * set the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags on the leaves | ||
638 | * of the directory tree. There is no need to clear the automount flag | ||
639 | * following a mount or restore it after an expire because these mounts | ||
640 | * are always covered. However, it is neccessary to ensure that these | ||
641 | * flags are clear on non-empty directories to avoid unnecessary calls | ||
642 | * during path walks. | ||
643 | */ | ||
644 | static void autofs_set_leaf_automount_flags(struct dentry *dentry) | ||
645 | { | ||
646 | struct dentry *parent; | ||
647 | |||
648 | /* root and dentrys in the root are already handled */ | ||
649 | if (IS_ROOT(dentry->d_parent)) | ||
650 | return; | ||
651 | |||
652 | managed_dentry_set_managed(dentry); | ||
653 | |||
654 | parent = dentry->d_parent; | ||
655 | /* only consider parents below dentrys in the root */ | ||
656 | if (IS_ROOT(parent->d_parent)) | ||
657 | return; | ||
658 | managed_dentry_clear_managed(parent); | ||
659 | return; | ||
660 | } | ||
661 | |||
662 | static void autofs_clear_leaf_automount_flags(struct dentry *dentry) | ||
663 | { | ||
664 | struct list_head *d_child; | ||
665 | struct dentry *parent; | ||
666 | |||
667 | /* flags for dentrys in the root are handled elsewhere */ | ||
668 | if (IS_ROOT(dentry->d_parent)) | ||
669 | return; | ||
670 | |||
671 | managed_dentry_clear_managed(dentry); | ||
672 | |||
673 | parent = dentry->d_parent; | ||
674 | /* only consider parents below dentrys in the root */ | ||
675 | if (IS_ROOT(parent->d_parent)) | ||
676 | return; | ||
677 | d_child = &dentry->d_u.d_child; | ||
678 | /* Set parent managed if it's becoming empty */ | ||
679 | if (d_child->next == &parent->d_subdirs && | ||
680 | d_child->prev == &parent->d_subdirs) | ||
681 | managed_dentry_set_managed(parent); | ||
682 | return; | ||
683 | } | ||
684 | |||
633 | static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | 685 | static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) |
634 | { | 686 | { |
635 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 687 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
@@ -657,6 +709,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
657 | spin_unlock(&dentry->d_lock); | 709 | spin_unlock(&dentry->d_lock); |
658 | spin_unlock(&autofs4_lock); | 710 | spin_unlock(&autofs4_lock); |
659 | 711 | ||
712 | if (sbi->version < 5) | ||
713 | autofs_clear_leaf_automount_flags(dentry); | ||
714 | |||
660 | if (atomic_dec_and_test(&ino->count)) { | 715 | if (atomic_dec_and_test(&ino->count)) { |
661 | p_ino = autofs4_dentry_ino(dentry->d_parent); | 716 | p_ino = autofs4_dentry_ino(dentry->d_parent); |
662 | if (p_ino && dentry->d_parent != dentry) | 717 | if (p_ino && dentry->d_parent != dentry) |
@@ -699,6 +754,9 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
699 | } | 754 | } |
700 | d_add(dentry, inode); | 755 | d_add(dentry, inode); |
701 | 756 | ||
757 | if (sbi->version < 5) | ||
758 | autofs_set_leaf_automount_flags(dentry); | ||
759 | |||
702 | dentry->d_fsdata = ino; | 760 | dentry->d_fsdata = ino; |
703 | ino->dentry = dget(dentry); | 761 | ino->dentry = dget(dentry); |
704 | atomic_inc(&ino->count); | 762 | atomic_inc(&ino->count); |