[Devel] [PATCH RHEL7 COMMIT] ms/dcache: don't remove from shrink list in select_collect()
Konstantin Khorenko
khorenko at virtuozzo.com
Thu Mar 24 08:14:58 PDT 2016
The commit is pushed to "branch-rh7-3.10.0-327.10.1.vz7.12.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.10.1.vz7.12.3
------>
commit b318383cb6d1f596af70ec277d9db7b8cee7789a
Author: Al Viro <viro at zeniv.linux.org.uk>
Date: Thu Mar 24 19:14:58 2016 +0400
ms/dcache: don't remove from shrink list in select_collect()
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>
Acked-by: Dmitry Monakhov <dmonakhov at virtuozzo.com>
---
fs/dcache.c | 31 ++++++++++---------------------
1 file changed, 10 insertions(+), 21 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 30d3d70..cba54cf 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;
}
More information about the Devel
mailing list