Repository : http://git.fedorahosted.org/cgit/kernel-tests.git
On branch : master
commit eba7bafd9275f10799f0dd4e62496b28ad608b91 Author: Justin M. Forbes jforbes@redhat.com Date: Tue Feb 17 10:02:58 2015 -0600
Add leap second test and mq memory corruption tests
default/insert_leap_second/leap-a-day.c | 307 ++++++++++++++++++++++++++ default/insert_leap_second/runtest.sh | 40 ++++ default/mq-memory-corruption/mq_notify-5.1.c | 128 +++++++++++ default/mq-memory-corruption/runtest.sh | 23 ++ 4 files changed, 498 insertions(+), 0 deletions(-)
diff --git a/default/insert_leap_second/leap-a-day.c b/default/insert_leap_second/leap-a-day.c new file mode 100644 index 0000000..628aa47 --- /dev/null +++ b/default/insert_leap_second/leap-a-day.c @@ -0,0 +1,307 @@ +/* Leap second stress test + * by: John Stultz (john.stultz@linaro.org) + * (C) Copyright IBM 2012 + * (C) Copyright 2013, 2015 Linaro Limited + * Licensed under the GPLv2 + * + * This test signals the kernel to insert a leap second + * every day at midnight GMT. This allows for stessing the + * kernel's leap-second behavior, as well as how well applications + * handle the leap-second discontinuity. + * + * Usage: leap-a-day [-s] [-i <num>] + * + * Options: + * -s: Each iteration, set the date to 10 seconds before midnight GMT. + * This speeds up the number of leapsecond transitions tested, + * but because it calls settimeofday frequently, advancing the + * time by 24 hours every ~16 seconds, it may cause application + * disruption. + * + * -i: Number of iterations to run (default: infinite) + * + * Other notes: Disabling NTP prior to running this is advised, as the two + * may conflict in thier commands to the kernel. + * + * To build: + * $ gcc leap-a-day.c -o leap-a-day -lrt + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> +#include <sys/timex.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> + +extern char *optarg; + +#define NSEC_PER_SEC 1000000000ULL +#define CLOCK_TAI 11 + +/* returns 1 if a <= b, 0 otherwise */ +static inline int in_order(struct timespec a, struct timespec b) +{ + if(a.tv_sec < b.tv_sec) + return 1; + if(a.tv_sec > b.tv_sec) + return 0; + if(a.tv_nsec > b.tv_nsec) + return 0; + return 1; +} + +struct timespec timespec_add(struct timespec ts, unsigned long long ns) +{ + ts.tv_nsec += ns; + while(ts.tv_nsec >= NSEC_PER_SEC) { + ts.tv_nsec -= NSEC_PER_SEC; + ts.tv_sec++; + } + return ts; +} + +char* time_state_str(int state) +{ + switch (state) { + case TIME_OK: return "TIME_OK"; + case TIME_INS: return "TIME_INS"; + case TIME_DEL: return "TIME_DEL"; + case TIME_OOP: return "TIME_OOP"; + case TIME_WAIT: return "TIME_WAIT"; + case TIME_BAD: return "TIME_BAD"; + } + return "ERROR"; +} + +/* clear NTP time_status & time_state */ +void 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); + + /* Clear maxerror, as it can cause UNSYNC to be set */ + tx.modes = ADJ_MAXERROR; + tx.maxerror = 0; + ret = adjtimex(&tx); + + /* Clear the status */ + tx.modes = ADJ_STATUS; + tx.status = 0; + ret = adjtimex(&tx); +} + +/* Make sure we cleanup on ctrl-c */ +void handler(int unused) +{ + clear_time_state(); + exit(0); +} + +/* Test for known hrtimer failure */ +void test_hrtimer_failure(void) +{ + struct timespec now, target; + + clock_gettime(CLOCK_REALTIME, &now); + target = timespec_add(now, NSEC_PER_SEC/2); + clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &target, NULL); + clock_gettime(CLOCK_REALTIME, &now); + + if (!in_order(target, now)) { + printf("ERROR: hrtimer early expiration failure observed.\n"); + } + +} + +int main(int argc, char** argv) +{ + int settime = 0; + int tai_time = 0; + int insert = 1; + int iterations = -1; + int opt; + + /* Process arguments */ + while ((opt = getopt(argc, argv, "sti:"))!=-1) { + switch(opt) { + case 's': + printf("Setting time to speed up testing\n"); + settime = 1; + break; + case 'i': + iterations = atoi(optarg); + break; + case 't': + tai_time = 1; + break; + default: + printf("Usage: %s [-s] [-i <iterations>]\n", argv[0]); + printf(" -s: Set time to right before leap second each iteration\n"); + printf(" -i: Number of iterations\n"); + printf(" -t: Print TAI time\n"); + exit(-1); + } + } + + /* Make sure TAI support is present if -t was used */ + if (tai_time) { + struct timespec ts; + if (clock_gettime(CLOCK_TAI, &ts)) { + printf("System doesn't support CLOCK_TAI\n"); + exit(-1); + } + } + + signal(SIGINT, handler); + signal(SIGKILL, handler); + + if (iterations < 0) + printf("This runs continuously. Press ctrl-c to stop\n"); + else + printf("Running for %i iterations. Press ctrl-c to stop\n", iterations); + + printf("\n"); + while (1) { + int ret; + struct timespec ts; + struct timex tx; + time_t now, next_leap; + + /* 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); + + if (settime) { + struct timeval tv; + tv.tv_sec = next_leap - 10; + tv.tv_usec = 0; + settimeofday(&tv, NULL); + printf("Setting time to %s", ctime(&tv.tv_sec)); + } + + /* Reset NTP time state */ + clear_time_state(); + + /* Set the leap second insert flag */ + tx.modes = ADJ_STATUS; + if (insert) + tx.status = STA_INS; + else + tx.status = STA_DEL; + ret = adjtimex(&tx); + if (ret < 0 ) { + printf("Error: Problem setting STA_INS/STA_DEL!: %s\n", + time_state_str(ret)); + return -1; + } + + /* Validate STA_INS was set */ + tx.modes = 0; + ret = adjtimex(&tx); + if (tx.status != STA_INS && tx.status != STA_DEL) { + printf("Error: STA_INS/STA_DEL not set!: %s\n", + time_state_str(ret)); + return -1; + } + + if (tai_time) { + printf("Using TAI time," + " no inconsistencies should be seen!\n"); + } + + printf("Scheduling leap second for %s", ctime(&next_leap)); + + /* Wake up 3 seconds before leap */ + ts.tv_sec = next_leap - 3; + ts.tv_nsec = 0; + + while(clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL)) + printf("Something woke us up, returning to sleep\n"); + + /* Validate STA_INS is still set */ + tx.modes = 0; + ret = adjtimex(&tx); + if (tx.status != STA_INS && tx.status != STA_DEL) { + printf("Something cleared STA_INS/STA_DEL, setting it again.\n"); + tx.modes = ADJ_STATUS; + if (insert) + tx.status = STA_INS; + else + tx.status = STA_DEL; + ret = adjtimex(&tx); + } + + /* Check adjtimex output every half second */ + now = tx.time.tv_sec; + while (now < next_leap+2) { + char buf[26]; + struct timespec tai; + + tx.modes = 0; + ret = adjtimex(&tx); + + if (tai_time) { + clock_gettime(CLOCK_TAI, &tai); + printf("%ld sec, %9ld ns\t%s\n", + tai.tv_sec, + tai.tv_nsec, + time_state_str(ret)); + } else { + ctime_r(&tx.time.tv_sec, buf); + buf[strlen(buf)-1] = 0; /*remove trailing\n */ + + printf("%s + %6ld us (%i)\t%s\n", + buf, + tx.time.tv_usec, + tx.tai, + time_state_str(ret)); + } + now = tx.time.tv_sec; + /* Sleep for another half second */ + ts.tv_sec = 0; + ts.tv_nsec = NSEC_PER_SEC/2; + clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); + } + /* Switch to using other mode */ + insert = !insert; + + /* Note if kernel has known hrtimer failure */ + test_hrtimer_failure(); + + printf("Leap complete\n\n"); + + if ((iterations != -1) && !(--iterations)) + break; + } + + clear_time_state(); + return 0; +} diff --git a/default/insert_leap_second/runtest.sh b/default/insert_leap_second/runtest.sh new file mode 100755 index 0000000..54403ac --- /dev/null +++ b/default/insert_leap_second/runtest.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# +# Licensed under the terms of the GNU GPL License version 2 + +# Test inserting a leap second + +# Make sure we can run this test successfully +source ../../utils/root-check.sh +check_root +is_root=$? +if [ "$is_root" -ne "0" ]; then + exit 3 +fi + +# build the test source (upstream is git://github.com/johnstultz-work/timetests.git) +if [ ! -f ./leap-a-day ]; then + gcc -o leap-a-day leap-a-day.c + if [ "$?" -ne "0" ]; then + echo "leap-a-day build failed." + exit 3 + fi +fi + +# Check chronyd status and disable if enabled +if ! /usr/bin/systemctl status chronyd | grep -q active; then + # We don't want to change the time without fixing it + exit 3 +else + /usr/bin/systemctl stop chronyd +fi + +# Run the test +# insert a leap second one time, and reset the time to within +# 10 seconds of midnight UTC. +./leap-a-day -s -i 1 | tee -a test.out +# Restart chronyd +/usr/bin/systemctl start chronyd +if ! grep -q TIME_WAIT test.out; then + exit -1 +fi diff --git a/default/mq-memory-corruption/mq_notify-5.1.c b/default/mq-memory-corruption/mq_notify-5.1.c new file mode 100644 index 0000000..3ec1993 --- /dev/null +++ b/default/mq-memory-corruption/mq_notify-5.1.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2003, Intel Corporation. All rights reserved. + * Created by: crystal.xiong REMOVE-THIS AT intel DOT com + * This file is licensed under the GPL license. For the full content + * of this license, see the COPYING file at the top level of this + * source tree. + */ + +/* + * mq_notify() test plan: + * If a process has registered for notification of message arrival + * at a message queue, while some thread is blocked in mq_receive + * waiting to receive a message, the arriving message should satisfy + * the appropriate mq_receive(). In this case, no notification will + * be sent. + * NOTE: The test makes some assumptions and has some potential race + * conditions, but seems the best way to test for now. + * + * 3/28/2003 Fix a bug mentioned by Michal Wronski, pass mq_attr struct + * to the mq_open(). + * + * 4/11/2003 change sa_flags from SA_RESTART to 0 to avoid compile + * error. + * + * 2/17/2004 call mq_close and mq_unlink before exit to release mq + * resources + */ + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <mqueue.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +//#include "posixtest.h" + +#define PTS_PASS 0 +#define PTS_FAIL 1 +#define PTS_UNRESOLVED 2 + +#define TEST "5-1" +#define FUNCTION "mq_notify" +#define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": " + +#define NAMESIZE 50 +#define MSG_SIZE 40 +#define BUFFER 40 + +int enter_handler = 0; + +void msg_handler() +{ + enter_handler = 1; +} + +void mqclean(mqd_t queue, const char *qname) +{ + mq_close(queue); + mq_unlink(qname); +} + +int main() +{ + char mqname[NAMESIZE]; + mqd_t mqdes; + const char s_msg_ptr[MSG_SIZE] = "test message \n"; + char r_msg_ptr[MSG_SIZE]; + struct sigevent notification; + struct sigaction sa; + unsigned int prio = 1; + int pid; + struct mq_attr attr; + + sprintf(mqname, "/" FUNCTION "_" TEST "_%d", getpid()); + attr.mq_msgsize = BUFFER; + attr.mq_maxmsg = 10;//BUFFER; + + mqdes = mq_open(mqname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, &attr); + if (mqdes == (mqd_t)-1) { + perror(ERROR_PREFIX "mq_open"); + mqclean(mqdes, mqname); + return PTS_UNRESOLVED; + } + + pid = fork(); + if (pid == -1) { + perror(ERROR_PREFIX "fork"); + mqclean(mqdes, mqname); + return PTS_UNRESOLVED; + } + if (pid == 0) { + /* child process */ + mq_receive(mqdes, r_msg_ptr, MSG_SIZE, NULL); + return 0; + } + else { + /* parent process */ + sleep(2); /* after 2 seconds, + assume that child with block on mq_receive. */ + notification.sigev_notify = SIGEV_SIGNAL; + notification.sigev_signo = SIGUSR1; + sa.sa_handler = msg_handler; + sa.sa_flags = 0; + sigaction(SIGUSR1, &sa, NULL); + if (mq_notify(mqdes, ¬ification) != 0) { + perror(ERROR_PREFIX "mq_notify"); + return PTS_UNRESOLVED; + } + if (mq_send(mqdes, s_msg_ptr, MSG_SIZE, prio) == -1) { + perror(ERROR_PREFIX "mq_send"); + return PTS_UNRESOLVED; + } + sleep(1); + if (mq_unlink(mqname) != 0) { + perror(ERROR_PREFIX "mq_unlink"); + return PTS_UNRESOLVED; + } + if (enter_handler) { + printf("Test FAILED \n"); + return PTS_FAIL; + } + printf("Test PASSED \n"); + mqclean(mqdes, mqname); + return PTS_PASS; + } +} diff --git a/default/mq-memory-corruption/runtest.sh b/default/mq-memory-corruption/runtest.sh new file mode 100755 index 0000000..75f0801 --- /dev/null +++ b/default/mq-memory-corruption/runtest.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Licensed under the terms of the GNU GPL License version 2 + +# Running mq_notify/5-1 testcase from Open POSIX testsuite appears to lead to corrupted memory. +# This is later followed by various kernel crash/BUG messages. + +if [ ! -f ./mq-notify ]; then + gcc mq_notify-5.1.c -lrt -o mq-notify + if [ "$?" -ne "0" ]; then + echo "mq-notify build failed." + exit 3 + fi +fi + +for i in {1..10} +do + ./mq-notify + if [ "$?" -ne "0" ]; then + echo "mw-notify test failure." + exit -1 + fi +done
kernel@lists.fedoraproject.org