~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/timens/timens.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 struct test_clock {
 26         clockid_t id;
 27         char *name;
 28         /*
 29          * off_id is -1 if a clock has own offset, or it contains an index
 30          * which contains a right offset of this clock.
 31          */
 32         int off_id;
 33         time_t offset;
 34 };
 35 
 36 #define ct(clock, off_id)       { clock, #clock, off_id }
 37 static struct test_clock clocks[] = {
 38         ct(CLOCK_BOOTTIME, -1),
 39         ct(CLOCK_BOOTTIME_ALARM, 1),
 40         ct(CLOCK_MONOTONIC, -1),
 41         ct(CLOCK_MONOTONIC_COARSE, 1),
 42         ct(CLOCK_MONOTONIC_RAW, 1),
 43 };
 44 #undef ct
 45 
 46 static int child_ns, parent_ns = -1;
 47 
 48 static int switch_ns(int fd)
 49 {
 50         if (setns(fd, CLONE_NEWTIME)) {
 51                 pr_perror("setns()");
 52                 return -1;
 53         }
 54 
 55         return 0;
 56 }
 57 
 58 static int init_namespaces(void)
 59 {
 60         char path[] = "/proc/self/ns/time_for_children";
 61         struct stat st1, st2;
 62 
 63         if (parent_ns == -1) {
 64                 parent_ns = open(path, O_RDONLY);
 65                 if (parent_ns <= 0)
 66                         return pr_perror("Unable to open %s", path);
 67         }
 68 
 69         if (fstat(parent_ns, &st1))
 70                 return pr_perror("Unable to stat the parent timens");
 71 
 72         if (unshare_timens())
 73                 return  -1;
 74 
 75         child_ns = open(path, O_RDONLY);
 76         if (child_ns <= 0)
 77                 return pr_perror("Unable to open %s", path);
 78 
 79         if (fstat(child_ns, &st2))
 80                 return pr_perror("Unable to stat the timens");
 81 
 82         if (st1.st_ino == st2.st_ino)
 83                 return pr_perror("The same child_ns after CLONE_NEWTIME");
 84 
 85         return 0;
 86 }
 87 
 88 static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset)
 89 {
 90         struct timespec child_ts_new, parent_ts_old, cur_ts;
 91         char *entry = raw_syscall ? "syscall" : "vdso";
 92         double precision = 0.0;
 93 
 94         if (check_skip(clocks[clock_index].id))
 95                 return 0;
 96 
 97         switch (clocks[clock_index].id) {
 98         case CLOCK_MONOTONIC_COARSE:
 99         case CLOCK_MONOTONIC_RAW:
100                 precision = -2.0;
101                 break;
102         }
103 
104         if (switch_ns(parent_ns))
105                 return pr_err("switch_ns(%d)", child_ns);
106 
107         if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall))
108                 return -1;
109 
110         child_ts_new.tv_nsec = parent_ts_old.tv_nsec;
111         child_ts_new.tv_sec = parent_ts_old.tv_sec + offset;
112 
113         if (switch_ns(child_ns))
114                 return pr_err("switch_ns(%d)", child_ns);
115 
116         if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
117                 return -1;
118 
119         if (difftime(cur_ts.tv_sec, child_ts_new.tv_sec) < precision) {
120                 ksft_test_result_fail(
121                         "Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n",
122                         clocks[clock_index].name, entry, parent_ts_old.tv_sec,
123                         child_ts_new.tv_sec, cur_ts.tv_sec);
124                 return -1;
125         }
126 
127         if (switch_ns(parent_ns))
128                 return pr_err("switch_ns(%d)", parent_ns);
129 
130         if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
131                 return -1;
132 
133         if (difftime(cur_ts.tv_sec, parent_ts_old.tv_sec) > DAY_IN_SEC) {
134                 ksft_test_result_fail(
135                         "Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n",
136                         clocks[clock_index].name, entry, parent_ts_old.tv_sec,
137                         child_ts_new.tv_sec, cur_ts.tv_sec);
138                 /* Let's play nice and put it closer to original */
139                 clock_settime(clocks[clock_index].id, &cur_ts);
140                 return -1;
141         }
142 
143         ksft_test_result_pass("Passed for %s (%s)\n",
144                                 clocks[clock_index].name, entry);
145         return 0;
146 }
147 
148 int main(int argc, char *argv[])
149 {
150         unsigned int i;
151         time_t offset;
152         int ret = 0;
153 
154         nscheck();
155 
156         check_supported_timers();
157 
158         ksft_set_plan(ARRAY_SIZE(clocks) * 2);
159 
160         if (init_namespaces())
161                 return 1;
162 
163         /* Offsets have to be set before tasks enter the namespace. */
164         for (i = 0; i < ARRAY_SIZE(clocks); i++) {
165                 if (clocks[i].off_id != -1)
166                         continue;
167                 offset = TEN_DAYS_IN_SEC + i * 1000;
168                 clocks[i].offset = offset;
169                 if (_settime(clocks[i].id, offset))
170                         return 1;
171         }
172 
173         for (i = 0; i < ARRAY_SIZE(clocks); i++) {
174                 if (clocks[i].off_id != -1)
175                         offset = clocks[clocks[i].off_id].offset;
176                 else
177                         offset = clocks[i].offset;
178                 ret |= test_gettime(i, true, offset);
179                 ret |= test_gettime(i, false, offset);
180         }
181 
182         if (ret)
183                 ksft_exit_fail();
184 
185         ksft_exit_pass();
186         return !!ret;
187 }
188 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php