395 Star 1.4K Fork 1.3K

GVPopenEuler / kernel

 / 详情

[openEuler-1.0-LTS] Backport cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock

已完成
任务
创建于  
2023-03-08 18:02

问题原因
长稳测试中,频繁修改cfs_watch_dog,该路径中存在
cpus_read_lock()
smp_call_on_cpu()
cpus_read_unlock()

由于smp_call_on_cpu()中加队列操作,worker_thread中发现没有idle,化身为manager执行管理操作,创建worker。

worker_thread
    maybe_create_worker
        create_worker
            __kthread_create_on_node
                wait_for_completion_killable
                    wait_for_common
                        schedule_timeout

create_kthread
	kernel_thread
		_do_fork
			copy_process
				cgroup_threadgroup_change_begin
				threadgroup_rwsem_read

此时如果有cpu上下线操作
获取了cpus_write_lock(),此时cpus_write_lock被前面得cpus_read_lock卡住,且后续cpus_read_lock也会被卡住。

此时还有cgroup_procs_write操作,写入cgroup.procs,先拿到了cgroup_threadgroup_rwsem写锁,再尝试拿cpus_read_lock,被之前cpu上下线得cpus_write_lock阻塞。
cgroup_file_write
__cgroup1_procs_write
cpus_read_lock
cgroup_threadgroup_rwsem
cgroup_attach_task
cgroup_migrate_execute
cpuset_attach
//cpus_read_lock
线程上下线启动线程中threadgroup_rwsem_read,被刺客cgroup_threadgroup_rwsem写信号量阻塞,形成死锁。

解决方案,保障cpus_read_lock一定在cgroup_threadgroup_rwsem之前上锁。考虑4.19当前cpuset_mutex在cpus_read_lock之前上锁,此时合入cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock会引起这个cpus_read_lock在cpuset_mutex之前上锁,很容易导致死锁。故回合5.4补丁,交换cpus_read_lock和cpuset_mutex锁顺序。

补丁1(cgroup/cpuset: Change cpuset_rwsem and hotplug lock order)
修改上锁顺序,保障cpus_read_lock在cpuset_mutex之前上锁。
冲突说明

  1. 未合入性能补丁,1243dc518c9da467da6635313a2dbb41b8ffc275 (cgroup/cpuset: Convert cpuset_mutex to percpu_rwsem),故补丁中cpuset_rwsem还是使用cpuset_mutex。
  2. 无sched_partition_write接口,相关锁无需加减。检索删除了cpus_read_lock的rebuild_sched_domains_locked这个函数,无其他调用点。
  3. 4.19lts补丁aa44002e7db25f333ddf412fb81e8db6c100841a("cpuset: Fix unsafe lock order between cpuset lock and cpuslock"),保持了get_online_cpus与cpuset_mutex上锁顺序为,先cpuset_mutex->get_online_cpus,此时我们修改了这个锁序,将这个锁放到cpuset_mutex外侧。

补丁2(cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock)由于唤醒cpu执行创建或销毁任务时,可能会请求threadgroup_rwsem的读锁,因此threadgroup_rwsem需要在cpus_read_lock的保护之下。但是,cpuset的attach()函数,需要被threadgroup_rwsem的写锁保护,同时也希望禁止cpu的hotplug (这需要执行cpus_read_lock()),这样就会导致死锁。
也就是存在这样一个路径,一个唤醒cpu执行任务操作,先请求了cpus_read_lock,再请求threadgroup_rwsem的读锁。同时另一个任务执行了cpuset的attach操作,先获取了threadgroup_rwsem的写锁,去请求cpu_read_lock。两者顺序相反,导致死锁。
故解决方案为,保障cpuset在获取threadgroup_rwsem写锁之前,先拿cpu_read_lock,保障获取锁顺序一致。

补丁冲突说明 :未合入两个性能补丁,其作用在于判断某些条件不需要上锁,在上锁时加入判断。适配修改,不加判断,都上锁。
9a3284fad42f66bb43629c6716709ff791aaa457 (cgroup: Optimize single thread migration)
671c11f0619e5ccb380bcf0f062f69ba95fc974a (cgroup: Elide write-locking threadgroup_rwsem when updating csses on an empty subtree)

补丁3("cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock")补丁中,遗漏cgroup_attach_task_all函数未设置cpu_read_lock就执行cpuset_attach。
冲突说明 直接引入cpus_read_lock无定义报错,引入linux/cpu.h头文件发生kabi冲突,询问因为头文件导致某些结构体的可见性发生了改变。参考主线补丁075b593f54f0f3883532cb750081cae6917bc8fe("cgroup: Use cgroup_attach_{lock,unlock}() from cgroup_attach_task_all()")把cgroup_attach_lock引入。无kabi冲突

评论 (1)

Cai Xinchen 创建了任务
openeuler-ci-bot 添加了
 
sig/Kernel
标签
Cai Xinchen 修改了描述
Cai Xinchen 修改了描述
Cai Xinchen 修改了描述
zhangchangzhong 通过src-openeuler/kernel Pull Request !993任务状态待办的 修改为已完成

登录 后才可以发表评论

状态
负责人
项目
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
预计工期 (小时)
参与者(2)
5329419 openeuler ci bot 1632792936
C
1
https://gitee.com/openeuler/kernel.git
git@gitee.com:openeuler/kernel.git
openeuler
kernel
kernel

搜索帮助