DF-2615 / df2615_trigger.c
/* * DF-2615 PoC — one kdmsg_msg (the LNK_PING allocated in * kdmsg_iocom_uninit, kern_dmsg.c:280-281) leaks per hammer2 * mount/umount cycle when the mount was created with * cluster_fd < 0 (no iocom threads ever created, so nothing * drains iocom->msgq and EXITNOACC is never set). * * On the instrumented kernel each cycle prints: * DF2615_LEAK: 1 kdmsg_msg(s) queued at iocom_uninit exit * * Note: stock mount_hammer2(8) usually supplies cluster_fd >= 0 * (it auto-starts the hammer2 service daemon and connects to it), * which creates the iocom threads; in that configuration the write * thread sets EXITNOACC and the PING is drained. The leak path is * taken whenever the mount proceeds without a cluster connection * (daemon not running / connect failed -> mount_hammer2 passes -1, * or any direct mount(2) caller). * * build: cc -O -I/usr/src/sys -o df2615_trigger df2615_trigger.c * run: (root) ./df2615_trigger [cycles] */ #include <sys/param.h> #include <sys/mount.h> #include <sys/stat.h> #include <vfs/hammer2/hammer2_mount.h> #include <err.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define MOUNTPT "/mnt/h2leak" #define VOLUME "/dev/vn0@testvol" int main(int argc, char **argv) { struct hammer2_mount_info info; int n = (argc > 1) ? atoi(argv[1]) : 20; int i; if (mkdir(MOUNTPT, 0755) < 0 && errno != EEXIST) err(1, "mkdir " MOUNTPT); memset(&info, 0, sizeof(info)); info.volume = VOLUME; info.hflags = 0; info.cluster_fd = -1; /* no cluster -> no iocom threads */ for (i = 0; i < n; i++) { if (mount("hammer2", MOUNTPT, 0, &info) < 0) err(1, "mount cycle %d", i); if (unmount(MOUNTPT, 0) < 0) err(1, "unmount cycle %d", i); } printf("CYCLES_DONE=%d (cluster_fd=-1, no iocom threads)\n", n); return (0); } |