/* Demo leapsecond deadlock * by: John Stultz (john.stultz@linaro.org) * (C) Copyright IBM 2012 * (C) Copyright 2013, 2015 Linaro Limited * Licensed under the GPL * * This test demonstrates leapsecond deadlock that is possibe * on kernels from 2.6.26 to 3.3. * * WARNING: THIS WILL LIKELY HARDHANG SYSTEMS AND MAY LOSE DATA * RUN AT YOUR OWN RISK! * To build: * $ gcc leapcrash.c -o leapcrash -lrt */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/time.h> #include <sys/timex.h> #include <string.h> #include <signal.h> #ifdef KTEST #include "../kselftest.h" #else static inline int ksft_exit_pass(void) { exit(0); } static inline int ksft_exit_fail(void) { exit(1); } #endif /* clear NTP time_status & time_state */ int clear_time_state(void) { struct timex tx; int ret; /* * We have to call adjtime twice here, as kernels * prior to 6b1859dba01c7 (included in 3.5 and * -stable), had an issue with the state machine * and wouldn't clear the STA_INS/DEL flag directly. */ tx.modes = ADJ_STATUS; tx.status = STA_PLL; ret = adjtimex(&tx); tx.modes = ADJ_STATUS; tx.status = 0; ret = adjtimex(&tx); return ret; } /* Make sure we cleanup on ctrl-c */ void handler(int unused) { clear_time_state(); exit(0); } int main(void) { struct timex tx; struct timespec ts; time_t next_leap; int count = 0; setbuf(stdout, NULL); signal(SIGINT, handler); signal(SIGKILL, handler); printf("This runs for a few minutes. Press ctrl-c to stop\n"); clear_time_state(); /* Get the current time */ clock_gettime(CLOCK_REALTIME, &ts); /* Calculate the next possible leap second 23:59:60 GMT */ next_leap = ts.tv_sec; next_leap += 86400 - (next_leap % 86400); for (count = 0; count < 20; count++) { struct timeval tv; /* set the time to 2 seconds before the leap */ tv.tv_sec = next_leap - 2; tv.tv_usec = 0; if (settimeofday(&tv, NULL)) { printf("Error: You're likely not running with proper (ie: root) permissions\n"); return ksft_exit_fail(); } tx.modes = 0; adjtimex(&tx); /* hammer on adjtime w/ STA_INS */ while (tx.time.tv_sec < next_leap + 1) { /* Set the leap second insert flag */ tx.modes = ADJ_STATUS; tx.status = STA_INS; adjtimex(&tx); } clear_time_state(); printf("."); } printf("[OK]\n"); return ksft_exit_pass(); }