1d7b2902cSJohn Stultz /* Demo leapsecond deadlock 2d7b2902cSJohn Stultz * by: John Stultz (john.stultz@linaro.org) 3d7b2902cSJohn Stultz * (C) Copyright IBM 2012 4d7b2902cSJohn Stultz * (C) Copyright 2013, 2015 Linaro Limited 5d7b2902cSJohn Stultz * Licensed under the GPL 6d7b2902cSJohn Stultz * 7*4bf07f65SIngo Molnar * This test demonstrates leapsecond deadlock that is possible 8d7b2902cSJohn Stultz * on kernels from 2.6.26 to 3.3. 9d7b2902cSJohn Stultz * 10d7b2902cSJohn Stultz * WARNING: THIS WILL LIKELY HARD HANG SYSTEMS AND MAY LOSE DATA 11d7b2902cSJohn Stultz * RUN AT YOUR OWN RISK! 12d7b2902cSJohn Stultz * To build: 13d7b2902cSJohn Stultz * $ gcc leapcrash.c -o leapcrash -lrt 14d7b2902cSJohn Stultz */ 15d7b2902cSJohn Stultz 16d7b2902cSJohn Stultz 17d7b2902cSJohn Stultz 18d7b2902cSJohn Stultz #include <stdio.h> 19d7b2902cSJohn Stultz #include <stdlib.h> 20d7b2902cSJohn Stultz #include <time.h> 21d7b2902cSJohn Stultz #include <sys/time.h> 22d7b2902cSJohn Stultz #include <sys/timex.h> 23d7b2902cSJohn Stultz #include <string.h> 24d7b2902cSJohn Stultz #include <signal.h> 25d7b2902cSJohn Stultz #include "../kselftest.h" 26d7b2902cSJohn Stultz 27d7b2902cSJohn Stultz /* clear NTP time_status & time_state */ clear_time_state(void)28d7b2902cSJohn Stultzint clear_time_state(void) 29d7b2902cSJohn Stultz { 30d7b2902cSJohn Stultz struct timex tx; 31d7b2902cSJohn Stultz int ret; 32d7b2902cSJohn Stultz 33d7b2902cSJohn Stultz /* 34d7b2902cSJohn Stultz * We have to call adjtime twice here, as kernels 35d7b2902cSJohn Stultz * prior to 6b1859dba01c7 (included in 3.5 and 36d7b2902cSJohn Stultz * -stable), had an issue with the state machine 37d7b2902cSJohn Stultz * and wouldn't clear the STA_INS/DEL flag directly. 38d7b2902cSJohn Stultz */ 39d7b2902cSJohn Stultz tx.modes = ADJ_STATUS; 40d7b2902cSJohn Stultz tx.status = STA_PLL; 41d7b2902cSJohn Stultz ret = adjtimex(&tx); 42d7b2902cSJohn Stultz 43d7b2902cSJohn Stultz tx.modes = ADJ_STATUS; 44d7b2902cSJohn Stultz tx.status = 0; 45d7b2902cSJohn Stultz ret = adjtimex(&tx); 46d7b2902cSJohn Stultz 47d7b2902cSJohn Stultz return ret; 48d7b2902cSJohn Stultz } 49d7b2902cSJohn Stultz 50d7b2902cSJohn Stultz /* Make sure we cleanup on ctrl-c */ handler(int unused)51d7b2902cSJohn Stultzvoid handler(int unused) 52d7b2902cSJohn Stultz { 53d7b2902cSJohn Stultz clear_time_state(); 54d7b2902cSJohn Stultz exit(0); 55d7b2902cSJohn Stultz } 56d7b2902cSJohn Stultz 57d7b2902cSJohn Stultz main(void)58d7b2902cSJohn Stultzint main(void) 59d7b2902cSJohn Stultz { 60d7b2902cSJohn Stultz struct timex tx; 61d7b2902cSJohn Stultz struct timespec ts; 62d7b2902cSJohn Stultz time_t next_leap; 63d7b2902cSJohn Stultz int count = 0; 64d7b2902cSJohn Stultz 65d7b2902cSJohn Stultz setbuf(stdout, NULL); 66d7b2902cSJohn Stultz 67d7b2902cSJohn Stultz signal(SIGINT, handler); 68d7b2902cSJohn Stultz signal(SIGKILL, handler); 69d7b2902cSJohn Stultz printf("This runs for a few minutes. Press ctrl-c to stop\n"); 70d7b2902cSJohn Stultz 71d7b2902cSJohn Stultz clear_time_state(); 72d7b2902cSJohn Stultz 73d7b2902cSJohn Stultz 74d7b2902cSJohn Stultz /* Get the current time */ 75d7b2902cSJohn Stultz clock_gettime(CLOCK_REALTIME, &ts); 76d7b2902cSJohn Stultz 77d7b2902cSJohn Stultz /* Calculate the next possible leap second 23:59:60 GMT */ 78d7b2902cSJohn Stultz next_leap = ts.tv_sec; 79d7b2902cSJohn Stultz next_leap += 86400 - (next_leap % 86400); 80d7b2902cSJohn Stultz 81d7b2902cSJohn Stultz for (count = 0; count < 20; count++) { 82d7b2902cSJohn Stultz struct timeval tv; 83d7b2902cSJohn Stultz 84d7b2902cSJohn Stultz 85d7b2902cSJohn Stultz /* set the time to 2 seconds before the leap */ 86d7b2902cSJohn Stultz tv.tv_sec = next_leap - 2; 87d7b2902cSJohn Stultz tv.tv_usec = 0; 88d7b2902cSJohn Stultz if (settimeofday(&tv, NULL)) { 89d7b2902cSJohn Stultz printf("Error: You're likely not running with proper (ie: root) permissions\n"); 90d7b2902cSJohn Stultz return ksft_exit_fail(); 91d7b2902cSJohn Stultz } 92d7b2902cSJohn Stultz tx.modes = 0; 93d7b2902cSJohn Stultz adjtimex(&tx); 94d7b2902cSJohn Stultz 95d7b2902cSJohn Stultz /* hammer on adjtime w/ STA_INS */ 96d7b2902cSJohn Stultz while (tx.time.tv_sec < next_leap + 1) { 97d7b2902cSJohn Stultz /* Set the leap second insert flag */ 98d7b2902cSJohn Stultz tx.modes = ADJ_STATUS; 99d7b2902cSJohn Stultz tx.status = STA_INS; 100d7b2902cSJohn Stultz adjtimex(&tx); 101d7b2902cSJohn Stultz } 102d7b2902cSJohn Stultz clear_time_state(); 103d7b2902cSJohn Stultz printf("."); 104fe483192SKees Cook fflush(stdout); 105d7b2902cSJohn Stultz } 106d7b2902cSJohn Stultz printf("[OK]\n"); 107d7b2902cSJohn Stultz return ksft_exit_pass(); 108d7b2902cSJohn Stultz } 109