TIME_NAMESPACES - Linux手册页
Linux程序员手册 第7部分
更新日期: 2020-06-09
名称
time_namespaces-Linux时间名称空间概述
说明
时间名称空间可虚拟化两个系统时钟的值:
- *
- CLOCK_MONOTONIC(以及类似的CLOCK_MONOTONIC_COARSE和CLOCK_MONOTONIC_RAW)是一种不可设置的时钟,代表自POSIX所描述的"过去的某个未指定点"以来的单调时间。
- *
- CLOCK_BOOTTIME(以及类似的CLOCK_BOOTTIME_ALARM),与CLOCK_MONOTONIC相同的不可设置的时钟,除了它还包括系统挂起的任何时间。
因此,在这些时钟的时间命名空间共享每个名字空间的值的处理。这会影响针对这些时钟的各种API,包括:clock_gettime(2),clock_nanosleep(2),nanosleep(2),timer_settime(2),timerfd_settime(2)和/ proc / uptime。
当前,创建时间名称空间的唯一方法是通过使用CLONE_NEWTIME标志调用unshare(2)。该调用将创建一个新的时间名称空间,但不会将调用过程放在新的名称空间中。而是,调用进程的随后创建的子级将放置在新的名称空间中。这允许时钟偏移(见下文),用于新的命名空间的第一进程被放置在命名空间之前进行设置。 / proc / [pid] / ns / time_for_children符号链接显示将在其中创建进程的子级的时间名称空间。 (进程可以在调用setns(2)的过程中使用在此符号链接上打开的文件描述符,以便移入名称空间。)
/proc/PID/timens_offsets
与每个时间名称空间相关联的是相对于初始时间名称空间表示的偏移量,这些偏移量定义了该名称空间中单调时钟和启动时间时钟的值。这些偏移量通过文件/ proc / PID / timens_offsets公开。在这个文件中,偏移被表示为包括三个空格分隔场行:
<clock-id> <offset-secs> <offset-nanosecs>
clock-id是一个字符串,用于标识要显示其偏移量的时钟。对于CLOCK_MONOTONIC,此字段是单调的;对于CLOCK_BOOTTIME,此字段是启动的。其余字段表示此时间名称空间中时钟的偏移量(秒加纳秒)。这些偏移是相对于初始时间名称空间中的时钟值表示的。 offset-secs值可以为负,但要遵守以下说明的限制; offset-nanosecs是一个无符号值。
在初始时间名称空间中,timens_offsets文件的内容如下:
$ cat /proc/self/timens_offsets monotonic 0 0 boottime 0 0
在没有成员进程的新时间名称空间中,可以通过将相同格式的换行符终止的记录写入timens_offsets文件来修改时钟偏移量。该文件可以被写入多次,但第一个进程中创建或已进入后的命名空间,写(2)S于本文件失败,错误EACCES。为了写入timens_offsets文件,进程必须在拥有时间名称空间的用户名称空间中具有CAP_SYS_TIME功能。
写入timens_offsets文件可能失败,并出现以下错误:
- EINVAL
- offset-nanosecs值大于999,999,999。
- EINVAL
- 时钟编号值无效。
- EPERM
- 调用者不具有CAP_SYS_TIME功能。
- ERANGE
- An
offset-secs
value is out of range.
In particular;- *
- 不能将offset-secs设置为会使名称空间内相应时钟上的当前时间为负值的值;和
- *
- 不能将offset-secs设置为一个值,以使名称空间内相应时钟上的时间超过内核常数KTIME_SEC_MAX的值的一半(这将时钟值限制为大约146年的最大值)。
在unshare(2)创建的新时间名称空间中,timens_offsets文件的内容继承自创建过程的时间名称空间。
备注
使用时间名称空间需要使用CONFIG_TIME_NS选项配置的内核。
请注意,时间名称空间不会虚拟化CLOCK_REALTIME时钟。由于内核内部的复杂性和开销,避免了对该时钟的虚拟化。
为了与最初的实现兼容,将时钟ID写入/ proc / [pid] / timens_offsets文件时,可以写入ID的数值,而不是上面显示的符号名称。即用1代替单调,用7代替启动时间。为了提高可用性,最好在数字上使用符号名称。
添加时间命名空间的动机是让单调和启动时的时钟保持容器迁移和检查点期间一致的值/恢复。
示例
下面的shell会话演示时间命名空间的操作。我们首先在初始时间名称空间中显示外壳的时间名称空间的索引节点号:
$ readlink /proc/$$/ns/time time:[4026531834]
继续使用初始时间名称空间,我们使用uptime(1)显示系统正常运行时间,并使用clock_getres(2)中显示的clock_times示例程序显示各种时钟的值:
$ uptime --pretty up 21 hours, 17 minutes $ ./clock_times CLOCK_REALTIME : 1585989401.971 (18356 days + 8h 36m 41s) CLOCK_TAI : 1585989438.972 (18356 days + 8h 37m 18s) CLOCK_MONOTONIC: 56338.247 (15h 38m 58s) CLOCK_BOOTTIME : 76633.544 (21h 17m 13s)
然后,我们使用unshare(1)创建一个时间名称空间并执行bash(1)shell。在新的外壳程序中,我们使用内置的echo命令将记录写入timens_offsets文件,从而调整CLOCK_MONOTONIC时钟向前2天的偏移和CLOCK_BOOTTIME时钟向前7天的偏移:
$ PS1="ns2# " sudo unshare -T -- bash --norc ns2# echo "monotonic $((2*24*60*60)) 0" > /proc/$$/timens_offsets ns2# echo "boottime $((7*24*60*60)) 0" > /proc/$$/timens_offsets
上面,我们开始在bash(1)外壳,因此没有启动脚本中执行的--norc选项。这将确保没有子进程从壳创造我们有机会更新timens_offsets文件之前。
然后,我们使用cat(1)显示timens_offsets文件的内容。 cat(1)的执行会在新的时间名称空间中创建第一个进程,之后进一步尝试更新timens_offsets文件会产生错误。
ns2# cat /proc/$$/timens_offsets monotonic 172800 0 boottime 604800 0 ns2# echo "boottime $((9*24*60*60)) 0" > /proc/$$/timens_offsets bash: echo: write error: Permission denied
在新的名称空间中,我们执行uptime(1)和clock_times示例程序:
ns2# uptime --pretty up 1 week, 21 hours, 18 minutes ns2# ./clock_times CLOCK_REALTIME : 1585989457.056 (18356 days + 8h 37m 37s) CLOCK_TAI : 1585989494.057 (18356 days + 8h 38m 14s) CLOCK_MONOTONIC: 229193.332 (2 days + 15h 39m 53s) CLOCK_BOOTTIME : 681488.629 (7 days + 21h 18m 8s)
从上面的输出中,我们可以看到单调时钟和引导时间时钟在新的时间名称空间中具有不同的值。
检查在/ proc / [PID] / NS /时间的/ proc / [PID] / NS / time_for_children符号链接,我们看到,外壳是初始时间命名空间中的一员,但它的孩子们在新的命名空间创建。
ns2# readlink /proc/$$/ns/time time:[4026531834] ns2# readlink /proc/$$/ns/time_for_children time:[4026532900] ns2# readlink /proc/self/ns/time # Creates a child process time:[4026532900]
返回到初始时间命名空间的外壳,我们可以看到,单调和启动时的时钟是由其他时间命名空间所做的timens_offsets变动的影响:
$ uptime --pretty up 21 hours, 19 minutes $ ./clock_times CLOCK_REALTIME : 1585989401.971 (18356 days + 8h 38m 51s) CLOCK_TAI : 1585989438.972 (18356 days + 8h 39m 28s) CLOCK_MONOTONIC: 56338.247 (15h 41m 8s) CLOCK_BOOTTIME : 76633.544 (21h 19m 23s)
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。