1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <sched.h> 8 #include <time.h> 9 #include <stdio.h> 10 #include <unistd.h> 11 #include <sys/syscall.h> 12 #include <dlfcn.h> 13 14 #include "log.h" 15 #include "timens.h" 16 17 typedef int (*vgettime_t)(clockid_t, struct timespec *); 18 19 vgettime_t vdso_clock_gettime; 20 21 static void fill_function_pointers(void) 22 { 23 void *vdso = dlopen("linux-vdso.so.1", 24 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 25 if (!vdso) 26 vdso = dlopen("linux-gate.so.1", 27 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 28 if (!vdso) { 29 pr_err("[WARN]\tfailed to find vDSO\n"); 30 return; 31 } 32 33 vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); 34 if (!vdso_clock_gettime) 35 pr_err("Warning: failed to find clock_gettime in vDSO\n"); 36 37 } 38 39 static void test(clock_t clockid, char *clockstr, bool in_ns) 40 { 41 struct timespec tp, start; 42 long i = 0; 43 const int timeout = 3; 44 45 vdso_clock_gettime(clockid, &start); 46 tp = start; 47 for (tp = start; start.tv_sec + timeout > tp.tv_sec || 48 (start.tv_sec + timeout == tp.tv_sec && 49 start.tv_nsec > tp.tv_nsec); i++) { 50 vdso_clock_gettime(clockid, &tp); 51 } 52 53 ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n", 54 in_ns ? "ns" : "host", clockstr, i); 55 } 56 57 int main(int argc, char *argv[]) 58 { 59 time_t offset = 10; 60 int nsfd; 61 62 ksft_set_plan(8); 63 64 fill_function_pointers(); 65 66 test(CLOCK_MONOTONIC, "monotonic", false); 67 test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false); 68 test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false); 69 test(CLOCK_BOOTTIME, "boottime", false); 70 71 nscheck(); 72 73 if (unshare_timens()) 74 return 1; 75 76 nsfd = open("/proc/self/ns/time_for_children", O_RDONLY); 77 if (nsfd < 0) 78 return pr_perror("Can't open a time namespace"); 79 80 if (_settime(CLOCK_MONOTONIC, offset)) 81 return 1; 82 if (_settime(CLOCK_BOOTTIME, offset)) 83 return 1; 84 85 if (setns(nsfd, CLONE_NEWTIME)) 86 return pr_perror("setns"); 87 88 test(CLOCK_MONOTONIC, "monotonic", true); 89 test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true); 90 test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true); 91 test(CLOCK_BOOTTIME, "boottime", true); 92 93 ksft_exit_pass(); 94 return 0; 95 } 96