検証のために TASK_UNINTERRUPTIBLE なプロセスを作りたくなったときのメモ。
cgroup の freezer サブシステムを利用してプロセスを停止する(TASK_UNINTERRUPTIBLE にする) 方法を記載する。 検証は EC2 の Ubuntu 20.0.4 LTS イメージを利用した。
まず、cgroup の freezer サブシステムがマウントされていることを確認する。
# mount | grep freezer
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
次に、停止したいプロセス(今回は yes コマンドを無限に実行させて 1 CPU を使い切る)を起動する。
terminal A $ yes > /dev/null
terminal B # top -b | head
top - 23:34:59 up 2 min, 2 users, load average: 0.26, 0.12, 0.04
Tasks: 121 total, 2 running, 119 sleeping, 0 stopped, 0 zombie
%Cpu(s): 38.7 us, 12.9 sy, 0.0 ni, 48.4 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 3933.7 total, 3075.3 free, 237.1 used, 621.4 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 3470.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1409 ubuntu 20 0 7228 532 464 R 100.0 0.0 0:06.92 yes
1 root 20 0 101816 11520 8548 S 0.0 0.3 0:03.31 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
次に、freezer サブシステム配下にディレクトリを作成し、停止したいプロセスの id を tasks に書き込む。
# mkdir /sys/fs/cgroup/freezer/stw
# echo 1409 > /sys/fs/cgroup/freezer/stw/tasks
最後に、 freezer.state
に FROZEN を書き込むと、該当のプロセスを TASK_UNINTERRUPTIBLE に設定できる。 ps コマンドでも D+
になっているのがわかる。
# echo "FROZEN" > /sys/fs/cgroup/freezer/stw/freezer.state
# top -b | head
top - 23:36:07 up 3 min, 2 users, load average: 0.67, 0.28, 0.11
Tasks: 121 total, 1 running, 120 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 3.1 sy, 0.0 ni, 96.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 3933.7 total, 3074.6 free, 237.7 used, 621.4 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 3473.4 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 101816 11520 8548 S 0.0 0.3 0:03.31 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
# ps -aux | grep yes
ubuntu 1409 73.8 0.0 7228 532 pts/1 D+ 23:34 1:09 yes
TASK_UNINTERRUPTIBLE なプロセスを用意できたが、検証内容によっては注意が必要。たとえば hung_task_panic カーネルパラメータなどの動作検証はできない(意図的に FREEZER で停止しているプロセスは処理を切り上げている)。