我正在运行带有 kernel 的 CentOS 7 3.10.0-693.5.2.el7.x86_64
。
我使用 cgroup 对进程应用内存限制。在应用程序滚动重新启动期间,内存限制加倍以满足内存需求。
然而,有时重新启动后,无法将交换内存限制降低到原始值,并且 cgroup 返回错误write error: Device or resource busy
例如
[root@us app]# echo "643825664" > memory.limit_in_bytes
[root@us app]# echo "673825664" > memory.memsw.limit_in_bytes
-bash: echo: write error: Device or resource busy
[root@us app]# echo "873825664" > memory.memsw.limit_in_bytes
[root@us app]#
写入更大的值(例如+200MB)似乎可以正常工作。
我还没弄清楚为什么会出现这种情况。我在 cgroup 文档中没有找到任何引用此错误的内容。我认为它必须在当前交换使用量高于限制的情况下执行某些操作。
您有遇到此类错误的经验吗?
答案1
说什么cat memory.memsw.usage_in_bytes
?您不能将最大值设置为低于当前限制。
查看 3.10 Linux 源代码,修改memsw.limit_in_bytes
结果调用mem_cgroup_write()
:
{
.name = "memsw.limit_in_bytes",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT),
.write_string = mem_cgroup_write,
.read = mem_cgroup_read,
},
mem_cgroup_write()
定义于:
https://elixir.bootlin.com/linux/v3.10/source/mm/memcontrol.c#L5199
mem_cgroup_write()
mem_cgroup_resize_memsw_limit()
当类型为_MEMSWAP
:时依次调用:
else if (type == _MEMSWAP)
ret = mem_cgroup_resize_memsw_limit(memcg, val);
mem_cgroup_resize_memsw_limit()
定义于:
https://elixir.bootlin.com/linux/v3.10/source/mm/memcontrol.c#L4647
该函数调用res_counter_set_limit()
:
https://elixir.bootlin.com/linux/v3.10/source/include/linux/res_counter.h#L200
该函数的实现是:
unsigned long flags;
int ret = -EBUSY;
spin_lock_irqsave(&cnt->lock, flags);
if (cnt->usage <= limit) {
cnt->limit = limit;
ret = 0;
}
spin_unlock_irqrestore(&cnt->lock, flags);
return ret;
请注意,它ret
被初始化为-EBUSY
(对应于Device or resource busy
您所看到的消息),并且仅当当前使用量小于或等于请求的限制时才更改为零。我的猜测是,在你的情况下不是,所以函数返回-EBUSY
.
如果res_counter_set_limit()
返回非零值mem_cgroup_resize_memsw_limit()
,则mem_cgroup_resize_limit()
依次返回相同的值。 mem_cgroup_resize_limit()
将值返回到mem_cgroup_write()
.该返回值被传播到用户空间,这就是为什么您会看到从echo
.
当前内核源的实现有点不同,但行为是相同的。您不能将最小值调整为小于使用值的值。