aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2005-01-07 21:50:46 -0800
committerLinus Torvalds <torvalds@evo.osdl.org>2005-01-07 21:50:46 -0800
commit116194f29f13541a261b0523f710b2723bd62b9f (patch)
treee93018ceb83b8f836c662a8aa0fc6a7b77ecef6c /fs
parent8f254b62810cb1333e24bbabd3cd64637ea5f5d3 (diff)
downloadhistory-116194f29f13541a261b0523f710b2723bd62b9f.tar.gz
[PATCH] sched: vfs: fix scheduling latencies in prune_dcache() and select_parent()
The attached patch fixes long scheduling latencies in select_parent() and prune_dcache(). The prune_dcache() lock-break is easy, but for select_parent() the only viable solution i found was to break out if there's a resched necessary - the reordering is not necessary and the dcache scanning/shrinking will later on do it anyway. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Nick Piggin <nickpiggin@yahoo.com.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index bd8f593a3a7dc8..9d457dfc3d676b 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -156,7 +156,7 @@ repeat:
spin_unlock(&dcache_lock);
return;
}
-
+
/*
* AV: ->d_delete() is _NOT_ allowed to block now.
*/
@@ -392,6 +392,8 @@ static void prune_dcache(int count)
struct dentry *dentry;
struct list_head *tmp;
+ cond_resched_lock(&dcache_lock);
+
tmp = dentry_unused.prev;
if (tmp == &dentry_unused)
break;
@@ -548,6 +550,13 @@ positive:
* list for prune_dcache(). We descend to the next level
* whenever the d_subdirs list is non-empty and continue
* searching.
+ *
+ * It returns zero iff there are no unused children,
+ * otherwise it returns the number of children moved to
+ * the end of the unused list. This may not be the total
+ * number of unused children, because select_parent can
+ * drop the lock and return early due to latency
+ * constraints.
*/
static int select_parent(struct dentry * parent)
{
@@ -577,6 +586,15 @@ resume:
dentry_stat.nr_unused++;
found++;
}
+
+ /*
+ * We can return to the caller if we have found some (this
+ * ensures forward progress). We'll be coming back to find
+ * the rest.
+ */
+ if (found && need_resched())
+ goto out;
+
/*
* Descend a level if the d_subdirs list is non-empty.
*/
@@ -601,6 +619,7 @@ this_parent->d_parent->d_name.name, this_parent->d_name.name, found);
#endif
goto resume;
}
+out:
spin_unlock(&dcache_lock);
return found;
}