From: Nick Piggin This one came back. It is the VFS: Busy inodes after unmount. Self-destruct in 5 seconds. Have a nice day... thing. Signed-off-by: Andrew Morton --- 25-akpm/fs/dcache.c | 26 +++++++++++++++++--------- 1 files changed, 17 insertions(+), 9 deletions(-) diff -puN fs/dcache.c~sched-vfs-fix-scheduling-latencies-in-prune_dcache-and-select_parent-fix fs/dcache.c --- 25/fs/dcache.c~sched-vfs-fix-scheduling-latencies-in-prune_dcache-and-select_parent-fix 2004-11-15 20:01:46.176657040 -0800 +++ 25-akpm/fs/dcache.c 2004-11-15 20:01:46.181656280 -0800 @@ -156,7 +156,7 @@ repeat: spin_unlock(&dcache_lock); return; } - + /* * AV: ->d_delete() is _NOT_ allowed to block now. */ @@ -550,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) { @@ -566,14 +573,6 @@ resume: struct dentry *dentry = list_entry(tmp, struct dentry, d_child); next = tmp->next; - /* - * select_parent() is a performance optimization, it is - * not necessary to complete it. Abort if a reschedule is - * pending: - */ - if (need_resched()) - goto out; - if (!list_empty(&dentry->d_lru)) { dentry_stat.nr_unused--; list_del_init(&dentry->d_lru); @@ -587,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. */ _