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 vdso = dlopen("linux-vdso32.so.1", 30 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 31 if (!vdso) 32 vdso = dlopen("linux-vdso64.so.1", 33 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 34 if (!vdso) { 35 pr_err("[WARN]\tfailed to find vDSO\n"); 36 return; 37 } 38 39 vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); 40 if (!vdso_clock_gettime) 41 vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__kernel_clock_gettime"); 42 if (!vdso_clock_gettime) 43 pr_err("Warning: failed to find clock_gettime in vDSO\n"); 44 45 } 46 47 static void test(clock_t clockid, char *clockstr, bool in_ns) 48 { 49 struct timespec tp, start; 50 long i = 0; 51 const int timeout = 3; 52 53 vdso_clock_gettime(clockid, &start); 54 tp = start; 55 for (tp = start; start.tv_sec + timeout > tp.tv_sec || 56 (start.tv_sec + timeout == tp.tv_sec && 57 start.tv_nsec > tp.tv_nsec); i++) { 58 vdso_clock_gettime(clockid, &tp); 59 } 60 61 ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n", 62 in_ns ? "ns" : "host", clockstr, i); 63 } 64 65 int main(int argc, char *argv[]) 66 { 67 time_t offset = 10; 68 int nsfd; 69 70 ksft_set_plan(8); 71 72 fill_function_pointers(); 73 74 test(CLOCK_MONOTONIC, "monotonic", false); 75 test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false); 76 test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false); 77 test(CLOCK_BOOTTIME, "boottime", false); 78 79 nscheck(); 80 81 if (unshare_timens()) 82 return 1; 83 84 nsfd = open("/proc/self/ns/time_for_children", O_RDONLY); 85 if (nsfd < 0) 86 return pr_perror("Can't open a time namespace"); 87 88 if (_settime(CLOCK_MONOTONIC, offset)) 89 return 1; 90 if (_settime(CLOCK_BOOTTIME, offset)) 91 return 1; 92 93 if (setns(nsfd, CLONE_NEWTIME)) 94 return pr_perror("setns"); 95 96 test(CLOCK_MONOTONIC, "monotonic", true); 97 test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true); 98 test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true); 99 test(CLOCK_BOOTTIME, "boottime", true); 100 101 ksft_exit_pass(); 102 return 0; 103 } 104