DF-2816 / race2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | /* * DF-2815 - direct-syscall variant. * * Main thread calls reboot(2) directly (RB_DUMP), churn threads on other * CPUs keep issuing DIOCGKERNELDUMP set/clear against the global `dumper' * while the kernel is inside boot() -> dumpsys() -> md_dumpsys(&dumper). * * A clear (set_dumper(NULL) bzero, kern_shutdown.c:952) landing after * dumpsys() has passed its `dumper.dumper != NULL' check (kern_shutdown.c:980) * leaves di->priv == NULL for the next dev_ddump() in minidump_machdep.c * -> dev_needmplock(NULL) dereferences NULL->si_ops -> kernel page fault * while dumping. * * usage: race2 <device> <nthreads> <clearmask-log2> */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/diskslice.h> #include <sys/reboot.h> #include <sys/syscall.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdarg.h> #include <pthread.h> static int fd; static int clear_shift = 8; /* clear every (1<<shift) ioctls */ static volatile unsigned long n_ok, n_err, n_set, n_clr; static volatile int stop; static FILE *logf; static void logline(const char *fmt, ...) { va_list ap; time_t t; char b[128]; time(&t); va_start(ap, fmt); vsnprintf(b, sizeof(b), fmt, ap); va_end(ap); fprintf(logf, "%ld %s", (long)t, b); fflush(logf); } static void * churn(void *x __unused) { u_int u; unsigned long i = 0; while (!stop) { u = ((i & ((1UL << clear_shift) - 1)) == 0) ? 0 : 1; if (ioctl(fd, DIOCGKERNELDUMP, &u) == 0) { n_ok++; if (u) n_set++; else n_clr++; } else { n_err++; } i++; } return (NULL); } int main(int argc, char **argv) { pthread_t tid[64]; int nthreads = 4; int i; if (argc > 1) fd = open(argv[1], O_RDONLY); else fd = open("/dev/vbd0s1b", O_RDONLY); if (argc > 2) nthreads = atoi(argv[2]); if (argc > 3) clear_shift = atoi(argv[3]); if (nthreads > 64) nthreads = 64; logf = fopen("/root/race2.log", "w"); if (logf == NULL) logf = stderr; setvbuf(logf, NULL, _IONBF, 0); if (fd < 0) { logline("open failed\n"); exit(1); } logline("race2: starting %d churn threads clear_shift=%d\n", nthreads, clear_shift); for (i = 0; i < nthreads; i++) pthread_create(&tid[i], NULL, churn, NULL); sleep(1); /* let churn ramp up */ logline("race2: calling reboot(RB_DUMP|RB_NOSYNC) now, ok=%lu clr=%lu\n", n_ok, n_clr); syscall(SYS_reboot, RB_AUTOBOOT | RB_DUMP | RB_NOSYNC); logline("race2: reboot returned?!\n"); stop = 1; for (i = 0; i < nthreads; i++) pthread_join(tid[i], NULL); logline("race2: done ok=%lu err=%lu set=%lu clr=%lu\n", n_ok, n_err, n_set, n_clr); return (0); } |