Cgroup意外将SIGSTOP传播给父级

问题描述

我有一个小的脚本可以在限制CPU时间的cgroup中运行命令:

$ cat cgrun.sh
#!/bin/bash

if [[ $# -lt 1 ]]; then
    echo "Usage: $0 <bin>"
    exit 1
fi

sudo cgcreate -g cpu:/cpulimit
sudo cgset -r cpu.cfs_period_us=1000000 cpulimit
sudo cgset -r cpu.cfs_quota_us=100000 cpulimit
sudo cgexec -g cpu:cpulimit sudo -u $USER "$@"
sudo cgdelete cpu:/cpulimit

我让命令运行:./cgrun.sh /bin/sleep 10

然后我从另一个终端将SIGSTOP发送到sleep命令。此时,父命令sudocgexec也以某种方式也接收到该信号。然后,我将SIGCONT发送到sleep命令,该命令允许睡眠继续进行。

但是这时sudocgexec停止了,并且从没有进入睡眠过程的僵尸。我不知道这怎么会发生?我该如何预防呢?而且,我无法将SIGCONT发送到sudocgexec,因为我正在从用户发送信号,而这些命令是以root身份运行的。

这是htop中的外观(省略了一些列):

    PID USER S CPU% MEM%   TIME+  Command
1222869 user S  0.0  0.0  0:00.00 │     │  └─ /bin/bash ./cgrun.sh /bin/sleep 10
1222882 root T  0.0  0.0  0:00.00 │     │     └─ sudo cgexec -g cpu:cpulimit sudo -u user /bin/sleep 10
1222884 root T  0.0  0.0  0:00.00 │     │        └─ sudo -u desertfox /bin/sleep 10
1222887 user Z  0.0  0.0  0:00.00 │     │           └─ /bin/sleep 10

如何以不使SIGSTOP退回父进程的方式创建cgroup?

UPD

如果我使用systemd-run启动进程,则不会观察到相同的行为:

sudo systemd-run --uid=$USER -t -p CPUQuota=10% sleep 10

解决方法

我将使用shell命令以“艰难的方式”来创建 cpulimit cgroup(它是mkdir),而不是使用“ cg工具”,将cfs参数(使用相应的 cpu.cfs _ *文件中的echo命令),创建带有(...)表示法的子外壳,将其移入cgroup({{1 }}的pid命令插入cgroup的echo文件中,并在此子Shell中执行请求的命令。

因此,tasks看起来像这样:

cgrun.sh

运行它(在获取当前shell的pid以便在另一个终端中显示流程层次结构之前):

#!/bin/bash

if [[ $# -lt 1 ]]; then
    echo "Usage: $0 <bin>" >&2
    exit 1
fi

CGTREE=/sys/fs/cgroup/cpu

sudo -s <<EOF
[ ! -d ${CGTREE}/cpulimit ] && mkdir ${CGTREE}/cpulimit
echo 1000000 > ${CGTREE}/cpulimit/cpu.cfs_period_us
echo 100000 > ${CGTREE}/cpulimit/cpu.cfs_quota_us
EOF

# Sub-shell in background
(
  # Pid of the current sub-shell
  # ($$ would return the pid of the father process)
  MY_PID=$BASHPID

  # Move current process into the cgroup
  sudo sh -c "echo ${MY_PID} > ${CGTREE}/cpulimit/tasks"

  # Run the command with calling user id (it inherits the cgroup)
  exec "$@"

) &

# Wait for the sub-shell
wait $!

# Exit code of the sub-shell
rc=$?

# Delete the cgroup
sudo rmdir ${CGTREE}/cpulimit

# Exit with the return code of the sub-shell
exit $rc

这将创建以下流程层次结构:

$ echo $$
112588
$ ./cgrun.sh /bin/sleep 50

停止$ pstree -p 112588 bash(112588)-+-cgrun.sh(113079)---sleep(113086) 进程:

sleep

查看cgroup以验证是否正在运行$ kill -STOP 113086 命令(其pid在sleep文件中)并且正确设置了CFS参数:

tasks

将SIGCONT信号发送到$ ls -l /sys/fs/cgroup/cpu/cpulimit/ total 0 -rw-r--r-- 1 root root 0 nov. 5 22:38 cgroup.clone_children -rw-r--r-- 1 root root 0 nov. 5 22:38 cgroup.procs -rw-r--r-- 1 root root 0 nov. 5 22:36 cpu.cfs_period_us -rw-r--r-- 1 root root 0 nov. 5 22:36 cpu.cfs_quota_us -rw-r--r-- 1 root root 0 nov. 5 22:38 cpu.shares -r--r--r-- 1 root root 0 nov. 5 22:38 cpu.stat -rw-r--r-- 1 root root 0 nov. 5 22:38 cpu.uclamp.max -rw-r--r-- 1 root root 0 nov. 5 22:38 cpu.uclamp.min -r--r--r-- 1 root root 0 nov. 5 22:38 cpuacct.stat -rw-r--r-- 1 root root 0 nov. 5 22:38 cpuacct.usage -r--r--r-- 1 root root 0 nov. 5 22:38 cpuacct.usage_all -r--r--r-- 1 root root 0 nov. 5 22:38 cpuacct.usage_percpu -r--r--r-- 1 root root 0 nov. 5 22:38 cpuacct.usage_percpu_sys -r--r--r-- 1 root root 0 nov. 5 22:38 cpuacct.usage_percpu_user -r--r--r-- 1 root root 0 nov. 5 22:38 cpuacct.usage_sys -r--r--r-- 1 root root 0 nov. 5 22:38 cpuacct.usage_user -rw-r--r-- 1 root root 0 nov. 5 22:38 notify_on_release -rw-r--r-- 1 root root 0 nov. 5 22:36 tasks $ cat /sys/fs/cgroup/cpu/cpulimit/tasks 113086 # This is the pid of sleep $ cat /sys/fs/cgroup/cpu/cpulimit/cpu.cfs_* 1000000 100000 进程:

sleep

该过程完成并且cgroup被破坏:

$ kill -CONT 113086

完成后获取脚本的退出代码(这是已启动命令的退出代码):

$ ls -l /sys/fs/cgroup/cpu/cpulimit
ls: cannot access '/sys/fs/cgroup/cpu/cpulimit': No such file or directory

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...