FAILED: patch "[PATCH] mm: memcg: synchronize objcg lists with a dedicated spinlock" failed to apply to 5.10-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 0764db9b49c932b89ee4d9e3236dff4bb07b4a66 Mon Sep 17 00:00:00 2001
From: Roman Gushchin <[email protected]>
Date: Fri, 11 Feb 2022 16:32:32 -0800
Subject: [PATCH] mm: memcg: synchronize objcg lists with a dedicated spinlock
Alexander reported a circular lock dependency revealed by the mmap1 ltp test:
LOCKDEP_CIRCULAR (suite: ltp, case: mtest06 (mmap1))
WARNING: possible circular locking dependency detected
5.17.0-20220113.rc0.git0.f2211f194038.300.fc35.s390x+debug #1 Not tainted
------------------------------------------------------
mmap1/202299 is trying to acquire lock:
00000001892c0188 (css_set_lock){..-.}-{2:2}, at: obj_cgroup_release+0x4a/0xe0
but task is already holding lock:
00000000ca3b3818 (&sighand->siglock){-.-.}-{2:2}, at: force_sig_info_to_task+0x38/0x180
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&sighand->siglock){-.-.}-{2:2}:
__lock_acquire+0x604/0xbd8
lock_acquire.part.0+0xe2/0x238
lock_acquire+0xb0/0x200
_raw_spin_lock_irqsave+0x6a/0xd8
__lock_task_sighand+0x90/0x190
cgroup_freeze_task+0x2e/0x90
cgroup_migrate_execute+0x11c/0x608
cgroup_update_dfl_csses+0x246/0x270
cgroup_subtree_control_write+0x238/0x518
kernfs_fop_write_iter+0x13e/0x1e0
new_sync_write+0x100/0x190
vfs_write+0x22c/0x2d8
ksys_write+0x6c/0xf8
__do_syscall+0x1da/0x208
system_call+0x82/0xb0
-> #0 (css_set_lock){..-.}-{2:2}:
check_prev_add+0xe0/0xed8
validate_chain+0x736/0xb20
__lock_acquire+0x604/0xbd8
lock_acquire.part.0+0xe2/0x238
lock_acquire+0xb0/0x200
_raw_spin_lock_irqsave+0x6a/0xd8
obj_cgroup_release+0x4a/0xe0
percpu_ref_put_many.constprop.0+0x150/0x168
drain_obj_stock+0x94/0xe8
refill_obj_stock+0x94/0x278
obj_cgroup_charge+0x164/0x1d8
kmem_cache_alloc+0xac/0x528
__sigqueue_alloc+0x150/0x308
__send_signal+0x260/0x550
send_signal+0x7e/0x348
force_sig_info_to_task+0x104/0x180
force_sig_fault+0x48/0x58
__do_pgm_check+0x120/0x1f0
pgm_check_handler+0x11e/0x180
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&sighand->siglock);
lock(css_set_lock);
lock(&sighand->siglock);
lock(css_set_lock);
*** DEADLOCK ***
2 locks held by mmap1/202299:
#0: 00000000ca3b3818 (&sighand->siglock){-.-.}-{2:2}, at: force_sig_info_to_task+0x38/0x180
#1: 00000001892ad560 (rcu_read_lock){....}-{1:2}, at: percpu_ref_put_many.constprop.0+0x0/0x168
stack backtrace:
CPU: 15 PID: 202299 Comm: mmap1 Not tainted 5.17.0-20220113.rc0.git0.f2211f194038.300.fc35.s390x+debug #1
Hardware name: IBM 3906 M04 704 (LPAR)
Call Trace:
dump_stack_lvl+0x76/0x98
check_noncircular+0x136/0x158
check_prev_add+0xe0/0xed8
validate_chain+0x736/0xb20
__lock_acquire+0x604/0xbd8
lock_acquire.part.0+0xe2/0x238
lock_acquire+0xb0/0x200
_raw_spin_lock_irqsave+0x6a/0xd8
obj_cgroup_release+0x4a/0xe0
percpu_ref_put_many.constprop.0+0x150/0x168
drain_obj_stock+0x94/0xe8
refill_obj_stock+0x94/0x278
obj_cgroup_charge+0x164/0x1d8
kmem_cache_alloc+0xac/0x528
__sigqueue_alloc+0x150/0x308
__send_signal+0x260/0x550
send_signal+0x7e/0x348
force_sig_info_to_task+0x104/0x180
force_sig_fault+0x48/0x58
__do_pgm_check+0x120/0x1f0
pgm_check_handler+0x11e/0x180
INFO: lockdep is turned off.In this example a slab allocation from __send_signal() caused a refilling and draining of a percpu objcg stock, resulted in a releasing of another non-related objcg. Objcg release path requires taking the css_set_lock, which is used to synchronize objcg lists.
This can create a circular dependency with the sighandler lock, which is taken with the locked css_set_lock by the freezer code (to freeze a task).
In general it seems that using css_set_lock to synchronize objcg lists makes any slab allocations and deallocation with the locked css_set_lock and any intervened locks risky.
To fix the problem and make the code more robust let's stop using css_set_lock to synchronize objcg lists and use a new dedicated spinlock instead.
include/linux/memcontrol.h +3 -2
@@ -219,7 +219,7 @@ struct obj_cgroup {struct mem_cgroup *memcg;atomic_t nr_charged_bytes;union { -struct list_head list; +struct list_head list;/* protected by objcg_lock */ struct rcu_head rcu; }; };
@@ -315,7 +315,8 @@ struct mem_cgroup {#ifdef CONFIG_MEMCG_KMEM int kmemcg_id;struct obj_cgroup __rcu *objcg; -struct list_head objcg_list;/* list of inherited objcgs */ +/* list of inherited objcgs, protected by objcg_lock */ +struct list_head objcg_list;#endif MEMCG_PADDING (_pad2_);
mm/memcontrol.c +5 -5
@@ -254,7 +254,7 @@ struct mem_cgroup *vmpressure_to_memcg(struct vmpressure *vmpr) }#ifdef CONFIG_MEMCG_KMEM -extern spinlock_t css_set_lock; +static DEFINE_SPINLOCK (objcg_lock);bool mem_cgroup_kmem_disabled (void ) {
@@ -298,9 +298,9 @@ static void obj_cgroup_release(struct percpu_ref *ref)if (nr_pages)obj_cgroup_uncharge_pages (objcg, nr_pages); -spin_lock_irqsave (&css_set_lock, flags); +spin_lock_irqsave (&objcg_lock, flags);list_del (&objcg->list); -spin_unlock_irqrestore (&css_set_lock, flags); +spin_unlock_irqrestore (&objcg_lock, flags);percpu_ref_exit (ref);kfree_rcu (objcg, rcu);
@@ -332,7 +332,7 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg, objcg =rcu_replace_pointer (memcg->objcg,NULL , true); -spin_lock_irq (&css_set_lock); +spin_lock_irq (&objcg_lock);/* 1) Ready to reparent active objcg. */ list_add (&objcg->list, &memcg->objcg_list);
@@ -342,7 +342,7 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg,/* 3) Move already reparented objcgs to the parent's list */ list_splice (&memcg->objcg_list, &parent->objcg_list); -spin_unlock_irq (&css_set_lock); +spin_unlock_irq (&objcg_lock);percpu_ref_kill (&objcg->refcnt); }
Roman Gushchin
Tested-by Alexander Egorenkov Reviewed-by Waiman Long Acked-by Tejun Heo Reviewed-by Shakeel Butt Reviewed-by Jeremy Linton Tested-by Jeremy LintonQuoted 6 lines · Greg Kroah-Hartman
The patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Quoted 6 lines
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Hi Greg!
Below is the backport of 0764db9b49c9 ("mm: memcg: synchronize objcg lists with a dedicated spinlock") to 5.10-stable.
Thanks!
--
From 43272d8809626549b7392d91e694afa74810fb00 Mon Sep 17 00:00:00 2001
From: Roman Gushchin <[email protected]>
Date: Fri, 11 Feb 2022 16:32:32 -0800
Subject: [PATCH] mm: memcg: synchronize objcg lists with a dedicated spinlock
Alexander reported a circular lock dependency revealed by the mmap1 ltp test:
LOCKDEP_CIRCULAR (suite: ltp, case: mtest06 (mmap1))
WARNING: possible circular locking dependency detected
5.17.0-20220113.rc0.git0.f2211f194038.300.fc35.s390x+debug #1 Not tainted
------------------------------------------------------
mmap1/202299 is trying to acquire lock:
00000001892c0188 (css_set_lock){..-.}-{2:2}, at: obj_cgroup_release+0x4a/0xe0
but task is already holding lock:
00000000ca3b3818 (&sighand->siglock){-.-.}-{2:2}, at: force_sig_info_to_task+0x38/0x180
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&sighand->siglock){-.-.}-{2:2}:
__lock_acquire+0x604/0xbd8
lock_acquire.part.0+0xe2/0x238
lock_acquire+0xb0/0x200
_raw_spin_lock_irqsave+0x6a/0xd8
__lock_task_sighand+0x90/0x190
cgroup_freeze_task+0x2e/0x90
cgroup_migrate_execute+0x11c/0x608
cgroup_update_dfl_csses+0x246/0x270
cgroup_subtree_control_write+0x238/0x518
kernfs_fop_write_iter+0x13e/0x1e0
new_sync_write+0x100/0x190
vfs_write+0x22c/0x2d8
ksys_write+0x6c/0xf8
__do_syscall+0x1da/0x208
system_call+0x82/0xb0
-> #0 (css_set_lock){..-.}-{2:2}:
check_prev_add+0xe0/0xed8
validate_chain+0x736/0xb20
__lock_acquire+0x604/0xbd8
lock_acquire.part.0+0xe2/0x238
lock_acquire+0xb0/0x200
_raw_spin_lock_irqsave+0x6a/0xd8
obj_cgroup_release+0x4a/0xe0
percpu_ref_put_many.constprop.0+0x150/0x168
drain_obj_stock+0x94/0xe8
refill_obj_stock+0x94/0x278
obj_cgroup_charge+0x164/0x1d8
kmem_cache_alloc+0xac/0x528
__sigqueue_alloc+0x150/0x308
__send_signal+0x260/0x550
send_signal+0x7e/0x348
force_sig_info_to_task+0x104/0x180
force_sig_fault+0x48/0x58
__do_pgm_check+0x120/0x1f0
pgm_check_handler+0x11e/0x180
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&sighand->siglock);
lock(css_set_lock);
lock(&sighand->siglock);
lock(css_set_lock);
*** DEADLOCK ***
2 locks held by mmap1/202299:
#0: 00000000ca3b3818 (&sighand->siglock){-.-.}-{2:2}, at: force_sig_info_to_task+0x38/0x180
#1: 00000001892ad560 (rcu_read_lock){....}-{1:2}, at: percpu_ref_put_many.constprop.0+0x0/0x168
stack backtrace:
CPU: 15 PID: 202299 Comm: mmap1 Not tainted 5.17.0-20220113.rc0.git0.f2211f194038.300.fc35.s390x+debug #1
Hardware name: IBM 3906 M04 704 (LPAR)
Call Trace:
dump_stack_lvl+0x76/0x98
check_noncircular+0x136/0x158
check_prev_add+0xe0/0xed8
validate_chain+0x736/0xb20
__lock_acquire+0x604/0xbd8
lock_acquire.part.0+0xe2/0x238
lock_acquire+0xb0/0x200
_raw_spin_lock_irqsave+0x6a/0xd8
obj_cgroup_release+0x4a/0xe0
percpu_ref_put_many.constprop.0+0x150/0x168
drain_obj_stock+0x94/0xe8
refill_obj_stock+0x94/0x278
obj_cgroup_charge+0x164/0x1d8
kmem_cache_alloc+0xac/0x528
__sigqueue_alloc+0x150/0x308
__send_signal+0x260/0x550
send_signal+0x7e/0x348
force_sig_info_to_task+0x104/0x180
force_sig_fault+0x48/0x58
__do_pgm_check+0x120/0x1f0
pgm_check_handler+0x11e/0x180
INFO: lockdep is turned off.In this example a slab allocation from __send_signal() caused a refilling and draining of a percpu objcg stock, resulted in a releasing of another non-related objcg. Objcg release path requires taking the css_set_lock, which is used to synchronize objcg lists.
This can create a circular dependency with the sighandler lock, which is taken with the locked css_set_lock by the freezer code (to freeze a task).
In general it seems that using css_set_lock to synchronize objcg lists makes any slab allocations and deallocation with the locked css_set_lock and any intervened locks risky.
To fix the problem and make the code more robust let's stop using css_set_lock to synchronize objcg lists and use a new dedicated spinlock instead.
--- include/linux/memcontrol.h | 5 +++-- mm/memcontrol.c | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-)
include/linux/memcontrol.h +3 -2
@@ -197,7 +197,7 @@ struct obj_cgroup {struct mem_cgroup *memcg;atomic_t nr_charged_bytes;union { -struct list_head list; +struct list_head list;/* protected by objcg_lock */ struct rcu_head rcu; }; };
@@ -300,7 +300,8 @@ struct mem_cgroup {int kmemcg_id;enum memcg_kmem_state kmem_state;struct obj_cgroup __rcu *objcg; -struct list_head objcg_list;/* list of inherited objcgs */ +/* list of inherited objcgs, protected by objcg_lock */ +struct list_head objcg_list;#endif MEMCG_PADDING (_pad2_);
mm/memcontrol.c +5 -5
@@ -250,7 +250,7 @@ struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr) }#ifdef CONFIG_MEMCG_KMEM -extern spinlock_t css_set_lock; +static DEFINE_SPINLOCK (objcg_lock);static void obj_cgroup_release (struct percpu_ref *ref) {
@@ -284,13 +284,13 @@ static void obj_cgroup_release(struct percpu_ref *ref)WARN_ON_ONCE (nr_bytes & (PAGE_SIZE -1 )); nr_pages = nr_bytes >>PAGE_SHIFT ; -spin_lock_irqsave (&css_set_lock, flags); +spin_lock_irqsave (&objcg_lock, flags); memcg =obj_cgroup_memcg (objcg);if (nr_pages)__memcg_kmem_uncharge (memcg, nr_pages);list_del (&objcg->list);mem_cgroup_put (memcg); -spin_unlock_irqrestore (&css_set_lock, flags); +spin_unlock_irqrestore (&objcg_lock, flags);percpu_ref_exit (ref);kfree_rcu (objcg, rcu);
@@ -322,7 +322,7 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg, objcg =rcu_replace_pointer (memcg->objcg,NULL , true); -spin_lock_irq (&css_set_lock); +spin_lock_irq (&objcg_lock);/* Move active objcg to the parent's list */ xchg (&objcg->memcg, parent);
@@ -337,7 +337,7 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg, }list_splice (&memcg->objcg_list, &parent->objcg_list); -spin_unlock_irq (&css_set_lock); +spin_unlock_irq (&objcg_lock);percpu_ref_kill (&objcg->refcnt); }
Signature · 1 line
2.34.1
Greg KH
maintainerQuoted 11 lines · Roman Gushchin
Quoted 10 lines · Greg Kroah-Hartman
The patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.thanks,
greg k-h
Quoted 7 lines
Quoted 2 lines
------------------ original commit in Linus's tree ------------------
Hi Greg!
Below is the backport of
0764db9b49c9("mm: memcg: synchronize objcg lists with a dedicated spinlock") to 5.10-stable.
Now queued up,t hanks.
greg k-h