1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <sched.h> 6 #include <stdio.h> 7 #include <stdbool.h> 8 #include <sys/stat.h> 9 #include <sys/syscall.h> 10 #include <sys/types.h> 11 #include <time.h> 12 #include <unistd.h> 13 #include <string.h> 14 15 #include "log.h" 16 #include "timens.h" 17 18 /* 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. 21 */ 22 #define DAY_IN_SEC (60*60*24) 23 #define TEN_DAYS_IN_SEC (10*DAY_IN_SEC) 24 25 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 26 27 struct test_clock { 28 clockid_t id; 29 char *name; 30 /* 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. 33 */ 34 int off_id; 35 time_t offset; 36 }; 37 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), 45 }; 46 #undef ct 47 48 static int child_ns, parent_ns = -1; 49 50 static int switch_ns(int fd) 51 { 52 if (setns(fd, CLONE_NEWTIME)) { 53 pr_perror("setns()"); 54 return -1; 55 } 56 57 return 0; 58 } 59 60 static int init_namespaces(void) 61 { 62 char path[] = "/proc/self/ns/time_for_children"; 63 struct stat st1, st2; 64 65 if (parent_ns == -1) { 66 parent_ns = open(path, O_RDONLY); 67 if (parent_ns <= 0) 68 return pr_perror("Unable to open %s", path); 69 } 70 71 if (fstat(parent_ns, &st1)) 72 return pr_perror("Unable to stat the parent timens"); 73 74 if (unshare_timens()) 75 return -1; 76 77 child_ns = open(path, O_RDONLY); 78 if (child_ns <= 0) 79 return pr_perror("Unable to open %s", path); 80 81 if (fstat(child_ns, &st2)) 82 return pr_perror("Unable to stat the timens"); 83 84 if (st1.st_ino == st2.st_ino) 85 return pr_perror("The same child_ns after CLONE_NEWTIME"); 86 87 return 0; 88 } 89 90 static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset) 91 { 92 struct timespec child_ts_new, parent_ts_old, cur_ts; 93 char *entry = raw_syscall ? "syscall" : "vdso"; 94 double precision = 0.0; 95 96 if (check_skip(clocks[clock_index].id)) 97 return 0; 98 99 switch (clocks[clock_index].id) { 100 case CLOCK_MONOTONIC_COARSE: 101 case CLOCK_MONOTONIC_RAW: 102 precision = -2.0; 103 break; 104 } 105 106 if (switch_ns(parent_ns)) 107 return pr_err("switch_ns(%d)", child_ns); 108 109 if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall)) 110 return -1; 111 112 child_ts_new.tv_nsec = parent_ts_old.tv_nsec; 113 child_ts_new.tv_sec = parent_ts_old.tv_sec + offset; 114 115 if (switch_ns(child_ns)) 116 return pr_err("switch_ns(%d)", child_ns); 117 118 if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall)) 119 return -1; 120 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); 126 return -1; 127 } 128 129 if (switch_ns(parent_ns)) 130 return pr_err("switch_ns(%d)", parent_ns); 131 132 if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall)) 133 return -1; 134 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); 142 return -1; 143 } 144 145 ksft_test_result_pass("Passed for %s (%s)\n", 146 clocks[clock_index].name, entry); 147 return 0; 148 } 149 150 int main(int argc, char *argv[]) 151 { 152 unsigned int i; 153 time_t offset; 154 int ret = 0; 155 156 nscheck(); 157 158 check_supported_timers(); 159 160 ksft_set_plan(ARRAY_SIZE(clocks) * 2); 161 162 if (init_namespaces()) 163 return 1; 164 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) 168 continue; 169 offset = TEN_DAYS_IN_SEC + i * 1000; 170 clocks[i].offset = offset; 171 if (_settime(clocks[i].id, offset)) 172 return 1; 173 } 174 175 for (i = 0; i < ARRAY_SIZE(clocks); i++) { 176 if (clocks[i].off_id != -1) 177 offset = clocks[clocks[i].off_id].offset; 178 else 179 offset = clocks[i].offset; 180 ret |= test_gettime(i, true, offset); 181 ret |= test_gettime(i, false, offset); 182 } 183 184 if (ret) 185 ksft_exit_fail(); 186 187 ksft_exit_pass(); 188 return !!ret; 189 } 190