15bccfe41SJohn Stultz /* Leap second stress test 25bccfe41SJohn Stultz * by: John Stultz (john.stultz@linaro.org) 35bccfe41SJohn Stultz * (C) Copyright IBM 2012 45bccfe41SJohn Stultz * (C) Copyright 2013, 2015 Linaro Limited 55bccfe41SJohn Stultz * Licensed under the GPLv2 65bccfe41SJohn Stultz * 75bccfe41SJohn Stultz * This test signals the kernel to insert a leap second 85bccfe41SJohn Stultz * every day at midnight GMT. This allows for stessing the 95bccfe41SJohn Stultz * kernel's leap-second behavior, as well as how well applications 105bccfe41SJohn Stultz * handle the leap-second discontinuity. 115bccfe41SJohn Stultz * 125bccfe41SJohn Stultz * Usage: leap-a-day [-s] [-i <num>] 135bccfe41SJohn Stultz * 145bccfe41SJohn Stultz * Options: 155bccfe41SJohn Stultz * -s: Each iteration, set the date to 10 seconds before midnight GMT. 165bccfe41SJohn Stultz * This speeds up the number of leapsecond transitions tested, 175bccfe41SJohn Stultz * but because it calls settimeofday frequently, advancing the 185bccfe41SJohn Stultz * time by 24 hours every ~16 seconds, it may cause application 195bccfe41SJohn Stultz * disruption. 205bccfe41SJohn Stultz * 215bccfe41SJohn Stultz * -i: Number of iterations to run (default: infinite) 225bccfe41SJohn Stultz * 235bccfe41SJohn Stultz * Other notes: Disabling NTP prior to running this is advised, as the two 245bccfe41SJohn Stultz * may conflict in their commands to the kernel. 255bccfe41SJohn Stultz * 265bccfe41SJohn Stultz * To build: 275bccfe41SJohn Stultz * $ gcc leap-a-day.c -o leap-a-day -lrt 285bccfe41SJohn Stultz * 295bccfe41SJohn Stultz * This program is free software: you can redistribute it and/or modify 305bccfe41SJohn Stultz * it under the terms of the GNU General Public License as published by 315bccfe41SJohn Stultz * the Free Software Foundation, either version 2 of the License, or 325bccfe41SJohn Stultz * (at your option) any later version. 335bccfe41SJohn Stultz * 345bccfe41SJohn Stultz * This program is distributed in the hope that it will be useful, 355bccfe41SJohn Stultz * but WITHOUT ANY WARRANTY; without even the implied warranty of 365bccfe41SJohn Stultz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 375bccfe41SJohn Stultz * GNU General Public License for more details. 385bccfe41SJohn Stultz */ 395bccfe41SJohn Stultz 405bccfe41SJohn Stultz 415bccfe41SJohn Stultz 425bccfe41SJohn Stultz #include <stdio.h> 435bccfe41SJohn Stultz #include <stdlib.h> 445bccfe41SJohn Stultz #include <time.h> 455bccfe41SJohn Stultz #include <sys/time.h> 465bccfe41SJohn Stultz #include <sys/timex.h> 47*0c4a5fc9SJohn Stultz #include <sys/errno.h> 485bccfe41SJohn Stultz #include <string.h> 495bccfe41SJohn Stultz #include <signal.h> 505bccfe41SJohn Stultz #include <unistd.h> 515bccfe41SJohn Stultz #ifdef KTEST 525bccfe41SJohn Stultz #include "../kselftest.h" 535bccfe41SJohn Stultz #else 545bccfe41SJohn Stultz static inline int ksft_exit_pass(void) 555bccfe41SJohn Stultz { 565bccfe41SJohn Stultz exit(0); 575bccfe41SJohn Stultz } 585bccfe41SJohn Stultz static inline int ksft_exit_fail(void) 595bccfe41SJohn Stultz { 605bccfe41SJohn Stultz exit(1); 615bccfe41SJohn Stultz } 625bccfe41SJohn Stultz #endif 635bccfe41SJohn Stultz 645bccfe41SJohn Stultz #define NSEC_PER_SEC 1000000000ULL 655bccfe41SJohn Stultz #define CLOCK_TAI 11 665bccfe41SJohn Stultz 67*0c4a5fc9SJohn Stultz time_t next_leap; 68*0c4a5fc9SJohn Stultz int error_found; 69*0c4a5fc9SJohn Stultz 705bccfe41SJohn Stultz /* returns 1 if a <= b, 0 otherwise */ 715bccfe41SJohn Stultz static inline int in_order(struct timespec a, struct timespec b) 725bccfe41SJohn Stultz { 735bccfe41SJohn Stultz if (a.tv_sec < b.tv_sec) 745bccfe41SJohn Stultz return 1; 755bccfe41SJohn Stultz if (a.tv_sec > b.tv_sec) 765bccfe41SJohn Stultz return 0; 775bccfe41SJohn Stultz if (a.tv_nsec > b.tv_nsec) 785bccfe41SJohn Stultz return 0; 795bccfe41SJohn Stultz return 1; 805bccfe41SJohn Stultz } 815bccfe41SJohn Stultz 825bccfe41SJohn Stultz struct timespec timespec_add(struct timespec ts, unsigned long long ns) 835bccfe41SJohn Stultz { 845bccfe41SJohn Stultz ts.tv_nsec += ns; 855bccfe41SJohn Stultz while (ts.tv_nsec >= NSEC_PER_SEC) { 865bccfe41SJohn Stultz ts.tv_nsec -= NSEC_PER_SEC; 875bccfe41SJohn Stultz ts.tv_sec++; 885bccfe41SJohn Stultz } 895bccfe41SJohn Stultz return ts; 905bccfe41SJohn Stultz } 915bccfe41SJohn Stultz 925bccfe41SJohn Stultz char *time_state_str(int state) 935bccfe41SJohn Stultz { 945bccfe41SJohn Stultz switch (state) { 955bccfe41SJohn Stultz case TIME_OK: return "TIME_OK"; 965bccfe41SJohn Stultz case TIME_INS: return "TIME_INS"; 975bccfe41SJohn Stultz case TIME_DEL: return "TIME_DEL"; 985bccfe41SJohn Stultz case TIME_OOP: return "TIME_OOP"; 995bccfe41SJohn Stultz case TIME_WAIT: return "TIME_WAIT"; 1005bccfe41SJohn Stultz case TIME_BAD: return "TIME_BAD"; 1015bccfe41SJohn Stultz } 1025bccfe41SJohn Stultz return "ERROR"; 1035bccfe41SJohn Stultz } 1045bccfe41SJohn Stultz 1055bccfe41SJohn Stultz /* clear NTP time_status & time_state */ 1065bccfe41SJohn Stultz int clear_time_state(void) 1075bccfe41SJohn Stultz { 1085bccfe41SJohn Stultz struct timex tx; 1095bccfe41SJohn Stultz int ret; 1105bccfe41SJohn Stultz 1115bccfe41SJohn Stultz /* 1125bccfe41SJohn Stultz * We have to call adjtime twice here, as kernels 1135bccfe41SJohn Stultz * prior to 6b1859dba01c7 (included in 3.5 and 1145bccfe41SJohn Stultz * -stable), had an issue with the state machine 1155bccfe41SJohn Stultz * and wouldn't clear the STA_INS/DEL flag directly. 1165bccfe41SJohn Stultz */ 1175bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 1185bccfe41SJohn Stultz tx.status = STA_PLL; 1195bccfe41SJohn Stultz ret = adjtimex(&tx); 1205bccfe41SJohn Stultz 1215bccfe41SJohn Stultz /* Clear maxerror, as it can cause UNSYNC to be set */ 1225bccfe41SJohn Stultz tx.modes = ADJ_MAXERROR; 1235bccfe41SJohn Stultz tx.maxerror = 0; 1245bccfe41SJohn Stultz ret = adjtimex(&tx); 1255bccfe41SJohn Stultz 1265bccfe41SJohn Stultz /* Clear the status */ 1275bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 1285bccfe41SJohn Stultz tx.status = 0; 1295bccfe41SJohn Stultz ret = adjtimex(&tx); 1305bccfe41SJohn Stultz 1315bccfe41SJohn Stultz return ret; 1325bccfe41SJohn Stultz } 1335bccfe41SJohn Stultz 1345bccfe41SJohn Stultz /* Make sure we cleanup on ctrl-c */ 1355bccfe41SJohn Stultz void handler(int unused) 1365bccfe41SJohn Stultz { 1375bccfe41SJohn Stultz clear_time_state(); 1385bccfe41SJohn Stultz exit(0); 1395bccfe41SJohn Stultz } 1405bccfe41SJohn Stultz 141*0c4a5fc9SJohn Stultz void sigalarm(int signo) 142*0c4a5fc9SJohn Stultz { 143*0c4a5fc9SJohn Stultz struct timex tx; 144*0c4a5fc9SJohn Stultz char buf[26]; 145*0c4a5fc9SJohn Stultz int ret; 146*0c4a5fc9SJohn Stultz 147*0c4a5fc9SJohn Stultz tx.modes = 0; 148*0c4a5fc9SJohn Stultz ret = adjtimex(&tx); 149*0c4a5fc9SJohn Stultz 150*0c4a5fc9SJohn Stultz ctime_r(&tx.time.tv_sec, buf); 151*0c4a5fc9SJohn Stultz buf[strlen(buf)-1] = 0; /*remove trailing\n */ 152*0c4a5fc9SJohn Stultz printf("%s + %6ld us (%i)\t%s - TIMER FIRED\n", 153*0c4a5fc9SJohn Stultz buf, 154*0c4a5fc9SJohn Stultz tx.time.tv_usec, 155*0c4a5fc9SJohn Stultz tx.tai, 156*0c4a5fc9SJohn Stultz time_state_str(ret)); 157*0c4a5fc9SJohn Stultz 158*0c4a5fc9SJohn Stultz if (tx.time.tv_sec < next_leap) { 159*0c4a5fc9SJohn Stultz printf("Error: Early timer expiration!\n"); 160*0c4a5fc9SJohn Stultz error_found = 1; 161*0c4a5fc9SJohn Stultz } 162*0c4a5fc9SJohn Stultz if (ret != TIME_WAIT) { 163*0c4a5fc9SJohn Stultz printf("Error: Incorrect NTP state?\n"); 164*0c4a5fc9SJohn Stultz error_found = 1; 165*0c4a5fc9SJohn Stultz } 166*0c4a5fc9SJohn Stultz } 167*0c4a5fc9SJohn Stultz 168*0c4a5fc9SJohn Stultz 1695bccfe41SJohn Stultz /* Test for known hrtimer failure */ 1705bccfe41SJohn Stultz void test_hrtimer_failure(void) 1715bccfe41SJohn Stultz { 1725bccfe41SJohn Stultz struct timespec now, target; 1735bccfe41SJohn Stultz 1745bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &now); 1755bccfe41SJohn Stultz target = timespec_add(now, NSEC_PER_SEC/2); 1765bccfe41SJohn Stultz clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &target, NULL); 1775bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &now); 1785bccfe41SJohn Stultz 179*0c4a5fc9SJohn Stultz if (!in_order(target, now)) { 1805bccfe41SJohn Stultz printf("ERROR: hrtimer early expiration failure observed.\n"); 181*0c4a5fc9SJohn Stultz error_found = 1; 182*0c4a5fc9SJohn Stultz } 1835bccfe41SJohn Stultz } 1845bccfe41SJohn Stultz 1855bccfe41SJohn Stultz int main(int argc, char **argv) 1865bccfe41SJohn Stultz { 187*0c4a5fc9SJohn Stultz timer_t tm1; 188*0c4a5fc9SJohn Stultz struct itimerspec its1; 189*0c4a5fc9SJohn Stultz struct sigevent se; 190*0c4a5fc9SJohn Stultz struct sigaction act; 191*0c4a5fc9SJohn Stultz int signum = SIGRTMAX; 1925bccfe41SJohn Stultz int settime = 0; 1935bccfe41SJohn Stultz int tai_time = 0; 1945bccfe41SJohn Stultz int insert = 1; 1955bccfe41SJohn Stultz int iterations = -1; 1965bccfe41SJohn Stultz int opt; 1975bccfe41SJohn Stultz 1985bccfe41SJohn Stultz /* Process arguments */ 1995bccfe41SJohn Stultz while ((opt = getopt(argc, argv, "sti:")) != -1) { 2005bccfe41SJohn Stultz switch (opt) { 2015bccfe41SJohn Stultz case 's': 2025bccfe41SJohn Stultz printf("Setting time to speed up testing\n"); 2035bccfe41SJohn Stultz settime = 1; 2045bccfe41SJohn Stultz break; 2055bccfe41SJohn Stultz case 'i': 2065bccfe41SJohn Stultz iterations = atoi(optarg); 2075bccfe41SJohn Stultz break; 2085bccfe41SJohn Stultz case 't': 2095bccfe41SJohn Stultz tai_time = 1; 2105bccfe41SJohn Stultz break; 2115bccfe41SJohn Stultz default: 2125bccfe41SJohn Stultz printf("Usage: %s [-s] [-i <iterations>]\n", argv[0]); 2135bccfe41SJohn Stultz printf(" -s: Set time to right before leap second each iteration\n"); 2145bccfe41SJohn Stultz printf(" -i: Number of iterations\n"); 2155bccfe41SJohn Stultz printf(" -t: Print TAI time\n"); 2165bccfe41SJohn Stultz exit(-1); 2175bccfe41SJohn Stultz } 2185bccfe41SJohn Stultz } 2195bccfe41SJohn Stultz 2205bccfe41SJohn Stultz /* Make sure TAI support is present if -t was used */ 2215bccfe41SJohn Stultz if (tai_time) { 2225bccfe41SJohn Stultz struct timespec ts; 2235bccfe41SJohn Stultz 2245bccfe41SJohn Stultz if (clock_gettime(CLOCK_TAI, &ts)) { 2255bccfe41SJohn Stultz printf("System doesn't support CLOCK_TAI\n"); 2265bccfe41SJohn Stultz ksft_exit_fail(); 2275bccfe41SJohn Stultz } 2285bccfe41SJohn Stultz } 2295bccfe41SJohn Stultz 2305bccfe41SJohn Stultz signal(SIGINT, handler); 2315bccfe41SJohn Stultz signal(SIGKILL, handler); 2325bccfe41SJohn Stultz 233*0c4a5fc9SJohn Stultz /* Set up timer signal handler: */ 234*0c4a5fc9SJohn Stultz sigfillset(&act.sa_mask); 235*0c4a5fc9SJohn Stultz act.sa_flags = 0; 236*0c4a5fc9SJohn Stultz act.sa_handler = sigalarm; 237*0c4a5fc9SJohn Stultz sigaction(signum, &act, NULL); 238*0c4a5fc9SJohn Stultz 2395bccfe41SJohn Stultz if (iterations < 0) 2405bccfe41SJohn Stultz printf("This runs continuously. Press ctrl-c to stop\n"); 2415bccfe41SJohn Stultz else 2425bccfe41SJohn Stultz printf("Running for %i iterations. Press ctrl-c to stop\n", iterations); 2435bccfe41SJohn Stultz 2445bccfe41SJohn Stultz printf("\n"); 2455bccfe41SJohn Stultz while (1) { 2465bccfe41SJohn Stultz int ret; 2475bccfe41SJohn Stultz struct timespec ts; 2485bccfe41SJohn Stultz struct timex tx; 249*0c4a5fc9SJohn Stultz time_t now; 2505bccfe41SJohn Stultz 2515bccfe41SJohn Stultz /* Get the current time */ 2525bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &ts); 2535bccfe41SJohn Stultz 2545bccfe41SJohn Stultz /* Calculate the next possible leap second 23:59:60 GMT */ 2555bccfe41SJohn Stultz next_leap = ts.tv_sec; 2565bccfe41SJohn Stultz next_leap += 86400 - (next_leap % 86400); 2575bccfe41SJohn Stultz 2585bccfe41SJohn Stultz if (settime) { 2595bccfe41SJohn Stultz struct timeval tv; 2605bccfe41SJohn Stultz 2615bccfe41SJohn Stultz tv.tv_sec = next_leap - 10; 2625bccfe41SJohn Stultz tv.tv_usec = 0; 2635bccfe41SJohn Stultz settimeofday(&tv, NULL); 2645bccfe41SJohn Stultz printf("Setting time to %s", ctime(&tv.tv_sec)); 2655bccfe41SJohn Stultz } 2665bccfe41SJohn Stultz 2675bccfe41SJohn Stultz /* Reset NTP time state */ 2685bccfe41SJohn Stultz clear_time_state(); 2695bccfe41SJohn Stultz 2705bccfe41SJohn Stultz /* Set the leap second insert flag */ 2715bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 2725bccfe41SJohn Stultz if (insert) 2735bccfe41SJohn Stultz tx.status = STA_INS; 2745bccfe41SJohn Stultz else 2755bccfe41SJohn Stultz tx.status = STA_DEL; 2765bccfe41SJohn Stultz ret = adjtimex(&tx); 2775bccfe41SJohn Stultz if (ret < 0) { 2785bccfe41SJohn Stultz printf("Error: Problem setting STA_INS/STA_DEL!: %s\n", 2795bccfe41SJohn Stultz time_state_str(ret)); 2805bccfe41SJohn Stultz return ksft_exit_fail(); 2815bccfe41SJohn Stultz } 2825bccfe41SJohn Stultz 2835bccfe41SJohn Stultz /* Validate STA_INS was set */ 2845bccfe41SJohn Stultz tx.modes = 0; 2855bccfe41SJohn Stultz ret = adjtimex(&tx); 2865bccfe41SJohn Stultz if (tx.status != STA_INS && tx.status != STA_DEL) { 2875bccfe41SJohn Stultz printf("Error: STA_INS/STA_DEL not set!: %s\n", 2885bccfe41SJohn Stultz time_state_str(ret)); 2895bccfe41SJohn Stultz return ksft_exit_fail(); 2905bccfe41SJohn Stultz } 2915bccfe41SJohn Stultz 2925bccfe41SJohn Stultz if (tai_time) { 2935bccfe41SJohn Stultz printf("Using TAI time," 2945bccfe41SJohn Stultz " no inconsistencies should be seen!\n"); 2955bccfe41SJohn Stultz } 2965bccfe41SJohn Stultz 2975bccfe41SJohn Stultz printf("Scheduling leap second for %s", ctime(&next_leap)); 2985bccfe41SJohn Stultz 299*0c4a5fc9SJohn Stultz /* Set up timer */ 300*0c4a5fc9SJohn Stultz printf("Setting timer for %s", ctime(&next_leap)); 301*0c4a5fc9SJohn Stultz memset(&se, 0, sizeof(se)); 302*0c4a5fc9SJohn Stultz se.sigev_notify = SIGEV_SIGNAL; 303*0c4a5fc9SJohn Stultz se.sigev_signo = signum; 304*0c4a5fc9SJohn Stultz se.sigev_value.sival_int = 0; 305*0c4a5fc9SJohn Stultz if (timer_create(CLOCK_REALTIME, &se, &tm1) == -1) { 306*0c4a5fc9SJohn Stultz printf("Error: timer_create failed\n"); 307*0c4a5fc9SJohn Stultz return ksft_exit_fail(); 308*0c4a5fc9SJohn Stultz } 309*0c4a5fc9SJohn Stultz its1.it_value.tv_sec = next_leap; 310*0c4a5fc9SJohn Stultz its1.it_value.tv_nsec = 0; 311*0c4a5fc9SJohn Stultz its1.it_interval.tv_sec = 0; 312*0c4a5fc9SJohn Stultz its1.it_interval.tv_nsec = 0; 313*0c4a5fc9SJohn Stultz timer_settime(tm1, TIMER_ABSTIME, &its1, NULL); 314*0c4a5fc9SJohn Stultz 3155bccfe41SJohn Stultz /* Wake up 3 seconds before leap */ 3165bccfe41SJohn Stultz ts.tv_sec = next_leap - 3; 3175bccfe41SJohn Stultz ts.tv_nsec = 0; 3185bccfe41SJohn Stultz 319*0c4a5fc9SJohn Stultz 3205bccfe41SJohn Stultz while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL)) 3215bccfe41SJohn Stultz printf("Something woke us up, returning to sleep\n"); 3225bccfe41SJohn Stultz 3235bccfe41SJohn Stultz /* Validate STA_INS is still set */ 3245bccfe41SJohn Stultz tx.modes = 0; 3255bccfe41SJohn Stultz ret = adjtimex(&tx); 3265bccfe41SJohn Stultz if (tx.status != STA_INS && tx.status != STA_DEL) { 3275bccfe41SJohn Stultz printf("Something cleared STA_INS/STA_DEL, setting it again.\n"); 3285bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 3295bccfe41SJohn Stultz if (insert) 3305bccfe41SJohn Stultz tx.status = STA_INS; 3315bccfe41SJohn Stultz else 3325bccfe41SJohn Stultz tx.status = STA_DEL; 3335bccfe41SJohn Stultz ret = adjtimex(&tx); 3345bccfe41SJohn Stultz } 3355bccfe41SJohn Stultz 3365bccfe41SJohn Stultz /* Check adjtimex output every half second */ 3375bccfe41SJohn Stultz now = tx.time.tv_sec; 3385bccfe41SJohn Stultz while (now < next_leap + 2) { 3395bccfe41SJohn Stultz char buf[26]; 3405bccfe41SJohn Stultz struct timespec tai; 341*0c4a5fc9SJohn Stultz int ret; 3425bccfe41SJohn Stultz 3435bccfe41SJohn Stultz tx.modes = 0; 3445bccfe41SJohn Stultz ret = adjtimex(&tx); 3455bccfe41SJohn Stultz 3465bccfe41SJohn Stultz if (tai_time) { 3475bccfe41SJohn Stultz clock_gettime(CLOCK_TAI, &tai); 3485bccfe41SJohn Stultz printf("%ld sec, %9ld ns\t%s\n", 3495bccfe41SJohn Stultz tai.tv_sec, 3505bccfe41SJohn Stultz tai.tv_nsec, 3515bccfe41SJohn Stultz time_state_str(ret)); 3525bccfe41SJohn Stultz } else { 3535bccfe41SJohn Stultz ctime_r(&tx.time.tv_sec, buf); 3545bccfe41SJohn Stultz buf[strlen(buf)-1] = 0; /*remove trailing\n */ 3555bccfe41SJohn Stultz 3565bccfe41SJohn Stultz printf("%s + %6ld us (%i)\t%s\n", 3575bccfe41SJohn Stultz buf, 3585bccfe41SJohn Stultz tx.time.tv_usec, 3595bccfe41SJohn Stultz tx.tai, 3605bccfe41SJohn Stultz time_state_str(ret)); 3615bccfe41SJohn Stultz } 3625bccfe41SJohn Stultz now = tx.time.tv_sec; 3635bccfe41SJohn Stultz /* Sleep for another half second */ 3645bccfe41SJohn Stultz ts.tv_sec = 0; 3655bccfe41SJohn Stultz ts.tv_nsec = NSEC_PER_SEC / 2; 3665bccfe41SJohn Stultz clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); 3675bccfe41SJohn Stultz } 3685bccfe41SJohn Stultz /* Switch to using other mode */ 3695bccfe41SJohn Stultz insert = !insert; 3705bccfe41SJohn Stultz 3715bccfe41SJohn Stultz /* Note if kernel has known hrtimer failure */ 3725bccfe41SJohn Stultz test_hrtimer_failure(); 3735bccfe41SJohn Stultz 374*0c4a5fc9SJohn Stultz printf("Leap complete\n"); 375*0c4a5fc9SJohn Stultz if (error_found) { 376*0c4a5fc9SJohn Stultz printf("Errors observed\n"); 377*0c4a5fc9SJohn Stultz clear_time_state(); 378*0c4a5fc9SJohn Stultz return ksft_exit_fail(); 379*0c4a5fc9SJohn Stultz } 380*0c4a5fc9SJohn Stultz printf("\n"); 3815bccfe41SJohn Stultz if ((iterations != -1) && !(--iterations)) 3825bccfe41SJohn Stultz break; 3835bccfe41SJohn Stultz } 3845bccfe41SJohn Stultz 3855bccfe41SJohn Stultz clear_time_state(); 3865bccfe41SJohn Stultz return ksft_exit_pass(); 3875bccfe41SJohn Stultz } 388