lkml.org 
[lkml]   [2013]   [May]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 084/115] fs/dcache.c: add cond_resched() to shrink_dcache_parent()
    Date
    3.9-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
    @@ -1230,8 +1230,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);




    \
     
     \ /
      Last update: 2013-05-06 23:41    [W:2.324 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site