1a18c35b9SAndreas Jaekel #include <stdio.h> 2a18c35b9SAndreas Jaekel #include <unistd.h> 3a18c35b9SAndreas Jaekel #include <stdlib.h> 4a18c35b9SAndreas Jaekel #include <fcntl.h> 5a18c35b9SAndreas Jaekel #include <stropts.h> 6a18c35b9SAndreas Jaekel #include <poll.h> 7a18c35b9SAndreas Jaekel #include <string.h> 8a18c35b9SAndreas Jaekel #include <sys/fs/zev.h> 9a18c35b9SAndreas Jaekel #include <errno.h> 10*aafc540fSAndreas Jaekel #include <libnvpair.h> 11a18c35b9SAndreas Jaekel 12a18c35b9SAndreas Jaekel #define OP_STATISTICS (1 << 0) 13a18c35b9SAndreas Jaekel #define OP_POLL_EVENTS (1 << 1) 14a18c35b9SAndreas Jaekel #define OP_MUTE_POOL (1 << 2) 15a18c35b9SAndreas Jaekel #define OP_UNMUTE_POOL (1 << 3) 16a18c35b9SAndreas Jaekel #define OP_SET_MAX_QUEUE_LEN (1 << 4) 17a18c35b9SAndreas Jaekel 18a18c35b9SAndreas Jaekel #define ZEV_DEVICE "/devices/pseudo/zev@0:zev" 19a18c35b9SAndreas Jaekel 20a18c35b9SAndreas Jaekel static char *zev_device = ZEV_DEVICE; 21a18c35b9SAndreas Jaekel 22*aafc540fSAndreas Jaekel static char *zev_op_name[] = { 23*aafc540fSAndreas Jaekel "ZEV_OP_ERROR", 24*aafc540fSAndreas Jaekel "ZEV_OP_ZFS_MOUNT", 25*aafc540fSAndreas Jaekel "ZEV_OP_ZFS_UMOUNT", 26*aafc540fSAndreas Jaekel "ZEV_OP_ZVOL_WRITE", 27*aafc540fSAndreas Jaekel "ZEV_OP_ZVOL_TRUNCATE", 28*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE", 29*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_CREATE", 30*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_MKDIR", 31*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_MAKE_XATTR_DIR", 32*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_REMOVE", 33*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_RMDIR", 34*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_LINK", 35*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_SYMLINK", 36*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_RENAME", 37*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_WRITE", 38*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_TRUNCATE", 39*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_SETATTR", 40*aafc540fSAndreas Jaekel "ZEV_OP_ZNODE_ACL", 41*aafc540fSAndreas Jaekel NULL 42*aafc540fSAndreas Jaekel }; 43*aafc540fSAndreas Jaekel 44a18c35b9SAndreas Jaekel static void 45a18c35b9SAndreas Jaekel zev_statistics(int fd) 46a18c35b9SAndreas Jaekel { 47a18c35b9SAndreas Jaekel zev_statistics_t zs; 48a18c35b9SAndreas Jaekel if (ioctl(fd, ZEV_IOC_GET_STATISTICS, &zs)) { 49a18c35b9SAndreas Jaekel perror("getting statistics data failed"); 50a18c35b9SAndreas Jaekel exit (EXIT_FAILURE); 51a18c35b9SAndreas Jaekel } 52a18c35b9SAndreas Jaekel printf("ZEV module state:\n"); 53a18c35b9SAndreas Jaekel 54a18c35b9SAndreas Jaekel printf(" queue length in bytes : %lu\n", zs.zev_queue_len); 55a18c35b9SAndreas Jaekel printf(" queue length limit : %lu\n", zs.zev_max_queue_len); 56fec460f8SAndreas Jaekel printf(" poll wakeup throttle : %lu\n\n", 57fec460f8SAndreas Jaekel zs.zev_poll_wakeup_queue_len); 58a18c35b9SAndreas Jaekel printf(" bytes read from device : %lu\n", zs.zev_bytes_read); 59a18c35b9SAndreas Jaekel printf(" module internal errors : %lu\n\n", zs.zev_cnt_errors); 60a18c35b9SAndreas Jaekel 61a18c35b9SAndreas Jaekel printf("ZFS event statistics:\n"); 62a18c35b9SAndreas Jaekel 63a18c35b9SAndreas Jaekel printf(" total ZFS events : %lu\n", zs.zev_cnt_total_events); 64a18c35b9SAndreas Jaekel printf(" ZFS mount : %lu\n", zs.zev_cnt_zfs_mount); 65a18c35b9SAndreas Jaekel printf(" ZFS umount : %lu\n", zs.zev_cnt_zfs_umount); 66a18c35b9SAndreas Jaekel printf(" ZVOL write : %lu\n", zs.zev_cnt_zvol_write); 67a18c35b9SAndreas Jaekel printf(" ZVOL truncate : %lu\n", zs.zev_cnt_zvol_truncate); 68a18c35b9SAndreas Jaekel printf(" ZNODE close after update: %lu\n", 69a18c35b9SAndreas Jaekel zs.zev_cnt_znode_close_after_update); 70a18c35b9SAndreas Jaekel printf(" ZNODE create : %lu\n", zs.zev_cnt_znode_create); 71a18c35b9SAndreas Jaekel printf(" ZNODE remove : %lu\n", zs.zev_cnt_znode_remove); 72a18c35b9SAndreas Jaekel printf(" ZNODE link : %lu\n", zs.zev_cnt_znode_link); 73a18c35b9SAndreas Jaekel printf(" ZNODE symlink : %lu\n", zs.zev_cnt_znode_symlink); 74a18c35b9SAndreas Jaekel printf(" ZNODE rename : %lu\n", zs.zev_cnt_znode_rename); 75a18c35b9SAndreas Jaekel printf(" ZNODE write : %lu\n", zs.zev_cnt_znode_write); 76a18c35b9SAndreas Jaekel printf(" ZNODE truncate : %lu\n", 77a18c35b9SAndreas Jaekel zs.zev_cnt_znode_truncate); 78a18c35b9SAndreas Jaekel printf(" ZNODE setattr : %lu\n", zs.zev_cnt_znode_setattr); 79a18c35b9SAndreas Jaekel printf(" ZNODE acl : %lu\n", zs.zev_cnt_znode_acl); 80a18c35b9SAndreas Jaekel } 81a18c35b9SAndreas Jaekel 82a18c35b9SAndreas Jaekel static void 83*aafc540fSAndreas Jaekel zev_print_event(char *buf, int len) 84*aafc540fSAndreas Jaekel { 85*aafc540fSAndreas Jaekel nvlist_t *nvl; 86*aafc540fSAndreas Jaekel nvpair_t *curr, *next; 87*aafc540fSAndreas Jaekel int err; 88*aafc540fSAndreas Jaekel char *key; 89*aafc540fSAndreas Jaekel data_type_t type; 90*aafc540fSAndreas Jaekel uchar_t op; 91*aafc540fSAndreas Jaekel uint64_t op_time; 92*aafc540fSAndreas Jaekel char *when; 93*aafc540fSAndreas Jaekel time_t ot; 94*aafc540fSAndreas Jaekel boolean_t val_bool; 95*aafc540fSAndreas Jaekel uint64_t val_uint64; 96*aafc540fSAndreas Jaekel char *val_string; 97*aafc540fSAndreas Jaekel uchar_t val_byte; 98*aafc540fSAndreas Jaekel int32_t val_int32; 99*aafc540fSAndreas Jaekel 100*aafc540fSAndreas Jaekel if (0 != nvlist_unpack(buf, len, &nvl, NV_ENCODE_NATIVE)) { 101*aafc540fSAndreas Jaekel fprintf(stderr, "zev event garbled: can't unpack nvlist\n"); 102*aafc540fSAndreas Jaekel exit(1); 103*aafc540fSAndreas Jaekel } 104*aafc540fSAndreas Jaekel 105*aafc540fSAndreas Jaekel if (0 != nvlist_lookup_byte(nvl, "op", &op)) { 106*aafc540fSAndreas Jaekel fprintf(stderr, "zev event garbled: no op specified\n"); 107*aafc540fSAndreas Jaekel exit(1); 108*aafc540fSAndreas Jaekel } 109*aafc540fSAndreas Jaekel if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) { 110*aafc540fSAndreas Jaekel fprintf(stderr, "zev event garbled: op %d is outside range\n", 111*aafc540fSAndreas Jaekel op); 112*aafc540fSAndreas Jaekel exit(1); 113*aafc540fSAndreas Jaekel } 114*aafc540fSAndreas Jaekel if (0 != nvlist_lookup_uint64(nvl, "op_time", &op_time)) { 115*aafc540fSAndreas Jaekel fprintf(stderr, "zev event garbled: no op_time specified\n"); 116*aafc540fSAndreas Jaekel exit(1); 117*aafc540fSAndreas Jaekel } 118*aafc540fSAndreas Jaekel ot = op_time; 119*aafc540fSAndreas Jaekel when = ctime(&ot); 120*aafc540fSAndreas Jaekel when[24] = '\0'; 121*aafc540fSAndreas Jaekel printf("%s %s", when, zev_op_name[op - ZEV_OP_MIN]); 122*aafc540fSAndreas Jaekel 123*aafc540fSAndreas Jaekel curr = nvlist_next_nvpair(nvl, NULL); 124*aafc540fSAndreas Jaekel while (curr != NULL) { 125*aafc540fSAndreas Jaekel nvpair_t *next = nvlist_next_nvpair(nvl, curr); 126*aafc540fSAndreas Jaekel key = nvpair_name(curr); 127*aafc540fSAndreas Jaekel if (!strcmp(key, "op")) 128*aafc540fSAndreas Jaekel goto skip; 129*aafc540fSAndreas Jaekel if (!strcmp(key, "op_time")) 130*aafc540fSAndreas Jaekel goto skip; 131*aafc540fSAndreas Jaekel type = nvpair_type(curr); 132*aafc540fSAndreas Jaekel switch (type) { 133*aafc540fSAndreas Jaekel case DATA_TYPE_BOOLEAN_VALUE: 134*aafc540fSAndreas Jaekel nvlist_lookup_boolean_value(nvl, key, &val_bool); 135*aafc540fSAndreas Jaekel printf(" %s=%s", key, (val_bool ? "true" : "false")); 136*aafc540fSAndreas Jaekel break; 137*aafc540fSAndreas Jaekel case DATA_TYPE_BYTE: 138*aafc540fSAndreas Jaekel nvlist_lookup_byte(nvl, key, &val_byte); 139*aafc540fSAndreas Jaekel printf(" %s=%d", key, val_byte); 140*aafc540fSAndreas Jaekel break; 141*aafc540fSAndreas Jaekel case DATA_TYPE_UINT64: 142*aafc540fSAndreas Jaekel nvlist_lookup_uint64(nvl, key, &val_uint64); 143*aafc540fSAndreas Jaekel printf(" %s=%llu", key, val_uint64); 144*aafc540fSAndreas Jaekel break; 145*aafc540fSAndreas Jaekel case DATA_TYPE_INT32: 146*aafc540fSAndreas Jaekel nvlist_lookup_int32(nvl, key, &val_int32); 147*aafc540fSAndreas Jaekel printf(" %s=%d", key, val_int32); 148*aafc540fSAndreas Jaekel break; 149*aafc540fSAndreas Jaekel case DATA_TYPE_STRING: 150*aafc540fSAndreas Jaekel nvlist_lookup_string(nvl, key, &val_string); 151*aafc540fSAndreas Jaekel printf(" %s=%s", key, val_string); 152*aafc540fSAndreas Jaekel break; 153*aafc540fSAndreas Jaekel default: 154*aafc540fSAndreas Jaekel fprintf(stderr, "unexpected nvlist data type: %d\n", 155*aafc540fSAndreas Jaekel type); 156*aafc540fSAndreas Jaekel exit(1); 157*aafc540fSAndreas Jaekel } 158*aafc540fSAndreas Jaekel skip: 159*aafc540fSAndreas Jaekel curr = next; 160*aafc540fSAndreas Jaekel } 161*aafc540fSAndreas Jaekel printf("\n"); 162*aafc540fSAndreas Jaekel } 163*aafc540fSAndreas Jaekel 164*aafc540fSAndreas Jaekel static void 165a18c35b9SAndreas Jaekel zev_poll_events(int fd) 166a18c35b9SAndreas Jaekel { 167a18c35b9SAndreas Jaekel struct pollfd pfd[1]; 168a18c35b9SAndreas Jaekel int ret; 169*aafc540fSAndreas Jaekel char buf[4096]; 170a18c35b9SAndreas Jaekel while (1) { 171a18c35b9SAndreas Jaekel pfd[0].fd = fd; 172a18c35b9SAndreas Jaekel pfd[0].events = POLLIN; 173a18c35b9SAndreas Jaekel ret = poll(pfd, 1, 1000); 174a18c35b9SAndreas Jaekel if (ret < 0) { 175a18c35b9SAndreas Jaekel perror("poll failed"); 176a18c35b9SAndreas Jaekel exit(EXIT_FAILURE); 177a18c35b9SAndreas Jaekel } 178a18c35b9SAndreas Jaekel if (!(pfd[0].revents & POLLIN)) 179a18c35b9SAndreas Jaekel continue; 180a18c35b9SAndreas Jaekel /* data available */ 181a18c35b9SAndreas Jaekel ret = read(fd, buf, sizeof(buf)); 182a18c35b9SAndreas Jaekel if (ret < 0) { 183a18c35b9SAndreas Jaekel perror("read failed"); 184a18c35b9SAndreas Jaekel exit(EXIT_FAILURE); 185a18c35b9SAndreas Jaekel } 186a18c35b9SAndreas Jaekel if (ret == 0) 187a18c35b9SAndreas Jaekel continue; 188*aafc540fSAndreas Jaekel zev_print_event(buf, ret); 189a18c35b9SAndreas Jaekel } 190a18c35b9SAndreas Jaekel return; 191a18c35b9SAndreas Jaekel } 192a18c35b9SAndreas Jaekel 193a18c35b9SAndreas Jaekel static void 194a18c35b9SAndreas Jaekel usage(char *progname) 195a18c35b9SAndreas Jaekel { 196a18c35b9SAndreas Jaekel fprintf(stderr, "usage: %s [-s] [-d <dev>]\n", progname); 197a18c35b9SAndreas Jaekel fprintf(stderr, " -s show zev statistics\n"); 198a18c35b9SAndreas Jaekel fprintf(stderr, " -p poll for ZFS events\n"); 199a18c35b9SAndreas Jaekel fprintf(stderr, " -q <bytes> set maximum event queue length\n"); 200fec460f8SAndreas Jaekel fprintf(stderr, " -t <bytes> set queue length poll throttle\n"); 201a18c35b9SAndreas Jaekel fprintf(stderr, " -m <pool> mute pool, no events for this pool\n"); 202a18c35b9SAndreas Jaekel fprintf(stderr, " -M <pool> unmute pool\n"); 203a18c35b9SAndreas Jaekel fprintf(stderr, " -d <dev> device file to use. default is '%s'\n", 204a18c35b9SAndreas Jaekel ZEV_DEVICE); 205a18c35b9SAndreas Jaekel exit (EXIT_FAILURE); 206a18c35b9SAndreas Jaekel } 207a18c35b9SAndreas Jaekel 208a18c35b9SAndreas Jaekel static int 209a18c35b9SAndreas Jaekel zev_set_max_queue_len(int fd, char *optarg) 210a18c35b9SAndreas Jaekel { 211a18c35b9SAndreas Jaekel uint64_t maxqueuelen; 212a18c35b9SAndreas Jaekel 213a18c35b9SAndreas Jaekel errno = 0; 214a18c35b9SAndreas Jaekel maxqueuelen = strtol(optarg, (char **)NULL, 10); 215a18c35b9SAndreas Jaekel if (errno) { 216a18c35b9SAndreas Jaekel fprintf(stderr, "invalid queue length parameter: %s\n", optarg); 217a18c35b9SAndreas Jaekel return (EXIT_FAILURE); 218a18c35b9SAndreas Jaekel } 219a18c35b9SAndreas Jaekel if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) { 220a18c35b9SAndreas Jaekel perror("setting max queue length failed"); 221a18c35b9SAndreas Jaekel return (EXIT_FAILURE); 222a18c35b9SAndreas Jaekel } 223a18c35b9SAndreas Jaekel return (0); 224a18c35b9SAndreas Jaekel } 225a18c35b9SAndreas Jaekel 226a18c35b9SAndreas Jaekel static int 227fec460f8SAndreas Jaekel zev_set_poll_wakeup_queue_len(int fd, char *optarg) 228fec460f8SAndreas Jaekel { 229fec460f8SAndreas Jaekel uint64_t queuelen; 230fec460f8SAndreas Jaekel 231fec460f8SAndreas Jaekel errno = 0; 232fec460f8SAndreas Jaekel queuelen = strtol(optarg, (char **)NULL, 10); 233fec460f8SAndreas Jaekel if (errno) { 234fec460f8SAndreas Jaekel fprintf(stderr, "invalid queue length parameter: %s\n", optarg); 235fec460f8SAndreas Jaekel return (EXIT_FAILURE); 236fec460f8SAndreas Jaekel } 237fec460f8SAndreas Jaekel if (ioctl(fd, ZEV_IOC_SET_POLL_WAKEUP_QUEUE_LEN, &queuelen)) { 238fec460f8SAndreas Jaekel perror("setting poll wakeup queue length failed"); 239fec460f8SAndreas Jaekel return (EXIT_FAILURE); 240fec460f8SAndreas Jaekel } 241fec460f8SAndreas Jaekel return (0); 242fec460f8SAndreas Jaekel } 243fec460f8SAndreas Jaekel 244fec460f8SAndreas Jaekel static int 245a18c35b9SAndreas Jaekel zev_mute_unmute_impl(int fd, char *poolname, int mute) 246a18c35b9SAndreas Jaekel { 247a18c35b9SAndreas Jaekel zev_ioctl_poolarg_t pa; 248a18c35b9SAndreas Jaekel int len; 249a18c35b9SAndreas Jaekel int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL; 250a18c35b9SAndreas Jaekel len = strlen(poolname); 251a18c35b9SAndreas Jaekel if (len <= 0 || len >= sizeof(pa.zev_poolname)) { 252a18c35b9SAndreas Jaekel fprintf(stderr, "invalid poolname: %s\n", poolname); 253a18c35b9SAndreas Jaekel return (EXIT_FAILURE); 254a18c35b9SAndreas Jaekel } 255a18c35b9SAndreas Jaekel strcpy(pa.zev_poolname, poolname); 256a18c35b9SAndreas Jaekel pa.zev_poolname_len = len; 257a18c35b9SAndreas Jaekel if (ioctl(fd, op, &pa)) { 258a18c35b9SAndreas Jaekel perror("muting pool data failed"); 259a18c35b9SAndreas Jaekel return (EXIT_FAILURE); 260a18c35b9SAndreas Jaekel } 261a18c35b9SAndreas Jaekel return (0); 262a18c35b9SAndreas Jaekel } 263a18c35b9SAndreas Jaekel 264a18c35b9SAndreas Jaekel int 265a18c35b9SAndreas Jaekel zev_mute_pool(int fd, char *poolname) 266a18c35b9SAndreas Jaekel { 267a18c35b9SAndreas Jaekel return zev_mute_unmute_impl(fd, poolname, 1); 268a18c35b9SAndreas Jaekel } 269a18c35b9SAndreas Jaekel 270a18c35b9SAndreas Jaekel int 271a18c35b9SAndreas Jaekel zev_unmute_pool(int fd, char *poolname) 272a18c35b9SAndreas Jaekel { 273a18c35b9SAndreas Jaekel return zev_mute_unmute_impl(fd, poolname, 0); 274a18c35b9SAndreas Jaekel } 275a18c35b9SAndreas Jaekel 276a18c35b9SAndreas Jaekel int 277a18c35b9SAndreas Jaekel main(int argc, char **argv) 278a18c35b9SAndreas Jaekel { 279a18c35b9SAndreas Jaekel int fd; 280a18c35b9SAndreas Jaekel int c; 281a18c35b9SAndreas Jaekel int ops = 0; 282a18c35b9SAndreas Jaekel extern char *optarg; 283a18c35b9SAndreas Jaekel 284a18c35b9SAndreas Jaekel /* open device */ 285a18c35b9SAndreas Jaekel fd = open(zev_device, O_RDONLY); 286a18c35b9SAndreas Jaekel if (fd < 0) { 287a18c35b9SAndreas Jaekel perror("opening zev device failed"); 288a18c35b9SAndreas Jaekel return EXIT_FAILURE; 289a18c35b9SAndreas Jaekel } 290fec460f8SAndreas Jaekel while ((c = getopt(argc, argv, "spdq:t:m:M:h?")) != -1) { 291a18c35b9SAndreas Jaekel switch(c) { 292a18c35b9SAndreas Jaekel case 's': 293a18c35b9SAndreas Jaekel ops |= OP_STATISTICS; 294a18c35b9SAndreas Jaekel break; 295a18c35b9SAndreas Jaekel case 'p': 296a18c35b9SAndreas Jaekel ops |= OP_POLL_EVENTS; 297a18c35b9SAndreas Jaekel break; 298a18c35b9SAndreas Jaekel case 'd': 299a18c35b9SAndreas Jaekel zev_device = optarg; 300a18c35b9SAndreas Jaekel break; 301a18c35b9SAndreas Jaekel case 'q': 302a18c35b9SAndreas Jaekel return zev_set_max_queue_len(fd, optarg); 303fec460f8SAndreas Jaekel case 't': 304fec460f8SAndreas Jaekel return zev_set_poll_wakeup_queue_len(fd, optarg); 305a18c35b9SAndreas Jaekel case 'm': 306a18c35b9SAndreas Jaekel return zev_mute_pool(fd, optarg); 307a18c35b9SAndreas Jaekel case 'M': 308a18c35b9SAndreas Jaekel return zev_unmute_pool(fd, optarg); 309a18c35b9SAndreas Jaekel case 'h': 310a18c35b9SAndreas Jaekel case '?': 311a18c35b9SAndreas Jaekel default: 312a18c35b9SAndreas Jaekel usage(argv[0]); 313a18c35b9SAndreas Jaekel } 314a18c35b9SAndreas Jaekel } 315a18c35b9SAndreas Jaekel if (!ops) 316a18c35b9SAndreas Jaekel usage(argv[0]); 317a18c35b9SAndreas Jaekel if (ops & OP_STATISTICS) 318a18c35b9SAndreas Jaekel zev_statistics(fd); 319a18c35b9SAndreas Jaekel if (ops & OP_POLL_EVENTS) 320a18c35b9SAndreas Jaekel zev_poll_events(fd); 321a18c35b9SAndreas Jaekel close(fd); 322a18c35b9SAndreas Jaekel return EXIT_SUCCESS; 323a18c35b9SAndreas Jaekel } 324a18c35b9SAndreas Jaekel 325