autofs4 - fix autofs4_expire_indirect() traversal

The vfs-scale changes changed the traversal used in
autofs4_expire_indirect() from a list to a depth first tree traversal
which isn't right.

Signed-off-by: Ian Kent <raven@themaw.net>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Ian Kent 2011-03-25 01:51:20 +08:00 committed by Al Viro
parent f9398c233e
commit d4a85e35d1
1 changed files with 51 additions and 1 deletions

View File

@ -86,6 +86,56 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
return status;
}
/*
* Calculate and dget next entry in the subdirs list under root.
*/
static struct dentry *get_next_positive_subdir(struct dentry *prev,
struct dentry *root)
{
struct list_head *next;
struct dentry *p, *q;
spin_lock(&autofs4_lock);
if (prev == NULL) {
spin_lock(&root->d_lock);
prev = dget_dlock(root);
next = prev->d_subdirs.next;
p = prev;
goto start;
}
p = prev;
spin_lock(&p->d_lock);
again:
next = p->d_u.d_child.next;
start:
if (next == &root->d_subdirs) {
spin_unlock(&p->d_lock);
spin_unlock(&autofs4_lock);
dput(prev);
return NULL;
}
q = list_entry(next, struct dentry, d_u.d_child);
spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
/* Negative dentry - try next */
if (!simple_positive(q)) {
spin_unlock(&p->d_lock);
p = q;
goto again;
}
dget_dlock(q);
spin_unlock(&q->d_lock);
spin_unlock(&p->d_lock);
spin_unlock(&autofs4_lock);
dput(prev);
return q;
}
/*
* Calculate and dget next entry in top down tree traversal.
*/
@ -333,7 +383,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
timeout = sbi->exp_timeout;
dentry = NULL;
while ((dentry = get_next_positive_dentry(dentry, root))) {
while ((dentry = get_next_positive_subdir(dentry, root))) {
spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry);
/* No point expiring a pending mount */