1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci 4f08c3bdfSopenharmony_ci Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz> 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci/* 8f08c3bdfSopenharmony_ci 9f08c3bdfSopenharmony_ci Test that timerfd adds correctly an offset with absolute expiration time. 10f08c3bdfSopenharmony_ci 11f08c3bdfSopenharmony_ci After a call to unshare(CLONE_NEWTIME) a new timer namespace is created, the 12f08c3bdfSopenharmony_ci process that has called the unshare() can adjust offsets for CLOCK_MONOTONIC 13f08c3bdfSopenharmony_ci and CLOCK_BOOTTIME for its children by writing to the '/proc/self/timens_offsets'. 14f08c3bdfSopenharmony_ci 15f08c3bdfSopenharmony_ci */ 16f08c3bdfSopenharmony_ci 17f08c3bdfSopenharmony_ci#include <stdlib.h> 18f08c3bdfSopenharmony_ci#include "time64_variants.h" 19f08c3bdfSopenharmony_ci#include "tst_safe_clocks.h" 20f08c3bdfSopenharmony_ci#include "tst_safe_timerfd.h" 21f08c3bdfSopenharmony_ci#include "tst_timer.h" 22f08c3bdfSopenharmony_ci#include "lapi/sched.h" 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#define SLEEP_US 40000 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_cistatic struct tcase { 27f08c3bdfSopenharmony_ci int clk_id; 28f08c3bdfSopenharmony_ci int clk_off; 29f08c3bdfSopenharmony_ci int off; 30f08c3bdfSopenharmony_ci} tcases[] = { 31f08c3bdfSopenharmony_ci {CLOCK_MONOTONIC, CLOCK_MONOTONIC, 10}, 32f08c3bdfSopenharmony_ci {CLOCK_BOOTTIME, CLOCK_BOOTTIME, 10}, 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_ci {CLOCK_MONOTONIC, CLOCK_MONOTONIC, -10}, 35f08c3bdfSopenharmony_ci {CLOCK_BOOTTIME, CLOCK_BOOTTIME, -10}, 36f08c3bdfSopenharmony_ci}; 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_cistatic struct time64_variants variants[] = { 39f08c3bdfSopenharmony_ci#if (__NR_timerfd_settime != __LTP__NR_INVALID_SYSCALL) 40f08c3bdfSopenharmony_ci { .clock_gettime = sys_clock_gettime, .tfd_settime = sys_timerfd_settime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 41f08c3bdfSopenharmony_ci#endif 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci#if (__NR_timerfd_settime64 != __LTP__NR_INVALID_SYSCALL) 44f08c3bdfSopenharmony_ci { .clock_gettime = sys_clock_gettime64, .tfd_settime = sys_timerfd_settime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 45f08c3bdfSopenharmony_ci#endif 46f08c3bdfSopenharmony_ci}; 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_cistatic void setup(void) 49f08c3bdfSopenharmony_ci{ 50f08c3bdfSopenharmony_ci tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); 51f08c3bdfSopenharmony_ci} 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_cistatic void verify_timerfd(unsigned int n) 54f08c3bdfSopenharmony_ci{ 55f08c3bdfSopenharmony_ci struct time64_variants *tv = &variants[tst_variant]; 56f08c3bdfSopenharmony_ci struct tst_ts start, end; 57f08c3bdfSopenharmony_ci struct tst_its it; 58f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_ci start.type = end.type = it.type = tv->ts_type; 61f08c3bdfSopenharmony_ci SAFE_UNSHARE(CLONE_NEWTIME); 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF("/proc/self/timens_offsets", "%d %d 0", 64f08c3bdfSopenharmony_ci tc->clk_off, tc->off); 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci if (tv->clock_gettime(tc->clk_id, tst_ts_get(&start))) { 67f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "clock_gettime(2) failed for clock %s", 68f08c3bdfSopenharmony_ci tst_clock_name(tc->clk_id)); 69f08c3bdfSopenharmony_ci return; 70f08c3bdfSopenharmony_ci } 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci end = tst_ts_add_us(start, 1000000 * tc->off + SLEEP_US); 73f08c3bdfSopenharmony_ci tst_its_set_interval_sec(&it, 0); 74f08c3bdfSopenharmony_ci tst_its_set_interval_nsec(&it, 0); 75f08c3bdfSopenharmony_ci tst_its_set_value_from_ts(&it, end); 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci if (!SAFE_FORK()) { 78f08c3bdfSopenharmony_ci uint64_t exp; 79f08c3bdfSopenharmony_ci int fd = SAFE_TIMERFD_CREATE(tc->clk_id, 0); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci if (tv->tfd_settime(fd, TFD_TIMER_ABSTIME, tst_its_get(&it), NULL)) { 82f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "timerfd_settime() failed"); 83f08c3bdfSopenharmony_ci return; 84f08c3bdfSopenharmony_ci } 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci SAFE_READ(1, fd, &exp, sizeof(exp)); 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci if (exp != 1) 89f08c3bdfSopenharmony_ci tst_res(TFAIL, "Got %llu expirations", (long long unsigned)exp); 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 92f08c3bdfSopenharmony_ci exit(0); 93f08c3bdfSopenharmony_ci } 94f08c3bdfSopenharmony_ci 95f08c3bdfSopenharmony_ci SAFE_WAIT(NULL); 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci if (tv->clock_gettime(tc->clk_id, tst_ts_get(&end))) { 98f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "clock_gettime(2) failed for clock %s", 99f08c3bdfSopenharmony_ci tst_clock_name(tc->clk_id)); 100f08c3bdfSopenharmony_ci return; 101f08c3bdfSopenharmony_ci } 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci long long diff = tst_ts_diff_us(end, start); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci if (diff > 5 * SLEEP_US) { 106f08c3bdfSopenharmony_ci tst_res(TFAIL, "timerfd %s slept too long %lli", 107f08c3bdfSopenharmony_ci tst_clock_name(tc->clk_id), diff); 108f08c3bdfSopenharmony_ci return; 109f08c3bdfSopenharmony_ci } 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci if (diff < SLEEP_US) { 112f08c3bdfSopenharmony_ci tst_res(TFAIL, "timerfd %s slept too short %lli", 113f08c3bdfSopenharmony_ci tst_clock_name(tc->clk_id), diff); 114f08c3bdfSopenharmony_ci return; 115f08c3bdfSopenharmony_ci } 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci tst_res(TPASS, "timerfd %s slept correctly %lli", 118f08c3bdfSopenharmony_ci tst_clock_name(tc->clk_id), diff); 119f08c3bdfSopenharmony_ci} 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_cistatic struct tst_test test = { 122f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 123f08c3bdfSopenharmony_ci .test = verify_timerfd, 124f08c3bdfSopenharmony_ci .test_variants = ARRAY_SIZE(variants), 125f08c3bdfSopenharmony_ci .setup = setup, 126f08c3bdfSopenharmony_ci .needs_root = 1, 127f08c3bdfSopenharmony_ci .forks_child = 1, 128f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 129f08c3bdfSopenharmony_ci "CONFIG_TIME_NS=y", 130f08c3bdfSopenharmony_ci NULL 131f08c3bdfSopenharmony_ci } 132f08c3bdfSopenharmony_ci}; 133