0001
0002 #define _GNU_SOURCE
0003 #include <sys/types.h>
0004 #include <sys/stat.h>
0005 #include <errno.h>
0006 #include <fcntl.h>
0007 #include <sched.h>
0008 #include <time.h>
0009 #include <stdio.h>
0010 #include <unistd.h>
0011 #include <sys/syscall.h>
0012 #include <dlfcn.h>
0013
0014 #include "log.h"
0015 #include "timens.h"
0016
0017 typedef int (*vgettime_t)(clockid_t, struct timespec *);
0018
0019 vgettime_t vdso_clock_gettime;
0020
0021 static void fill_function_pointers(void)
0022 {
0023 void *vdso = dlopen("linux-vdso.so.1",
0024 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
0025 if (!vdso)
0026 vdso = dlopen("linux-gate.so.1",
0027 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
0028 if (!vdso)
0029 vdso = dlopen("linux-vdso32.so.1",
0030 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
0031 if (!vdso)
0032 vdso = dlopen("linux-vdso64.so.1",
0033 RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
0034 if (!vdso) {
0035 pr_err("[WARN]\tfailed to find vDSO\n");
0036 return;
0037 }
0038
0039 vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime");
0040 if (!vdso_clock_gettime)
0041 vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__kernel_clock_gettime");
0042 if (!vdso_clock_gettime)
0043 pr_err("Warning: failed to find clock_gettime in vDSO\n");
0044
0045 }
0046
0047 static void test(clock_t clockid, char *clockstr, bool in_ns)
0048 {
0049 struct timespec tp, start;
0050 long i = 0;
0051 const int timeout = 3;
0052
0053 vdso_clock_gettime(clockid, &start);
0054 tp = start;
0055 for (tp = start; start.tv_sec + timeout > tp.tv_sec ||
0056 (start.tv_sec + timeout == tp.tv_sec &&
0057 start.tv_nsec > tp.tv_nsec); i++) {
0058 vdso_clock_gettime(clockid, &tp);
0059 }
0060
0061 ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n",
0062 in_ns ? "ns" : "host", clockstr, i);
0063 }
0064
0065 int main(int argc, char *argv[])
0066 {
0067 time_t offset = 10;
0068 int nsfd;
0069
0070 ksft_set_plan(8);
0071
0072 fill_function_pointers();
0073
0074 test(CLOCK_MONOTONIC, "monotonic", false);
0075 test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false);
0076 test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false);
0077 test(CLOCK_BOOTTIME, "boottime", false);
0078
0079 nscheck();
0080
0081 if (unshare_timens())
0082 return 1;
0083
0084 nsfd = open("/proc/self/ns/time_for_children", O_RDONLY);
0085 if (nsfd < 0)
0086 return pr_perror("Can't open a time namespace");
0087
0088 if (_settime(CLOCK_MONOTONIC, offset))
0089 return 1;
0090 if (_settime(CLOCK_BOOTTIME, offset))
0091 return 1;
0092
0093 if (setns(nsfd, CLONE_NEWTIME))
0094 return pr_perror("setns");
0095
0096 test(CLOCK_MONOTONIC, "monotonic", true);
0097 test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true);
0098 test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true);
0099 test(CLOCK_BOOTTIME, "boottime", true);
0100
0101 ksft_exit_pass();
0102 return 0;
0103 }