我在 Shell 中测试文件是否为空。
test -s /sys/fs/cgroup/systemd/docker/d4e311735706485e748513bad611070e223cba76fdf4c72a1102d14b653da750/tasks
它返回false,我在使用时发现它的大小为0 ls -lh
,但是当我使用时cat
,我可以在这个文件中得到4071,这意味着文件不是空的。我想也许这个文件太小了,我在我的主目录中创建了一个文件,然后向它回显 4071,我发现它的大小不是 0。 /sys/fs/cgroup 中的文件是特殊的吗?
1 回答
您正在处理的文件是一个特殊文件,它是 cgroup 文件系统的一部分。
要了解为什么会发生这种情况,让我们看看当你这样做时会发生什么test -e $filename
。
我们将使用strace
打印系统调用命令的命令。
如果你这样做strace test -e $filename
,你会在结果中找到这一行:
stat("$filename", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
在这种情况下,它返回st_size = 0
文件的大小。
但问题是在内核内部的另一边实际发生了什么:
当您尝试处理文件时,您会执行系统调用,该系统调用会转到内核中称为虚拟文件系统的中间层,虚拟文件系统又会调用负责所需信息的部分。stat 系统调用将尝试从与文件对应的 inode 中获取状态。文件系统可以根据需要创建和操作 inode。
Cgroup 是一个特殊的文件系统,当它添加一个文件(使用kernel/cgroup.ccgroup_add_file
中定义的函数)时,它总是将大小 0 传递给,因此 /sys/fs/cgroups 中的任何文件(由 cgroup fs 创建)都会无论文件的实际内容如何,它的大小始终为零。__kernfs_create_file
对于另一部分,当 cat 文件时。如果你这样做strace cat $filename
,这就是你将得到的:
open("$filename", O_RDONLY) = 3
read(3, "...", 131072) = ###
读取系统调用将通过虚拟文件系统到达内核文件系统,并使用与文件关联的文件操作,它将为您获取所需的数据。
Cgroup fs 具有在其文件中生成数据的功能。这是在kernel/cgroup.ctasks
中定义文件的方式
{
.name = "tasks",
.seq_start = cgroup_pidlist_start,
.seq_next = cgroup_pidlist_next,
.seq_stop = cgroup_pidlist_stop,
.seq_show = cgroup_pidlist_show,
.private = CGROUP_FILE_TASKS,
.write = cgroup_tasks_write,
},
所以 seq_start、seq_next、seq_stop 和 seq_show 是负责生成文件所需信息的函数。您可以轻松地转到kernel/cgroups.c并检查它们的作用。
请注意,如果您想知道 cgroup 是否还有任务,更简单的方法是在发布时使用通知。
如果在 cgroup 中启用了 notify_on_release 标志 (1),那么每当 cgroup 中的最后一个任务离开(退出或附加到某个其他 cgroup)并且该 cgroup 的最后一个子 cgroup 被删除时,内核运行由指定的命令该层次结构的根目录中“release_agent”文件的内容,提供废弃 cgroup 的路径名(相对于 cgroup 文件系统的挂载点)。这可以自动删除废弃的 cgroup。系统启动时 root cgroup 中 notify_on_release 的默认值是禁用 (0)。其他 cgroup 在创建时的默认值是它们父母的 notify_on_release 设置的当前值。cgroup 层次结构的 release_agent 路径的默认值为空。