
This is a backport of a collection of 12 upstream patches. The main one being the switch to use a rwsem instead. The next important one being the switch of the rwsem to be a per filesystem lock instead of global. See the individual patches for details. They did not require much work or wiggling to get them applied. They all come from Linus' tree and are easily located. As such I have not modified their individual headers with upstream commit ids. Verification: - two scripts, the concept behind them supplied by Vefa Bicakci. The first one causes a lot of concurrent contention in sysfs. The second script highlights how well systemd is also contending. Run Script1 followed by Script2 Without this change, Script2 has timeouts and fails. Script1: for i in `seq 20`; do (while :; do find /sys/fs/cgroup/ -type f -readable -print0 \ 2>/dev/null | xargs -0 -n 20 -r cat >&/dev/null ; done) & done for i in `seq 10`; do (while :; do systemd-run --scope -q sleep 0.5 >/dev/null; done) & done Script2: while true; do date -Is /usr/bin/time -f %e systemctl enable -q lighttpd.service || break /usr/bin/time -f %e systemctl disable -q lighttpd.service || break /usr/bin/time -f %e systemctl restart -q lighttpd.service || break sleep 0.5 || break done - also soak testing to ensure that these patches don't introduce issues Partial-Bug: 2016028 Signed-off-by: Jim Somerville <jim.somerville@windriver.com> Change-Id: I6ad64cd7c90f756c6eb904065febfeb516e73009
83 lines
2.7 KiB
Diff
83 lines
2.7 KiB
Diff
From 652fe3382d6740a60d687d74373273f0b8eb1256 Mon Sep 17 00:00:00 2001
|
|
From: Minchan Kim <minchan@kernel.org>
|
|
Date: Wed, 1 Dec 2021 15:16:48 -0800
|
|
Subject: [PATCH] kernfs: prevent early freeing of root node
|
|
|
|
Marek reported the warning below.
|
|
|
|
=========================
|
|
WARNING: held lock freed!
|
|
5.16.0-rc2+ #10984 Not tainted
|
|
-------------------------
|
|
kworker/1:0/18 is freeing memory ffff00004034e200-ffff00004034e3ff,
|
|
with a lock still held there!
|
|
ffff00004034e348 (&root->kernfs_rwsem){++++}-{3:3}, at:
|
|
__kernfs_remove+0x310/0x37c
|
|
3 locks held by kworker/1:0/18:
|
|
#0: ffff000040107938 ((wq_completion)cgroup_destroy){+.+.}-{0:0}, at:
|
|
process_one_work+0x1f0/0x6f0
|
|
#1: ffff80000b55bdc0
|
|
((work_completion)(&(&css->destroy_rwork)->work)){+.+.}-{0:0}, at:
|
|
process_one_work+0x1f0/0x6f0
|
|
#2: ffff00004034e348 (&root->kernfs_rwsem){++++}-{3:3}, at:
|
|
__kernfs_remove+0x310/0x37c
|
|
|
|
stack backtrace:
|
|
CPU: 1 PID: 18 Comm: kworker/1:0 Not tainted 5.16.0-rc2+ #10984
|
|
Hardware name: Raspberry Pi 4 Model B (DT)
|
|
Workqueue: cgroup_destroy css_free_rwork_fn
|
|
Call trace:
|
|
dump_backtrace+0x0/0x1ac
|
|
show_stack+0x18/0x24
|
|
dump_stack_lvl+0x8c/0xb8
|
|
dump_stack+0x18/0x34
|
|
debug_check_no_locks_freed+0x124/0x140
|
|
kfree+0xf0/0x3a4
|
|
kernfs_put+0x1f8/0x224
|
|
__kernfs_remove+0x1b8/0x37c
|
|
kernfs_destroy_root+0x38/0x50
|
|
css_free_rwork_fn+0x288/0x3d4
|
|
process_one_work+0x288/0x6f0
|
|
worker_thread+0x74/0x470
|
|
kthread+0x188/0x194
|
|
ret_from_fork+0x10/0x20
|
|
|
|
Since kernfs moves the kernfs_rwsem lock into root, it couldn't hold
|
|
the lock when the root node is tearing down. Thus, get the refcount
|
|
of root node.
|
|
|
|
Fixes: 393c3714081a ("kernfs: switch global kernfs_rwsem lock to per-fs lock")
|
|
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
|
Acked-by: Tejun Heo <tj@kernel.org>
|
|
Signed-off-by: Minchan Kim <minchan@kernel.org>
|
|
Link: https://lore.kernel.org/r/20211201231648.1027165-1-minchan@kernel.org
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
Signed-off-by: Jim Somerville <jim.somerville@windriver.com>
|
|
---
|
|
fs/kernfs/dir.c | 8 +++++++-
|
|
1 file changed, 7 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
|
|
index 4af4ce02f58c..21ff2d9376fb 100644
|
|
--- a/fs/kernfs/dir.c
|
|
+++ b/fs/kernfs/dir.c
|
|
@@ -969,7 +969,13 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
|
|
*/
|
|
void kernfs_destroy_root(struct kernfs_root *root)
|
|
{
|
|
- kernfs_remove(root->kn); /* will also free @root */
|
|
+ /*
|
|
+ * kernfs_remove holds kernfs_rwsem from the root so the root
|
|
+ * shouldn't be freed during the operation.
|
|
+ */
|
|
+ kernfs_get(root->kn);
|
|
+ kernfs_remove(root->kn);
|
|
+ kernfs_put(root->kn); /* will also free @root */
|
|
}
|
|
|
|
/**
|
|
--
|
|
2.25.1
|
|
|