1 // SPDX-License-Identifier: GPL-2.0
9 #include <sys/syscall.h>
10 #include <sys/types.h>
19 * Test shouldn't be run for a day, so add 10 days to child
20 * time and check parent's time to be in the same day.
22 #define DAY_IN_SEC (60*60*24)
23 #define TEN_DAYS_IN_SEC (10*DAY_IN_SEC)
25 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
31 * off_id is -1 if a clock has own offset, or it contains an index
32 * which contains a right offset of this clock.
38 #define ct(clock, off_id) { clock, #clock, off_id }
39 static struct test_clock clocks
[] = {
40 ct(CLOCK_BOOTTIME
, -1),
41 ct(CLOCK_BOOTTIME_ALARM
, 1),
42 ct(CLOCK_MONOTONIC
, -1),
43 ct(CLOCK_MONOTONIC_COARSE
, 1),
44 ct(CLOCK_MONOTONIC_RAW
, 1),
48 static int child_ns
, parent_ns
= -1;
50 static int switch_ns(int fd
)
52 if (setns(fd
, CLONE_NEWTIME
)) {
60 static int init_namespaces(void)
62 char path
[] = "/proc/self/ns/time_for_children";
65 if (parent_ns
== -1) {
66 parent_ns
= open(path
, O_RDONLY
);
68 return pr_perror("Unable to open %s", path
);
71 if (fstat(parent_ns
, &st1
))
72 return pr_perror("Unable to stat the parent timens");
77 child_ns
= open(path
, O_RDONLY
);
79 return pr_perror("Unable to open %s", path
);
81 if (fstat(child_ns
, &st2
))
82 return pr_perror("Unable to stat the timens");
84 if (st1
.st_ino
== st2
.st_ino
)
85 return pr_perror("The same child_ns after CLONE_NEWTIME");
90 static int test_gettime(clockid_t clock_index
, bool raw_syscall
, time_t offset
)
92 struct timespec child_ts_new
, parent_ts_old
, cur_ts
;
93 char *entry
= raw_syscall
? "syscall" : "vdso";
94 double precision
= 0.0;
96 if (check_skip(clocks
[clock_index
].id
))
99 switch (clocks
[clock_index
].id
) {
100 case CLOCK_MONOTONIC_COARSE
:
101 case CLOCK_MONOTONIC_RAW
:
106 if (switch_ns(parent_ns
))
107 return pr_err("switch_ns(%d)", child_ns
);
109 if (_gettime(clocks
[clock_index
].id
, &parent_ts_old
, raw_syscall
))
112 child_ts_new
.tv_nsec
= parent_ts_old
.tv_nsec
;
113 child_ts_new
.tv_sec
= parent_ts_old
.tv_sec
+ offset
;
115 if (switch_ns(child_ns
))
116 return pr_err("switch_ns(%d)", child_ns
);
118 if (_gettime(clocks
[clock_index
].id
, &cur_ts
, raw_syscall
))
121 if (difftime(cur_ts
.tv_sec
, child_ts_new
.tv_sec
) < precision
) {
122 ksft_test_result_fail(
123 "Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n",
124 clocks
[clock_index
].name
, entry
, parent_ts_old
.tv_sec
,
125 child_ts_new
.tv_sec
, cur_ts
.tv_sec
);
129 if (switch_ns(parent_ns
))
130 return pr_err("switch_ns(%d)", parent_ns
);
132 if (_gettime(clocks
[clock_index
].id
, &cur_ts
, raw_syscall
))
135 if (difftime(cur_ts
.tv_sec
, parent_ts_old
.tv_sec
) > DAY_IN_SEC
) {
136 ksft_test_result_fail(
137 "Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n",
138 clocks
[clock_index
].name
, entry
, parent_ts_old
.tv_sec
,
139 child_ts_new
.tv_sec
, cur_ts
.tv_sec
);
140 /* Let's play nice and put it closer to original */
141 clock_settime(clocks
[clock_index
].id
, &cur_ts
);
145 ksft_test_result_pass("Passed for %s (%s)\n",
146 clocks
[clock_index
].name
, entry
);
150 int main(int argc
, char *argv
[])
158 check_supported_timers();
160 ksft_set_plan(ARRAY_SIZE(clocks
) * 2);
162 if (init_namespaces())
165 /* Offsets have to be set before tasks enter the namespace. */
166 for (i
= 0; i
< ARRAY_SIZE(clocks
); i
++) {
167 if (clocks
[i
].off_id
!= -1)
169 offset
= TEN_DAYS_IN_SEC
+ i
* 1000;
170 clocks
[i
].offset
= offset
;
171 if (_settime(clocks
[i
].id
, offset
))
175 for (i
= 0; i
< ARRAY_SIZE(clocks
); i
++) {
176 if (clocks
[i
].off_id
!= -1)
177 offset
= clocks
[clocks
[i
].off_id
].offset
;
179 offset
= clocks
[i
].offset
;
180 ret
|= test_gettime(i
, true, offset
);
181 ret
|= test_gettime(i
, false, offset
);