Commit 763aca82 authored by Chen Ridong's avatar Chen Ridong
Browse files

cgroup_writeback: fix softlockup for blkcg->memcg_list

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I99KM6



--------------------------------

When multi tasks write memory.wb_blkio_ino of a memcg at same time, it may
insert same node to blkcg->memcg_list, which will lead to softlockup.
This is because no protection when write blkcg->memcg_list, and it may
also lead to NULL pointer dereference when write and rmdir same memcg
at the same time. So add spin_lock to protect blkcg->memcg_list.

The error logs:
watchdog: BUG: soft lockup - CPU#4 stuck for 23s! [rmdir:938142]
[ 5716.668802]  ? irq_work_claim+0x25/0x60
[ 5716.668812]  ? __list_add_valid+0x9c/0xe0
[ 5716.668820]  wb_kill_blkcg+0x19f/0x310
[ 5716.668829]  wb_kill_memcg_blkcg+0x8d/0xa0
[ 5716.668837]  kill_css+0x89/0xd0
[ 5716.668846]  cgroup_destroy_locked+0x1c6/0x380
[ 5716.668855]  ? css_has_online_children+0x110/0x110
[ 5716.668864]  ? selinux_inode_setxattr+0x4e0/0x4e0
[ 5716.668876]  cgroup_rmdir+0x37/0x140
[ 5716.668888]  kernfs_iop_rmdir+0xbb/0xf0
[ 5716.668898]  vfs_rmdir.part.0+0xa5/0x230
[ 5716.668909]  do_rmdir+0x2e0/0x320
[ 5716.668926]  ? do_file_open_root+0x330/0x330
[ 5716.668933]  ? __check_object_size+0x38/0x50
[ 5716.668942]  ? getname_flags+0x14d/0x320
[ 5716.668952]  do_syscall_64+0x33/0x40
[ 5716.668961]  entry_SYSCALL_64_after_hwframe+0x62/0xc7
[ 5716.668968] RIP: 0033:0x7f742706cafb

Fixes: 404067a2 ("cgroup_writeback: fix deadlock in cgroup1_writeback")
Signed-off-by: default avatarChen Ridong <chenridong@huawei.com>
parent a474d353
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -438,8 +438,8 @@ static struct cgroup_subsys_state *cgwbv1_get_blkcss(struct mem_cgroup *memcg)
	struct cgroup_subsys_state *blkcg_css;

	rcu_read_lock();
	blkcg_css = memcg->wb_blk_css;
	if (!css_tryget_online(blkcg_css)) {
	blkcg_css = READ_ONCE(memcg->wb_blk_css);
	if (!blkcg_css || !css_tryget_online(blkcg_css)) {
		blkcg_css = blkcg_root_css;
		css_get(blkcg_css);
	}
@@ -1067,6 +1067,7 @@ EXPORT_SYMBOL(wait_iff_congested);
#include "../kernel/cgroup/cgroup-internal.h"

static bool cgroup1_writeback __read_mostly;
DEFINE_SPINLOCK(wb_blk_memlist_lock);

bool cgroup1_writeback_enabled(void)
{
@@ -1080,6 +1081,7 @@ static void wb_kill_memcg(struct cgroup_subsys_state *memcg_css)

	list_del_init(&memcg->memcg_node);
	css_put(memcg->wb_blk_css);
	memcg->wb_blk_css = NULL;
}

static void wb_kill_blkcg(struct cgroup_subsys_state *blkcg_css)
@@ -1103,24 +1105,26 @@ void wb_kill_memcg_blkcg(struct cgroup_subsys_state *css)
	if (!cgroup1_writeback)
		return;

	lockdep_assert_held(&cgroup_mutex);

	spin_lock(&wb_blk_memlist_lock);
	if (ss->id == io_cgrp_id)
		wb_kill_blkcg(css);
	else if (ss->id == memory_cgrp_id)
		wb_kill_memcg(css);
	spin_unlock(&wb_blk_memlist_lock);
}

void wb_attach_memcg_to_blkcg(struct cgroup_subsys_state *memcg_css,
			      struct cgroup_subsys_state *blkcg_css)
{
	struct mem_cgroup *memcg = mem_cgroup_from_css(memcg_css);
	struct cgroup_subsys_state *pre_blkcss = memcg->wb_blk_css;
	struct cgroup_subsys_state *pre_blkcss = NULL;
	struct blkcg *blkcg = css_to_blkcg(blkcg_css);

	if (!cgroup1_writeback)
		return;

	spin_lock(&wb_blk_memlist_lock);
	pre_blkcss = memcg->wb_blk_css;
	css_get(blkcg_css);
	memcg->wb_blk_css = blkcg_css;
	if (pre_blkcss == NULL)
@@ -1129,6 +1133,7 @@ void wb_attach_memcg_to_blkcg(struct cgroup_subsys_state *memcg_css,
		list_move(&memcg->memcg_node, &blkcg->memcg_list);
		css_put(pre_blkcss);
	}
	spin_unlock(&wb_blk_memlist_lock);
}

static int __init enable_cgroup1_writeback(char *s)
+2 −3
Original line number Diff line number Diff line
@@ -5862,11 +5862,10 @@ static int wb_blkio_show(struct seq_file *m, void *v)
		return -ENOMEM;

	rcu_read_lock();
	blkcg_css = memcg->wb_blk_css;
	if (!css_tryget_online(blkcg_css)) {
	blkcg_css = READ_ONCE(memcg->wb_blk_css);
	if (!blkcg_css || !css_tryget_online(blkcg_css)) {
		kfree(path);
		rcu_read_unlock();

		return -EINVAL;
	}
	blkcg_cgroup = blkcg_css->cgroup;