162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#define _GNU_SOURCE 362306a36Sopenharmony_ci#include <sys/types.h> 462306a36Sopenharmony_ci#include <sys/stat.h> 562306a36Sopenharmony_ci#include <errno.h> 662306a36Sopenharmony_ci#include <fcntl.h> 762306a36Sopenharmony_ci#include <sched.h> 862306a36Sopenharmony_ci#include <time.h> 962306a36Sopenharmony_ci#include <stdio.h> 1062306a36Sopenharmony_ci#include <unistd.h> 1162306a36Sopenharmony_ci#include <sys/syscall.h> 1262306a36Sopenharmony_ci#include <dlfcn.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "log.h" 1562306a36Sopenharmony_ci#include "timens.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_citypedef int (*vgettime_t)(clockid_t, struct timespec *); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_civgettime_t vdso_clock_gettime; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void fill_function_pointers(void) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci void *vdso = dlopen("linux-vdso.so.1", 2462306a36Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 2562306a36Sopenharmony_ci if (!vdso) 2662306a36Sopenharmony_ci vdso = dlopen("linux-gate.so.1", 2762306a36Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 2862306a36Sopenharmony_ci if (!vdso) 2962306a36Sopenharmony_ci vdso = dlopen("linux-vdso32.so.1", 3062306a36Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 3162306a36Sopenharmony_ci if (!vdso) 3262306a36Sopenharmony_ci vdso = dlopen("linux-vdso64.so.1", 3362306a36Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 3462306a36Sopenharmony_ci if (!vdso) { 3562306a36Sopenharmony_ci pr_err("[WARN]\tfailed to find vDSO\n"); 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); 4062306a36Sopenharmony_ci if (!vdso_clock_gettime) 4162306a36Sopenharmony_ci vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__kernel_clock_gettime"); 4262306a36Sopenharmony_ci if (!vdso_clock_gettime) 4362306a36Sopenharmony_ci pr_err("Warning: failed to find clock_gettime in vDSO\n"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic void test(clock_t clockid, char *clockstr, bool in_ns) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct timespec tp, start; 5062306a36Sopenharmony_ci long i = 0; 5162306a36Sopenharmony_ci const int timeout = 3; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci vdso_clock_gettime(clockid, &start); 5462306a36Sopenharmony_ci tp = start; 5562306a36Sopenharmony_ci for (tp = start; start.tv_sec + timeout > tp.tv_sec || 5662306a36Sopenharmony_ci (start.tv_sec + timeout == tp.tv_sec && 5762306a36Sopenharmony_ci start.tv_nsec > tp.tv_nsec); i++) { 5862306a36Sopenharmony_ci vdso_clock_gettime(clockid, &tp); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n", 6262306a36Sopenharmony_ci in_ns ? "ns" : "host", clockstr, i); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciint main(int argc, char *argv[]) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci time_t offset = 10; 6862306a36Sopenharmony_ci int nsfd; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci ksft_set_plan(8); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci fill_function_pointers(); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci test(CLOCK_MONOTONIC, "monotonic", false); 7562306a36Sopenharmony_ci test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false); 7662306a36Sopenharmony_ci test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false); 7762306a36Sopenharmony_ci test(CLOCK_BOOTTIME, "boottime", false); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci nscheck(); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (unshare_timens()) 8262306a36Sopenharmony_ci return 1; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci nsfd = open("/proc/self/ns/time_for_children", O_RDONLY); 8562306a36Sopenharmony_ci if (nsfd < 0) 8662306a36Sopenharmony_ci return pr_perror("Can't open a time namespace"); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (_settime(CLOCK_MONOTONIC, offset)) 8962306a36Sopenharmony_ci return 1; 9062306a36Sopenharmony_ci if (_settime(CLOCK_BOOTTIME, offset)) 9162306a36Sopenharmony_ci return 1; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (setns(nsfd, CLONE_NEWTIME)) 9462306a36Sopenharmony_ci return pr_perror("setns"); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci test(CLOCK_MONOTONIC, "monotonic", true); 9762306a36Sopenharmony_ci test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true); 9862306a36Sopenharmony_ci test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true); 9962306a36Sopenharmony_ci test(CLOCK_BOOTTIME, "boottime", true); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ksft_exit_pass(); 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 104