• Greg Thelen's avatar
    fs/dcache.c: add cond_resched() to shrink_dcache_parent() · 421348f1
    Greg Thelen authored
    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: default avatarGreg Thelen <gthelen@google.com>
    Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
    Cc: <stable@kernel.org>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    421348f1
dcache.c 78.8 KB