Messages in this thread Patch in this message | | | From | Greg Kroah-Hartman <> | Subject | [ 45/63] fs/dcache.c: add cond_resched() to shrink_dcache_parent() | Date | Mon, 6 May 2013 15:56:23 -0700 |
| |
3.4-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Thelen <gthelen@google.com>
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>
--- fs/dcache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
--- a/fs/dcache.c +++ b/fs/dcache.c @@ -1238,8 +1238,10 @@ void shrink_dcache_parent(struct dentry LIST_HEAD(dispose); int found; - while ((found = select_parent(parent, &dispose)) != 0) + while ((found = select_parent(parent, &dispose)) != 0) { shrink_dentry_list(&dispose); + cond_resched(); + } } EXPORT_SYMBOL(shrink_dcache_parent);
| |