aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2011-03-25 01:51:20 +0800
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-24 14:54:34 -0400
commitd4a85e35d1465da055264407d8395e84483084e6 (patch)
treed3bdbf9edd438ecd1a6de1bc30b9c13b466559e5 /fs
parentf9398c233e3201874395eea8558eb616fb198648 (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/autofs4/expire.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index c403abcc725..bc482e07b92 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -87,6 +87,56 @@ done:
}
/*
+ * 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.
*/
static struct dentry *get_next_positive_dentry(struct dentry *prev,
@@ -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 */