Commit d6826843 authored by Chen Ridong's avatar Chen Ridong
Browse files

cgroup_writeback: fix deadlock in cgroup1_writeback

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



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

When read/write memory.wb_blkio_ino of a memcg, and delete the
memcg at the same time, it could cause deadlock as below:
CPU0                               CPU1
rlock(kn->active#4);
                                  lock(cgroup_mutex);
                                  lock(kn->active#4);
lock(cgroup_mutex);

Therefore, use cgroup_kn_lock_live to replace cgroup_mutex in
reading/writing memory.wb_blkio_ino. cgroup_kn_lock_live is
locking helper for cgroup kernfs methods.

Fixes: cf4973d8 ("cgroup: support cgroup writeback on cgroupv1")
Signed-off-by: default avatarChen Ridong <chenridong@huawei.com>
parent 500f783c
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -578,8 +578,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);
	}
@@ -1180,6 +1180,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)
+10 −5
Original line number Diff line number Diff line
@@ -6029,6 +6029,7 @@ static ssize_t memcg_high_async_ratio_write(struct kernfs_open_file *of,

static int wb_blkio_show(struct seq_file *m, void *v)
{
	struct kernfs_open_file *of = m->private;
	char *path;
	ino_t blkcg_id;
	struct cgroup *blkcg_cgroup;
@@ -6042,12 +6043,15 @@ static int wb_blkio_show(struct seq_file *m, void *v)
	if (!path)
		return -ENOMEM;

	mutex_lock(&cgroup_mutex);
	if (!cgroup_kn_lock_live(of->kn, false)) {
		kfree(path);
		return -ENODEV;
	}
	blkcg_css = memcg->wb_blk_css;
	blkcg_cgroup = blkcg_css->cgroup;
	blkcg_id = cgroup_ino(blkcg_cgroup);
	cgroup_path(blkcg_cgroup, path, PATH_MAX);
	mutex_unlock(&cgroup_mutex);
	cgroup_kn_unlock(of->kn);
	seq_printf(m, "wb_blkio_path:%s\n", path);
	seq_printf(m, "wb_blkio_ino:%lu\n", blkcg_id);
	kfree(path);
@@ -6073,11 +6077,12 @@ static ssize_t wb_blkio_write(struct kernfs_open_file *of, char *buf,
	if (ret)
		return ret;

	mutex_lock(&cgroup_mutex);
	if (!cgroup_kn_lock_live(of->kn, false))
		return -ENODEV;
	root = blkcg_root_css->cgroup->root;
	blk_cgroup = __cgroup_get_from_id(root, cgrp_id);
	if (IS_ERR(blk_cgroup)) {
		mutex_unlock(&cgroup_mutex);
		cgroup_kn_unlock(of->kn);
		return -EINVAL;
	}
	blkcg_css = cgroup_tryget_css(blk_cgroup, &io_cgrp_subsys);
@@ -6088,7 +6093,7 @@ static ssize_t wb_blkio_write(struct kernfs_open_file *of, char *buf,

out_unlock:
	cgroup_put(blk_cgroup);
	mutex_unlock(&cgroup_mutex);
	cgroup_kn_unlock(of->kn);

	return ret < 0 ? ret : nbytes;
}