aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorGreg Thelen2013-04-30 17:26:48 -0500
committerGreg Kroah-Hartman2013-05-07 22:08:23 -0500
commit88d9e88d1b44a0b3947bce5d973c3ce0865ec868 (patch)
treeb8d138ac59dcbac6cfbd9912025b92837aacc7be /fs
parentdd644cc9dae03d05c128ee3aba39d18b97ebdc22 (diff)
downloadkernel-omap-88d9e88d1b44a0b3947bce5d973c3ce0865ec868.tar.gz
kernel-omap-88d9e88d1b44a0b3947bce5d973c3ce0865ec868.tar.xz
kernel-omap-88d9e88d1b44a0b3947bce5d973c3ce0865ec868.zip
fs/dcache.c: add cond_resched() to shrink_dcache_parent()
commit 421348f1ca0bf17769dee0aed4d991845ae0536d upstream. Call cond_resched() in shrink_dcache_parent() to maintain interactivity. Before this patch: void shrink_dcache_parent(struct dentry * parent) { while ((found = select_parent(parent, &dispose)) != 0) shrink_dentry_list(&dispose); } select_parent() populates the dispose list with dentries which shrink_dentry_list() then deletes. select_parent() carefully uses need_resched() to avoid doing too much work at once. But neither shrink_dcache_parent() nor its called functions call cond_resched(). So once need_resched() is set select_parent() will return single dentry dispose list which is then deleted by shrink_dentry_list(). This is inefficient when there are a lot of dentry to process. This can cause softlockup and hurts interactivity on non preemptable kernels. This change adds cond_resched() in shrink_dcache_parent(). The benefit of this is that need_resched() is quickly cleared so that future calls to select_parent() are able to efficiently return a big batch of dentry. These additional cond_resched() do not seem to impact performance, at least for the workload below. Here is a program which can cause soft lockup if other system activity sets need_resched(). int main() { struct rlimit rlim; int i; int f[100000]; char buf[20]; struct timeval t1, t2; double diff; /* cleanup past run */ system("rm -rf x"); /* boost nfile rlimit */ rlim.rlim_cur = 200000; rlim.rlim_max = 200000; if (setrlimit(RLIMIT_NOFILE, &rlim)) err(1, "setrlimit"); /* make directory for files */ if (mkdir("x", 0700)) err(1, "mkdir"); if (gettimeofday(&t1, NULL)) err(1, "gettimeofday"); /* populate directory with open files */ for (i = 0; i < 100000; i++) { snprintf(buf, sizeof(buf), "x/%d", i); f[i] = open(buf, O_CREAT); if (f[i] == -1) err(1, "open"); } /* close some of the files */ for (i = 0; i < 85000; i++) close(f[i]); /* unlink all files, even open ones */ system("rm -rf x"); if (gettimeofday(&t2, NULL)) err(1, "gettimeofday"); diff = (((double)t2.tv_sec * 1000000 + t2.tv_usec) - ((double)t1.tv_sec * 1000000 + t1.tv_usec)); printf("done: %g elapsed\n", diff/1e6); return 0; } Signed-off-by: Greg Thelen <gthelen@google.com> Signed-off-by: Dave Chinner <david@fromorbit.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index c3bbf8547537..de73da20f335 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1232,8 +1232,10 @@ void shrink_dcache_parent(struct dentry * parent)
1232 LIST_HEAD(dispose); 1232 LIST_HEAD(dispose);
1233 int found; 1233 int found;
1234 1234
1235 while ((found = select_parent(parent, &dispose)) != 0) 1235 while ((found = select_parent(parent, &dispose)) != 0) {
1236 shrink_dentry_list(&dispose); 1236 shrink_dentry_list(&dispose);
1237 cond_resched();
1238 }
1237} 1239}
1238EXPORT_SYMBOL(shrink_dcache_parent); 1240EXPORT_SYMBOL(shrink_dcache_parent);
1239 1241