DF-4528 / nvspam.c
/* nvspam.c -- attach-race spammer: loop forever over all /dev/nvme[0-9]*, * issuing NVMEIOCGETLOG. Restarts on errors; designed to be running when a * controller (re)attaches so it races the admin thread's identify storm. * Reports STUCK (>3s) calls and a heartbeat. */ #include <sys/ioccom.h> #include <sys/types.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <dirent.h> #include <errno.h> #include <time.h> typedef struct { unsigned char pad[4096]; } nvme_admin_data_t; typedef struct nvme_getlog_ioctl { uint8_t lid, reserved01; uint16_t status; uint32_t ret_size, beg_offset; nvme_admin_data_t info; } nvme_getlog_ioctl_t; #define NVMEIOCGETLOG _IOWR('O', 0, struct nvme_getlog_ioctl) static double now(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9; } int main(int argc, char **argv) { double last = now(), t0, t1, maxlat = 0; long n = 0, errs = 0, stuck = 0; setvbuf(stdout, NULL, _IOLBF, 0); for (;;) { DIR *d = opendir("/dev"); struct dirent *de; char path[64]; int fd = -1; if (d) { while ((de = readdir(d)) != NULL) { int v; if (sscanf(de->d_name, "nvme%d", &v) == 1) { snprintf(path, sizeof(path), "/dev/%s", de->d_name); fd = open(path, O_RDONLY); if (fd >= 0) break; } } closedir(d); } if (fd < 0) { usleep(20000); continue; } for (;;) { nvme_getlog_ioctl_t ioc; memset(&ioc, 0, sizeof(ioc)); ioc.lid = 1; ioc.ret_size = 4096; t0 = now(); if (ioctl(fd, NVMEIOCGETLOG, &ioc) < 0) { errs++; close(fd); break; } t1 = now(); if (t1 - t0 > maxlat) maxlat = t1 - t0; if (t1 - t0 > 3.0) { stuck++; printf("[%d] STUCK %.3fs (#%ld)\n", getpid(), t1 - t0, n); } n++; if (t1 - last > 1.0) { printf("[%d] HB n=%ld errs=%ld maxlat=%.4f " "stuck=%ld\n", getpid(), n, errs, maxlat, stuck); last = t1; } } } return 0; } |