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)  	return 0;  } +/* + * Version 4 of autofs provides a pseudo direct mount implementation + * that relies on directories at the leaves of a directory tree under + * an indirect mount to trigger mounts. To allow for this we need to + * set the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags on the leaves + * of the directory tree. There is no need to clear the automount flag + * following a mount or restore it after an expire because these mounts + * are always covered. However, it is neccessary to ensure that these + * flags are clear on non-empty directories to avoid unnecessary calls + * during path walks. + */ +static void autofs_set_leaf_automount_flags(struct dentry *dentry) +{ +	struct dentry *parent; + +	/* root and dentrys in the root are already handled */ +	if (IS_ROOT(dentry->d_parent)) +		return; + +	managed_dentry_set_managed(dentry); + +	parent = dentry->d_parent; +	/* only consider parents below dentrys in the root */ +	if (IS_ROOT(parent->d_parent)) +		return; +	managed_dentry_clear_managed(parent); +	return; +} + +static void autofs_clear_leaf_automount_flags(struct dentry *dentry) +{ +	struct list_head *d_child; +	struct dentry *parent; + +	/* flags for dentrys in the root are handled elsewhere */ +	if (IS_ROOT(dentry->d_parent)) +		return; + +	managed_dentry_clear_managed(dentry); + +	parent = dentry->d_parent; +	/* only consider parents below dentrys in the root */ +	if (IS_ROOT(parent->d_parent)) +		return; +	d_child = &dentry->d_u.d_child; +	/* Set parent managed if it's becoming empty */ +	if (d_child->next == &parent->d_subdirs && +	    d_child->prev == &parent->d_subdirs) +		managed_dentry_set_managed(parent); +	return; +} +  static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)  {  	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)  	spin_unlock(&dentry->d_lock);  	spin_unlock(&autofs4_lock); +	if (sbi->version < 5) +		autofs_clear_leaf_automount_flags(dentry); +  	if (atomic_dec_and_test(&ino->count)) {  		p_ino = autofs4_dentry_ino(dentry->d_parent);  		if (p_ino && dentry->d_parent != dentry) @@ -699,6 +754,9 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)  	}  	d_add(dentry, inode); +	if (sbi->version < 5) +		autofs_set_leaf_automount_flags(dentry); +  	dentry->d_fsdata = ino;  	ino->dentry = dget(dentry);  	atomic_inc(&ino->count); | 
