[Devel] [PATCH rh7 2/3] dcache: don't remove from shrink list in select_collect()

Dmitry Monakhov dmonakhov at openvz.org
Thu Mar 24 08:00:49 PDT 2016


Vladimir Davydov <vdavydov at virtuozzo.com> writes:

> From: Al Viro <viro at zeniv.linux.org.uk>
>
> Backport mainstream commit:
>
>   commit fe91522a7ba82ca1a51b07e19954b3825e4aaa22
>   Author: Al Viro <viro at zeniv.linux.org.uk>
>   Date:   Sat May 3 00:02:25 2014 -0400
>
>       don't remove from shrink list in select_collect()
>
>           If we find something already on a shrink list, just increment
>       data->found and do nothing else.  Loops in shrink_dcache_parent() and
>       check_submounts_and_drop() will do the right thing - everything we
>       did put into our list will be evicted and if there had been nothing,
>       but data->found got non-zero, well, we have somebody else shrinking
>       those guys; just try again.
>
>       Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
>
> Dcache shrinker temporarily adds dentries to a shrink list before
> dropping them. This list is allocated on stack and not protected by any
> locks, therefore only the caller (i.e. the process scanning dcache) can
> safely remove entries from it. Currently, however, dentries can be
> removed from a shrink list by dentry_kill() and select_collect(). If
> this races with a shrinker invocation, we'll get list corruption:
>
>   WARNING: at lib/list_debug.c:59 __list_del_entry+0xa1/0xd0()
>   list_del corruption. prev->next should be ffff8801e1621980, but was ffff8801de3155c0
>   CPU: 5 PID: 58031 Comm: trinity-main ve: 101 Not tainted 3.10.0-327.3.1.vz7.10.11 #1 10.11
>    000000000000003b 00000000d7f09cf1 ffff8800a3ca3b80 ffffffff816306f3
>    ffff8800a3ca3bb8 ffffffff8107b4c0 ffff8801e1621900 ffff8801e1621980
>    ffff880207c172b8 ffff8801e27069c0 0000000000000000 ffff8800a3ca3c20
>   Call Trace:
>    [<ffffffff816306f3>] dump_stack+0x19/0x1b
>    [<ffffffff8107b4c0>] warn_slowpath_common+0x70/0xb0
>    [<ffffffff8107b55c>] warn_slowpath_fmt+0x5c/0x80
>    [<ffffffff8130a0f1>] __list_del_entry+0xa1/0xd0
>    [<ffffffff8121083c>] d_shrink_del+0x2c/0x80
>    [<ffffffff81210fe5>] dentry_lru_del+0x25/0x30
>    [<ffffffff812116f1>] dput+0x161/0x280
>    [<ffffffff812057f5>] lookup_fast+0x275/0x2e0
>    [<ffffffff8120833c>] path_lookupat+0x16c/0x7a0
>    [<ffffffff81214dc7>] ? inode_init_always+0x107/0x1e0
>    [<ffffffff811db380>] ? kmem_cache_alloc+0xf0/0x220
>    [<ffffffff8120ab5f>] ? getname_flags+0x4f/0x1a0
>    [<ffffffff8120899b>] filename_lookup+0x2b/0xc0
>    [<ffffffff8120bc87>] user_path_at_empty+0x67/0xc0
>    [<ffffffff81112962>] ? from_kgid_munged+0x12/0x20
>    [<ffffffff811ff9e9>] ? cp_new_stat+0x149/0x180
>    [<ffffffff8120bcf1>] user_path_at+0x11/0x20
>    [<ffffffff811ff4f3>] vfs_fstatat+0x63/0xc0
>    [<ffffffff811ffb04>] SYSC_newfstatat+0x24/0x60
>    [<ffffffff8111c724>] ? __audit_syscall_entry+0xb4/0x110
>    [<ffffffff81022923>] ? syscall_trace_enter+0x173/0x220
>    [<ffffffff81640ff3>] ? tracesys+0x7e/0xe2
>    [<ffffffff811ffd4e>] SyS_newfstatat+0xe/0x10
>    [<ffffffff81641052>] tracesys+0xdd/0xe2
>
> https://jira.sw.ru/browse/PSBM-44210
>
> Signed-off-by: Vladimir Davydov <vdavydov at virtuozzo.com>
Ack-by: dmonakhov at openvz.org

> ---
>  fs/dcache.c | 31 ++++++++++---------------------
>  1 file changed, 10 insertions(+), 21 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 30d3d706f32e..cba54cf702f5 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1414,34 +1414,23 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
>  	if (data->start == dentry)
>  		goto out;
>  
> -	/*
> -	 * move only zero ref count dentries to the dispose list.
> -	 *
> -	 * Those which are presently on the shrink list, being processed
> -	 * by shrink_dentry_list(), shouldn't be moved.  Otherwise the
> -	 * loop in shrink_dcache_parent() might not make any progress
> -	 * and loop forever.
> -	 */
> -	if (dentry->d_lockref.count) {
> -		dentry_lru_del(dentry);
> -	} else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
> -		/*
> -		 * We can't use d_lru_shrink_move() because we
> -		 * need to get the global LRU lock and do the
> -		 * RLU accounting.
> -		 */
> -		d_lru_del(dentry);
> -		d_shrink_add(dentry, &data->dispose);
> +	if (dentry->d_flags & DCACHE_SHRINK_LIST) {
>  		data->found++;
> -		ret = D_WALK_NORETRY;
> +	} else {
> +		if (dentry->d_flags & DCACHE_LRU_LIST)
> +			d_lru_del(dentry);
> +		if (!dentry->d_lockref.count) {
> +			d_shrink_add(dentry, &data->dispose);
> +			data->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 (data->found && need_resched())
> -		ret = D_WALK_QUIT;
> +	if (!list_empty(&data->dispose))
> +		ret = need_resched() ? D_WALK_QUIT : D_WALK_NORETRY;
>  out:
>  	return ret;
>  }
> -- 
> 2.1.4
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 472 bytes
Desc: not available
URL: <http://lists.openvz.org/pipermail/devel/attachments/20160324/a8d4be8c/attachment.sig>


More information about the Devel mailing list