libvirtd日志报错virCgroupSetValueStr"No space left on device"

/var/lob/libvirt/libvirtd.log日志中有关于 cgroup 无法设置cpuset,cpu,cpuacct相关的

2018-07-30 10:26:46.764+0000| 24902| error | virCgroupSetValueStr:669 | Unable to write to '/sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemu\x2dexample\x2dad04f.scope/tasks': No space left on device
2018-07-30 10:26:46.764+0000| 24902| error | virCgroupRemoveRecursively:1042 | Unable to remove /sys/fs/cgroup/memory/machine.slice/machine-qemu\x2dexample\x2dad04f.scope/ (16)
2018-07-30 10:26:46.764+0000| 24902| error | virCgroupRemoveRecursively:1042 | Unable to remove /sys/fs/cgroup/devices/machine.slice/machine-qemu\x2dexample\x2dad04f.scope/ (16)
2018-07-30 10:26:46.764+0000| 24902| error | virCgroupRemoveRecursively:1042 | Unable to remove /sys/fs/cgroup/blkio/machine.slice/machine-qemu\x2dexample\x2dad04f.scope/ (16)

检查可以发现libvirtd默认应该建立的 /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemu\x2dexample\x2dad04f.scope/ cgroup控制组没有建立,所以在添加pid到 tasks 时候失败。不过,和常见的文件目录不存在报错No such file or directory不同,在cgroup的控制组中如果不能写入,都是显示No space left on devices

libvirt的cgroup

  • 可以看到,当创创建启动第一个虚拟机时候,libvirt创建了/sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice这个cgroup控制组,但是检查这个目录下的cpuset.memscpuset.cpus内容都是空的。

模拟创建cgroup

cgcreate -g cpuset:machine.slice/machine-qemu\x2diso\x2dexample\x2dtest.scope

创建完成后可以看到建立了目录/sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemux2disox2dexamplex2dtest.scope,注意此时这个目录下的 cpuset.cpuscpuset.mems 内容也是空的。

此时还不能加入task的pid

#echo 8324 > /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemux2disox2dexamplex2dtest.scope/tasks
-bash: echo: write error: No space left on device

而且也不能设置cpus(需要一级级设置):

#echo "0-63" > /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemux2disox2dexamplex2dtest.scope/cpuset.cpus
-bash: echo: write error: Permission denied

这是因为上一级cpuset.cpus没有设置,所以先设置上一级,然后设置下一级

#echo "0-63" > /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/cpuset.cpus

#echo "0-63" > /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemux2disox2dexamplex2dtest.scope/cpuset.cpus

#cat /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/cpuset.cpus
0-63

#cat /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemux2disox2dexamplex2dtest.scope/cpuset.cpus
0-63

同样也要设置好两级cpuset.mems:

#echo 0 > /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/cpuset.mems

#echo 0 > /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemux2disox2dexamplex2dtest.scope/cpuset.mems

此时就可以设置tasks不再报错

#echo 8324 > /sys/fs/cgroup/cpuset,cpu,cpuacct/machine.slice/machine-qemux2disox2dexamplex2dtest.scope/tasks

具体排查,请参考libvirt程序调试排错

No space left on device可能的其他原因

CGroups and No Space这篇文档让我想起这个问题以前处理过,在某次写脚本设置进程的cgroup时遇到过并且也解决过:

在设置cgroup控制组的时候,必须同时设置cpuset.cpuscpuset.mems两个值,否则会导致报错No space left on device

例如:

创建一个cgroup控制组my_app

cgcreate -g cpuset:my_app

如果操作系统是CentOS 5.x,则/cgroup/cpuset/my_app/cpuset.cpus/cgroup/cpuset/my_app/cpuset.mems值都是空的:

#cat /cgroup/cpuset/my_app/cpuset.cpus

#cat /cgroup/cpuset/my_app/cpuset.mems

如果操作系统是CentOS 7.x,则/sys/fs/cgroup/cpuset/my_app/cpuset.cpus/sys/fs/cgroup/cpuset/my_app/cpuset.mems值此时是空的:

#cat /sys/fs/cgroup/cpuset/my_app/cpuset.cpus

#cat /sys/fs/cgroup/cpuset/my_app/cpuset.mems

CentOS 7需要安装libcgroup-tools软件包才有cgcreate工具

如果此时只设置 cgroup 控制组 my_appcpuset.cpus 值,没有设置 cpuset.mems ,却马上将某个进程的pid加入到 my_app/tasks 中就会同样报错 ``

#cgset -r cpuset.cpus=32 my_app

#cat /sys/fs/cgroup/cpuset/my_app/cpuset.cpus
32

#cat /sys/fs/cgroup/cpuset/my_app/cpuset.mems

假设有一个进程 my_example_app.sh 的 pid 是 13058 ,需要将这个进程归到my_app这个cgroup控制组,我们通常可以使用:

echo 13058 >  /sys/fs/cgroup/cpuset/my_app/tasks

但是你会发现此时报错

-bash: echo: write error: No space left on device

解决的方法是:在设置cpuset.cpus=32之后,必须设置cpuset.mems=XXX才能添加tasks中的pid

#cgset -r cpuset.mems=0 my_app

#cat /sys/fs/cgroup/cpuset/my_app/cpuset.mems
0

然后执行将pid值13058添加到/sys/fs/cgroup/cpuset/my_app/tasks就不会报错

#echo 13058 >  /sys/fs/cgroup/cpuset/my_app/tasks

此时检查13058的 cgroup 控制组就可以看到正确的my_app这个cgroup控制组设置:

#cat /proc/13058/cgroup
...
4:cpuacct,cpu,cpuset:/my_app
...

参考

Last updated