时间命名空间应该如何使用?

时间命名空间应该如何使用?

我想我可以做这样的事情:

sudo unshare -T bash -c 'date -s "$1" && foobar' sh "$(date -d -1day)"

因此foobar会看到与系统其他部分不同的系统时间。但是,似乎不包含系统时间的变化。它改变了整个系统的系统时间。

这篇 LWN 文章似乎表明这个名称空间是为了我试图给它的用途而设计的。

当在根时间命名空间之外调用时,调整系统时间的系统调用将调整特定于命名空间的偏移量。

看着strace date -s ...,我看到了其他输出:

clock_settime(CLOCK_REALTIME, {tv_sec=1619044910, tv_nsec=0}) = 0

然而,阅读time_namespaces(7)

这会影响针对这些时钟进行测量的各种 API,包括:clock_gettime(2)、clock_nanosleep(2)、nanosleep(2)、timer_settime(2)、timerfd_settime(2) 和 /proc/uptime。

我看没有提到clock_settime(2)。 “包括”一词告诉我这可能不是完整的列表,但也许是。

我也不懂--boottime/ --monotonic。看着clock_settime(2),我看到:

CLOCK_MONOTONIC 不可设置的系统范围时钟,表示单调时间(如 POSIX 所描述的)“过去的某个未指定的点”。在 Linux 上,该点对应于系统自启动以来运行的秒数。

CLOCK_BOOTTIME(自 Linux 2.6.39 起;特定于 Linux)不可设置的系统范围时钟,与 CLOCK_MONOTONIC 相同,但它还包括系统挂起的任何时间。

然而,当尝试它们时,它们似乎并没有改变uptime

$ uptime -s
2021-04-10 10:30:45
$ sudo unshare -T --boottime 1000000000 uptime -s
2021-04-10 10:30:45
$ sudo unshare -T --monotonic 1000000000 uptime -s
2021-04-10 10:30:45
$ sudo unshare -T --boottime -100000 uptime -s
2021-04-10 10:30:45
$ sudo unshare -T --monotonic -100000 uptime -s
2021-04-10 10:30:45

我从中看到strace uptime它读取/proc/uptime而不是调用clock_gettime(2),并且/proc/uptime似乎不受unshare调用及其偏移量的影响,尽管文档说它time_namespaces(7)会影响/proc/uptime我上面引用的内容。

这个命名空间应该如何使用?我似乎找不到任何会受到影响的命令unshare --time

答案1

我认为您的推理中有三个要点需要澄清:


第一个取消共享时间命名空间会影响孩子们产生的从那时起通过称为unshare(2).调用过程本身不受影响。这有点像 PID 命名空间,但与迄今为止的其他命名空间类型不同。然而调用过程可能仍然进入新创建的时间命名空间,只是如果它想这样做,那么它也必须setns(2)(即nsenter(1)用 CLI 的说法)自己进入其中。

所有这些意味着unshare -T您一直在运行的命令从未真正将这些命令移动到新创建的时间命名空间中。您只需添加-f选项即可unshare(1)使其将指定的命令作为其子命令而不是execve(2)其自身运行。这样指定的命令将存在于该时间命名空间中。

当然,正如您所做的正确一样,您还需要指定--boottime和/或--monotonic选项来“扭曲”时间命名空间对这些时钟的视觉,否则子时间命名空间将与其父时间命名空间具有相同的视觉。

因此,总而言之,以您的尝试为例,在我的机器上:

$ sudo unshare -T --boottime 1000000000 uptime -s
2021-04-23 11:07:10
$ sudo unshare -fT --boottime 1000000000 uptime -s
1989-08-15 09:20:30
$

除了使用这些方便的选项之外,您还可以/proc/self/timens_offsets手动设置文件,只要在生成任何子项之前执行此操作即可。与上面的“手动”等效的内容类似于:

$ sudo unshare -T dash -c 'echo "boottime 1000000000 0" > /proc/self/timens_offsets; uptime -s'
1989-08-15 09:20:30

在这里,我dash只是使用一个更精简的外壳,它肯定不会为其自己的引导程序生成子级,并且还具有内置echo(以免为其生成子文件)去设置自己的timens_offsets文件。从那时起,运行的所有后续命令都dash将看到“扭曲的”启动时间。

但不是如果您愿意这样做exec uptime -s,因为这会替换dash 为uptime因此仍然存在于父时间命名空间中,除非你也nsenter(1)事先。考虑:

$ sudo unshare -T dash -c 'echo "boottime 1000000000 0" > /proc/self/timens_offsets; exec uptime -s'
2021-04-23 11:07:10
$ sudo unshare -T dash -c 'echo "boottime 1000000000 0" > /proc/self/timens_offsets; exec nsenter --time=/proc/self/ns/time_for_children uptime -s'
1989-08-15 09:20:30
$

第二点我发现需要澄清的是date专门针对该命令的。

注意从内核 v5.11 开始(以及当前最新的 v5.12-rc8),CLOCK_BOOTIME并且CLOCK_MONOTONIC可以在新的时间命名空间中“扭曲”,正如在注释time_namespaces(7):

请注意,时间命名空间不会虚拟化 CLOCK_REALTIME 时钟。由于内核内的复杂性和开销的原因,避免了该时钟的虚拟化。

但是,正如您从命令中可以注意到的那样,date它专门作用于时钟。这意味着,在我写这篇文章时,该命令仍然不受它所在的时间命名空间的影响。CLOCK_REALTIMEstrace date -s ...date

命令的快速示例确实受到时间命名空间的影响,因为它引用的是CLOCK_MONOTONICis dmesg。尝试类似的方法:

$ sudo unshare -fT --monotonic 1000000000 dmesg -T

第三重点似乎是关于这句话:

当在根时间命名空间之外调用时,调整系统时间的系统调用将调整特定于命名空间的偏移量。

诚然,这有点误导,因为(目前)它显然是不是可能会任意地改变时间命名空间的时间视野然后,仅仅因为CLOCK_MONOTONICCLOCK_BOOTTIME实际上都是不可改变的。这两个时钟是意思是成为不可改变的。

因此,唯一允许的操作是将它们“引导”到某个偏移量(与初始时间命名空间相关)任何进程都已加入该时间命名空间,因此任何进程都不会经历这两个时钟的跳跃(甚至不会向前)。

这就是为什么unshare(2)不将调用进程移动到新创建的时间命名空间中的原因:这样它(或其他进程)就有机会指定“引导”偏移量,实际上在任何一个进程进入时间命名空间后都无法更改该偏移量。时间命名空间。计算正确的偏移量显然是一个微妙的操作,这是“命名空间管理器”的工作。

相关内容