1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) Red Hat, Inc., 2012. 4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2019 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Author: Lingzhu Xiang <lxiang@redhat.com> 7f08c3bdfSopenharmony_ci * 8f08c3bdfSopenharmony_ci * Ported to new library: 9f08c3bdfSopenharmony_ci * 07/2019 Christian Amann <camann@suse.com> 10f08c3bdfSopenharmony_ci */ 11f08c3bdfSopenharmony_ci/* 12f08c3bdfSopenharmony_ci * Regression test for hrtimer early expiration during and after leap seconds 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * A bug in the hrtimer subsystem caused all TIMER_ABSTIME CLOCK_REALTIME 15f08c3bdfSopenharmony_ci * timers to expire one second early during leap second. 16f08c3bdfSopenharmony_ci * See http://lwn.net/Articles/504658/. 17f08c3bdfSopenharmony_ci * 18f08c3bdfSopenharmony_ci * This is a regression test for the bug. 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * Note: running this test simultaneously with a timesync daemon 21f08c3bdfSopenharmony_ci * (e.g. systemd-timesyncd) can cause this test to fail. 22f08c3bdfSopenharmony_ci */ 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#include <sys/types.h> 25f08c3bdfSopenharmony_ci#include <errno.h> 26f08c3bdfSopenharmony_ci#include <stdio.h> 27f08c3bdfSopenharmony_ci#include <time.h> 28f08c3bdfSopenharmony_ci#include "tst_test.h" 29f08c3bdfSopenharmony_ci#include "tst_safe_clocks.h" 30f08c3bdfSopenharmony_ci#include "lapi/common_timers.h" 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci#define SECONDS_BEFORE_LEAP 2 33f08c3bdfSopenharmony_ci#define SECONDS_AFTER_LEAP 2 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_cistatic int errors; 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_cistatic const char *strtime(const struct timespec *now) 38f08c3bdfSopenharmony_ci{ 39f08c3bdfSopenharmony_ci static char fmt[256], buf[256]; 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci if (snprintf(fmt, sizeof(fmt), "%%T.%09ld", now->tv_nsec) < 0) { 42f08c3bdfSopenharmony_ci buf[0] = '\0'; 43f08c3bdfSopenharmony_ci return buf; 44f08c3bdfSopenharmony_ci } 45f08c3bdfSopenharmony_ci if (!strftime(buf, sizeof(buf), fmt, localtime(&now->tv_sec))) { 46f08c3bdfSopenharmony_ci buf[0] = '\0'; 47f08c3bdfSopenharmony_ci return buf; 48f08c3bdfSopenharmony_ci } 49f08c3bdfSopenharmony_ci return buf; 50f08c3bdfSopenharmony_ci} 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cistatic inline int in_order(struct timespec a, struct timespec b) 53f08c3bdfSopenharmony_ci{ 54f08c3bdfSopenharmony_ci if (a.tv_sec < b.tv_sec) 55f08c3bdfSopenharmony_ci return 1; 56f08c3bdfSopenharmony_ci if (a.tv_sec > b.tv_sec) 57f08c3bdfSopenharmony_ci return 0; 58f08c3bdfSopenharmony_ci if (a.tv_nsec > b.tv_nsec) 59f08c3bdfSopenharmony_ci return 0; 60f08c3bdfSopenharmony_ci return 1; 61f08c3bdfSopenharmony_ci} 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_cistatic void adjtimex_status(struct timex *tx, int status) 64f08c3bdfSopenharmony_ci{ 65f08c3bdfSopenharmony_ci const char *const msgs[6] = { 66f08c3bdfSopenharmony_ci "clock synchronized", 67f08c3bdfSopenharmony_ci "insert leap second", 68f08c3bdfSopenharmony_ci "delete leap second", 69f08c3bdfSopenharmony_ci "leap second in progress", 70f08c3bdfSopenharmony_ci "leap second has occurred", 71f08c3bdfSopenharmony_ci "clock not synchronized", 72f08c3bdfSopenharmony_ci }; 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci int ret; 75f08c3bdfSopenharmony_ci struct timespec now; 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci tx->modes = ADJ_STATUS; 78f08c3bdfSopenharmony_ci tx->status = status; 79f08c3bdfSopenharmony_ci ret = adjtimex(tx); 80f08c3bdfSopenharmony_ci now.tv_sec = tx->time.tv_sec; 81f08c3bdfSopenharmony_ci now.tv_nsec = tx->time.tv_usec * 1000; 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci if ((tx->status & status) != status) 84f08c3bdfSopenharmony_ci tst_brk(TBROK, "adjtimex status %d not set", status); 85f08c3bdfSopenharmony_ci else if (ret < 0) 86f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "adjtimex"); 87f08c3bdfSopenharmony_ci else if (ret < 6) 88f08c3bdfSopenharmony_ci tst_res(TINFO, "%s adjtimex: %s", strtime(&now), msgs[ret]); 89f08c3bdfSopenharmony_ci else 90f08c3bdfSopenharmony_ci tst_res(TINFO, "%s adjtimex: clock state %d", 91f08c3bdfSopenharmony_ci strtime(&now), ret); 92f08c3bdfSopenharmony_ci} 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_cistatic void test_hrtimer_early_expiration(void) 95f08c3bdfSopenharmony_ci{ 96f08c3bdfSopenharmony_ci struct timespec now, target; 97f08c3bdfSopenharmony_ci int ret; 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &now); 100f08c3bdfSopenharmony_ci tst_res(TINFO, "now is %s", strtime(&now)); 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci target = now; 103f08c3bdfSopenharmony_ci target.tv_sec++; 104f08c3bdfSopenharmony_ci tst_res(TINFO, "sleep until %s", strtime(&target)); 105f08c3bdfSopenharmony_ci ret = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &target, NULL); 106f08c3bdfSopenharmony_ci if (ret < 0) { 107f08c3bdfSopenharmony_ci tst_res(TINFO | TERRNO, "clock_nanosleep"); 108f08c3bdfSopenharmony_ci return; 109f08c3bdfSopenharmony_ci } 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &now); 112f08c3bdfSopenharmony_ci tst_res(TINFO, "now is %s", strtime(&now)); 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_ci if (in_order(target, now)) { 115f08c3bdfSopenharmony_ci tst_res(TINFO, "hrtimer early expiration is not detected."); 116f08c3bdfSopenharmony_ci } else { 117f08c3bdfSopenharmony_ci tst_res(TFAIL, "hrtimer early expiration is detected."); 118f08c3bdfSopenharmony_ci errors++; 119f08c3bdfSopenharmony_ci } 120f08c3bdfSopenharmony_ci} 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_cistatic void run_leapsec(void) 123f08c3bdfSopenharmony_ci{ 124f08c3bdfSopenharmony_ci const struct timespec sleeptime = { 0, NSEC_PER_SEC / 2 }; 125f08c3bdfSopenharmony_ci struct timespec now, leap, start; 126f08c3bdfSopenharmony_ci struct timex tx; 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &now); 129f08c3bdfSopenharmony_ci start = now; 130f08c3bdfSopenharmony_ci tst_res(TINFO, "test start at %s", strtime(&now)); 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_ci test_hrtimer_early_expiration(); 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_ci /* calculate the next leap second */ 135f08c3bdfSopenharmony_ci now.tv_sec += 86400 - now.tv_sec % 86400; 136f08c3bdfSopenharmony_ci now.tv_nsec = 0; 137f08c3bdfSopenharmony_ci leap = now; 138f08c3bdfSopenharmony_ci tst_res(TINFO, "scheduling leap second %s", strtime(&leap)); 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci /* start before the leap second */ 141f08c3bdfSopenharmony_ci now.tv_sec -= SECONDS_BEFORE_LEAP; 142f08c3bdfSopenharmony_ci SAFE_CLOCK_SETTIME(CLOCK_REALTIME, &now); 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci tst_res(TINFO, "setting time to %s", strtime(&now)); 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_ci /* reset NTP time state */ 147f08c3bdfSopenharmony_ci adjtimex_status(&tx, STA_PLL); 148f08c3bdfSopenharmony_ci adjtimex_status(&tx, 0); 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci /* set the leap second insert flag */ 151f08c3bdfSopenharmony_ci adjtimex_status(&tx, STA_INS); 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_ci /* reliably sleep until after the leap second */ 154f08c3bdfSopenharmony_ci while (tx.time.tv_sec < leap.tv_sec + SECONDS_AFTER_LEAP) { 155f08c3bdfSopenharmony_ci adjtimex_status(&tx, tx.status); 156f08c3bdfSopenharmony_ci clock_nanosleep(CLOCK_MONOTONIC, 0, &sleeptime, NULL); 157f08c3bdfSopenharmony_ci } 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_ci test_hrtimer_early_expiration(); 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci adjtimex_status(&tx, STA_PLL); 162f08c3bdfSopenharmony_ci adjtimex_status(&tx, 0); 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_ci /* recover from timer expiring state and restore time */ 165f08c3bdfSopenharmony_ci SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &now); 166f08c3bdfSopenharmony_ci start.tv_sec += now.tv_sec - (leap.tv_sec - SECONDS_BEFORE_LEAP); 167f08c3bdfSopenharmony_ci start.tv_nsec += now.tv_nsec; 168f08c3bdfSopenharmony_ci start.tv_sec += start.tv_nsec / NSEC_PER_SEC; 169f08c3bdfSopenharmony_ci start.tv_nsec = start.tv_nsec % NSEC_PER_SEC; 170f08c3bdfSopenharmony_ci tst_res(TINFO, "restoring time to %s", strtime(&start)); 171f08c3bdfSopenharmony_ci /* calls clock_was_set() in kernel to revert inconsistency */ 172f08c3bdfSopenharmony_ci SAFE_CLOCK_SETTIME(CLOCK_REALTIME, &start); 173f08c3bdfSopenharmony_ci 174f08c3bdfSopenharmony_ci test_hrtimer_early_expiration(); 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci if (!errors) 177f08c3bdfSopenharmony_ci tst_res(TPASS, "No errors were reported during this test!"); 178f08c3bdfSopenharmony_ci else 179f08c3bdfSopenharmony_ci tst_res(TFAIL, "Got %d errors during this test!", errors); 180f08c3bdfSopenharmony_ci 181f08c3bdfSopenharmony_ci} 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_cistatic void setup(void) 184f08c3bdfSopenharmony_ci{ 185f08c3bdfSopenharmony_ci errors = 0; 186f08c3bdfSopenharmony_ci} 187f08c3bdfSopenharmony_ci 188f08c3bdfSopenharmony_cistatic void cleanup(void) 189f08c3bdfSopenharmony_ci{ 190f08c3bdfSopenharmony_ci struct timespec now; 191f08c3bdfSopenharmony_ci 192f08c3bdfSopenharmony_ci SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &now); 193f08c3bdfSopenharmony_ci /* Calls clock_was_set() in the kernel to revert inconsistencies. 194f08c3bdfSopenharmony_ci * The only possible error EPERM doesn't matter here. */ 195f08c3bdfSopenharmony_ci SAFE_CLOCK_SETTIME(CLOCK_REALTIME, &now); 196f08c3bdfSopenharmony_ci} 197f08c3bdfSopenharmony_ci 198f08c3bdfSopenharmony_cistatic struct tst_test test = { 199f08c3bdfSopenharmony_ci .test_all = run_leapsec, 200f08c3bdfSopenharmony_ci .setup = setup, 201f08c3bdfSopenharmony_ci .cleanup = cleanup, 202f08c3bdfSopenharmony_ci .needs_root = 1, 203f08c3bdfSopenharmony_ci}; 204