1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <fcntl.h> 5 #include <stropts.h> 6 #include <poll.h> 7 #include <string.h> 8 #include <sys/fs/zev.h> 9 #include <errno.h> 10 11 #define OP_STATISTICS (1 << 0) 12 #define OP_POLL_EVENTS (1 << 1) 13 #define OP_MUTE_POOL (1 << 2) 14 #define OP_UNMUTE_POOL (1 << 3) 15 #define OP_SET_MAX_QUEUE_LEN (1 << 4) 16 17 #define ZEV_DEVICE "/devices/pseudo/zev@0:zev" 18 19 static char *zev_device = ZEV_DEVICE; 20 21 static char *zev_op_name[] = { 22 "ZEV_OP_ERROR", 23 "ZEV_OP_MARK", 24 "ZEV_OP_ZFS_MOUNT", 25 "ZEV_OP_ZFS_UMOUNT", 26 "ZEV_OP_ZVOL_WRITE", 27 "ZEV_OP_ZVOL_TRUNCATE", 28 "ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE", 29 "ZEV_OP_ZNODE_CREATE", 30 "ZEV_OP_ZNODE_MKDIR", 31 "ZEV_OP_ZNODE_MAKE_XATTR_DIR", 32 "ZEV_OP_ZNODE_REMOVE", 33 "ZEV_OP_ZNODE_RMDIR", 34 "ZEV_OP_ZNODE_LINK", 35 "ZEV_OP_ZNODE_SYMLINK", 36 "ZEV_OP_ZNODE_RENAME", 37 "ZEV_OP_ZNODE_WRITE", 38 "ZEV_OP_ZNODE_TRUNCATE", 39 "ZEV_OP_ZNODE_SETATTR", 40 "ZEV_OP_ZNODE_ACL", 41 NULL 42 }; 43 44 static void 45 zev_statistics(int fd) 46 { 47 zev_statistics_t zs; 48 if (ioctl(fd, ZEV_IOC_GET_STATISTICS, &zs)) { 49 perror("getting statistics data failed"); 50 exit (EXIT_FAILURE); 51 } 52 printf("ZEV module state:\n"); 53 54 printf(" queue length in bytes : %lu\n", zs.zev_queue_len); 55 printf(" queue length limit : %lu\n", zs.zev_max_queue_len); 56 printf(" poll wakeup throttle : %lu\n\n", 57 zs.zev_poll_wakeup_queue_len); 58 printf(" bytes read from device : %lu\n", zs.zev_bytes_read); 59 printf(" module internal errors : %lu\n\n", zs.zev_cnt_errors); 60 61 printf("ZFS event statistics:\n"); 62 63 printf(" total ZFS events : %lu\n", zs.zev_cnt_total_events); 64 printf(" ZFS mount : %lu\n", zs.zev_cnt_zfs_mount); 65 printf(" ZFS umount : %lu\n", zs.zev_cnt_zfs_umount); 66 printf(" ZVOL write : %lu\n", zs.zev_cnt_zvol_write); 67 printf(" ZVOL truncate : %lu\n", zs.zev_cnt_zvol_truncate); 68 printf(" ZNODE close after update: %lu\n", 69 zs.zev_cnt_znode_close_after_update); 70 printf(" ZNODE create : %lu\n", zs.zev_cnt_znode_create); 71 printf(" ZNODE remove : %lu\n", zs.zev_cnt_znode_remove); 72 printf(" ZNODE link : %lu\n", zs.zev_cnt_znode_link); 73 printf(" ZNODE symlink : %lu\n", zs.zev_cnt_znode_symlink); 74 printf(" ZNODE rename : %lu\n", zs.zev_cnt_znode_rename); 75 printf(" ZNODE write : %lu\n", zs.zev_cnt_znode_write); 76 printf(" ZNODE truncate : %lu\n", 77 zs.zev_cnt_znode_truncate); 78 printf(" ZNODE setattr : %lu\n", zs.zev_cnt_znode_setattr); 79 printf(" ZNODE acl : %lu\n", zs.zev_cnt_znode_acl); 80 } 81 82 static void 83 zev_print_error(char *buf) 84 { 85 zev_error_t *rec = (zev_error_t *)buf; 86 time_t op_time = rec->op_time; 87 char *ct = ctime(&op_time); ct[24] = '\0'; 88 89 printf("%s %s: failed_op=%s msg=%s\n", 90 ct, zev_op_name[rec->op - ZEV_OP_MIN], 91 zev_op_name[rec->failed_op - ZEV_OP_MIN], ZEV_ERRSTR(rec)); 92 } 93 94 static void 95 zev_print_mark(char *buf) 96 { 97 zev_mark_t *rec = (zev_mark_t *)buf; 98 time_t op_time = rec->op_time; 99 char *ct = ctime(&op_time); ct[24] = '\0'; 100 101 printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n", 102 ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->mark_id, 103 rec->payload_len); 104 } 105 106 static void 107 zev_print_zfs_mount(char *buf) 108 { 109 zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf; 110 time_t op_time = rec->op_time; 111 char *ct = ctime(&op_time); ct[24] = '\0'; 112 113 printf("%s %s: guid=%llu remount=%s dataset='%s' mountpoint='%s'\n", 114 ct, zev_op_name[rec->op - ZEV_OP_MIN], 115 rec->guid, 116 rec->remount ? "true" : "false", 117 ZEV_DATASET(rec), 118 ZEV_MOUNTPOINT(rec)); 119 } 120 121 static void 122 zev_print_zfs_umount(char *buf) 123 { 124 zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf; 125 time_t op_time = rec->op_time; 126 char *ct = ctime(&op_time); ct[24] = '\0'; 127 128 printf("%s %s: guid=%llu\n", 129 ct, zev_op_name[rec->op - ZEV_OP_MIN], 130 rec->guid); 131 } 132 133 static void 134 zev_print_zvol_truncate(char *buf) 135 { 136 zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf; 137 time_t op_time = rec->op_time; 138 char *ct = ctime(&op_time); ct[24] = '\0'; 139 140 printf("%s %s: guid=%llu offset=%llu length=%llu\n", 141 ct, zev_op_name[rec->op - ZEV_OP_MIN], 142 rec->guid, 143 rec->offset, 144 rec->length); 145 } 146 147 static void 148 zev_print_zvol_write(char *buf) 149 { 150 zev_print_zvol_truncate(buf); 151 } 152 153 static void 154 zev_print_znode_close_after_update(char *buf) 155 { 156 zev_znode_close_after_update_t *rec = 157 (zev_znode_close_after_update_t *)buf; 158 time_t op_time = rec->op_time; 159 char *ct = ctime(&op_time); ct[24] = '\0'; 160 161 printf("%s %s: guid=%llu file=%llu.%llu\n", 162 ct, zev_op_name[rec->op - ZEV_OP_MIN], 163 rec->guid, 164 rec->file.ino, rec->file.gen); 165 } 166 167 static void 168 zev_print_znode_create(char *buf) 169 { 170 zev_znode_create_t *rec = (zev_znode_create_t *)buf; 171 time_t op_time = rec->op_time; 172 char *ct = ctime(&op_time); ct[24] = '\0'; 173 174 printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu " 175 "file.mtime=%llu, parent.mtime=%llu, name='%s'\n", 176 ct, zev_op_name[rec->op - ZEV_OP_MIN], 177 rec->guid, 178 rec->parent.ino, rec->parent.gen, 179 rec->file.ino, rec->file.gen, 180 rec->file.mtime, rec->parent.mtime, 181 ZEV_NAME(rec)); 182 } 183 184 static void 185 zev_print_znode_mkdir(char *buf) 186 { 187 zev_print_znode_create(buf); 188 } 189 190 static void 191 zev_print_znode_make_xattr_dir(char *buf) 192 { 193 zev_print_znode_create(buf); 194 } 195 196 static void 197 zev_print_znode_remove(char *buf) 198 { 199 zev_znode_remove_t *rec = (zev_znode_remove_t *)buf; 200 time_t op_time = rec->op_time; 201 char *ct = ctime(&op_time); ct[24] = '\0'; 202 203 printf("%s %s: guid=%llu parent=%llu.%llu file.mtime=%llu name='%s'\n", 204 ct, zev_op_name[rec->op - ZEV_OP_MIN], 205 rec->guid, 206 rec->parent.ino, rec->parent.gen, 207 rec->file.mtime, 208 ZEV_NAME(rec)); 209 } 210 211 static void 212 zev_print_znode_rmdir(char *buf) 213 { 214 zev_print_znode_remove(buf); 215 } 216 217 static void 218 zev_print_znode_link(char *buf) 219 { 220 zev_znode_link_t *rec = (zev_znode_link_t *)buf; 221 time_t op_time = rec->op_time; 222 char *ct = ctime(&op_time); ct[24] = '\0'; 223 224 printf("%s %s: parent=%llu.%llu file=%llu.%llu " 225 "file.ctime=%llu parent.ctime=%llu name='%s'\n", 226 ct, zev_op_name[rec->op - ZEV_OP_MIN], 227 rec->parent.ino, rec->parent.gen, 228 rec->file.ino, rec->file.gen, 229 rec->file.ctime, rec->parent.ctime, 230 ZEV_NAME(rec)); 231 printf("links: %d\n", rec->file.links); 232 } 233 234 static void 235 zev_print_znode_symlink(char *buf) 236 { 237 zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf; 238 time_t op_time = rec->op_time; 239 char *ct = ctime(&op_time); ct[24] = '\0'; 240 241 printf("%s %s: parent=%llu.%llu file=%llu.%llu name='%s' link='%s'\n", 242 ct, zev_op_name[rec->op - ZEV_OP_MIN], 243 rec->parent.ino, rec->parent.gen, 244 rec->file.ino, rec->file.gen, 245 ZEV_NAME(rec), 246 ZEV_LINK(rec)); 247 } 248 249 static void 250 zev_print_znode_rename(char *buf) 251 { 252 zev_znode_rename_t *rec = (zev_znode_rename_t *)buf; 253 time_t op_time = rec->op_time; 254 char *ct = ctime(&op_time); ct[24] = '\0'; 255 256 printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu file=%llu.%llu " 257 "file.mtime=%llu, file.ctime=%llu, srcdir.mtime=%llu, " 258 "srcdir.ctime=%llu, dstdir.mtime=%llu, dstdir.ctime=%llu, " 259 "srcname='%s' dstname='%s'\n", 260 ct, zev_op_name[rec->op - ZEV_OP_MIN], 261 rec->srcdir.ino, rec->srcdir.gen, 262 rec->dstdir.ino, rec->dstdir.gen, 263 rec->file.ino, rec->file.gen, 264 rec->file.mtime, rec->file.ctime, 265 rec->srcdir.mtime, rec->srcdir.ctime, 266 rec->dstdir.mtime, rec->dstdir.ctime, 267 ZEV_SRCNAME(rec), 268 ZEV_DSTNAME(rec)); 269 } 270 271 static void 272 zev_print_znode_write(char *buf) 273 { 274 zev_znode_write_t *rec = (zev_znode_write_t *)buf; 275 time_t op_time = rec->op_time; 276 char *ct = ctime(&op_time); ct[24] = '\0'; 277 278 printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n", 279 ct, zev_op_name[rec->op - ZEV_OP_MIN], 280 rec->file.ino, rec->file.gen, 281 rec->offset, rec->length); 282 } 283 284 static void 285 zev_print_znode_truncate(char *buf) 286 { 287 zev_print_znode_write(buf); 288 } 289 290 static void 291 zev_print_znode_setattr(char *buf) 292 { 293 zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf; 294 time_t op_time = rec->op_time; 295 char *ct = ctime(&op_time); ct[24] = '\0'; 296 297 printf("%s %s: file=%llu.%llu mtime=%llu\n", 298 ct, zev_op_name[rec->op - ZEV_OP_MIN], 299 rec->file.ino, rec->file.gen, rec->file.mtime); 300 } 301 302 static void 303 zev_print_znode_acl(char *buf) 304 { 305 zev_print_znode_setattr(buf); 306 } 307 308 static void 309 zev_print_event(char *buf, int len) 310 { 311 int record_len; 312 int op; 313 314 record_len = *(uint32_t *)buf; 315 if (record_len != len) { 316 fprintf(stderr, "record length mismatch: got %d, expected %d\n", 317 record_len, len); 318 exit(1); 319 } 320 op = *((uint32_t *)buf + 1); 321 if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) { 322 fprintf(stderr, "unknown op code: %d\n", op); 323 exit(1); 324 } 325 switch (op) { 326 case ZEV_OP_ERROR: 327 zev_print_error(buf); 328 break; 329 case ZEV_OP_MARK: 330 zev_print_mark(buf); 331 break; 332 case ZEV_OP_ZFS_MOUNT: 333 zev_print_zfs_mount(buf); 334 break; 335 case ZEV_OP_ZFS_UMOUNT: 336 zev_print_zfs_umount(buf); 337 break; 338 case ZEV_OP_ZVOL_TRUNCATE: 339 zev_print_zvol_truncate(buf); 340 break; 341 case ZEV_OP_ZVOL_WRITE: 342 zev_print_zvol_write(buf); 343 break; 344 case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE: 345 zev_print_znode_close_after_update(buf); 346 break; 347 case ZEV_OP_ZNODE_CREATE: 348 zev_print_znode_create(buf); 349 break; 350 case ZEV_OP_ZNODE_MKDIR: 351 zev_print_znode_mkdir(buf); 352 break; 353 case ZEV_OP_ZNODE_MAKE_XATTR_DIR: 354 zev_print_znode_make_xattr_dir(buf); 355 break; 356 case ZEV_OP_ZNODE_REMOVE: 357 zev_print_znode_remove(buf); 358 break; 359 case ZEV_OP_ZNODE_RMDIR: 360 zev_print_znode_rmdir(buf); 361 break; 362 case ZEV_OP_ZNODE_LINK: 363 zev_print_znode_link(buf); 364 break; 365 case ZEV_OP_ZNODE_SYMLINK: 366 zev_print_znode_symlink(buf); 367 break; 368 case ZEV_OP_ZNODE_RENAME: 369 zev_print_znode_rename(buf); 370 break; 371 case ZEV_OP_ZNODE_WRITE: 372 zev_print_znode_write(buf); 373 break; 374 case ZEV_OP_ZNODE_TRUNCATE: 375 zev_print_znode_truncate(buf); 376 break; 377 case ZEV_OP_ZNODE_SETATTR: 378 zev_print_znode_setattr(buf); 379 break; 380 case ZEV_OP_ZNODE_ACL: 381 zev_print_znode_acl(buf); 382 break; 383 default: 384 fprintf(stderr, "unhandled op code: %d\n", op); 385 exit(1); 386 } 387 } 388 389 static void 390 zev_poll_events(int fd) 391 { 392 struct pollfd pfd[1]; 393 int ret; 394 char buf[4096]; 395 zev_event_t *ev; 396 int off = 0; 397 while (1) { 398 pfd[0].fd = fd; 399 pfd[0].events = POLLIN; 400 ret = poll(pfd, 1, 1000); 401 if (ret < 0) { 402 perror("poll failed"); 403 exit(EXIT_FAILURE); 404 } 405 if (!(pfd[0].revents & POLLIN)) 406 continue; 407 /* data available */ 408 ret = read(fd, buf, sizeof(buf)); 409 if (ret < 0) { 410 perror("read failed"); 411 exit(EXIT_FAILURE); 412 } 413 if (ret == 0) 414 continue; 415 while (ret > off) { 416 ev = (zev_event_t *)(buf + off); 417 zev_print_event(buf + off, ev->header.record_len); 418 off += ev->header.record_len; 419 } 420 off = 0; 421 } 422 return; 423 } 424 425 static void 426 usage(char *progname) 427 { 428 fprintf(stderr, "usage: %s [-s] [-d <dev>]\n", progname); 429 fprintf(stderr, " -s show zev statistics\n"); 430 fprintf(stderr, " -p poll for ZFS events\n"); 431 fprintf(stderr, " -q <bytes> set maximum event queue length\n"); 432 fprintf(stderr, " -t <bytes> set queue length poll throttle\n"); 433 fprintf(stderr, " -m <pool> mute pool, no events for this pool\n"); 434 fprintf(stderr, " -M <pool> unmute pool\n"); 435 fprintf(stderr, " -d <dev> device file to use. default is '%s'\n", 436 ZEV_DEVICE); 437 fprintf(stderr, " -k <guid>:<payload> queue mark event\n"); 438 exit (EXIT_FAILURE); 439 } 440 441 static int 442 zev_set_max_queue_len(int fd, char *optarg) 443 { 444 uint64_t maxqueuelen; 445 446 errno = 0; 447 maxqueuelen = strtol(optarg, (char **)NULL, 10); 448 if (errno) { 449 fprintf(stderr, "invalid queue length parameter: %s\n", optarg); 450 return (EXIT_FAILURE); 451 } 452 if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) { 453 perror("setting max queue length failed"); 454 return (EXIT_FAILURE); 455 } 456 return (0); 457 } 458 459 static int 460 zev_set_poll_wakeup_queue_len(int fd, char *optarg) 461 { 462 uint64_t queuelen; 463 464 errno = 0; 465 queuelen = strtol(optarg, (char **)NULL, 10); 466 if (errno) { 467 fprintf(stderr, "invalid queue length parameter: %s\n", optarg); 468 return (EXIT_FAILURE); 469 } 470 if (ioctl(fd, ZEV_IOC_SET_POLL_WAKEUP_QUEUE_LEN, &queuelen)) { 471 perror("setting poll wakeup queue length failed"); 472 return (EXIT_FAILURE); 473 } 474 return (0); 475 } 476 477 static int 478 zev_mute_unmute_impl(int fd, char *poolname, int mute) 479 { 480 zev_ioctl_poolarg_t pa; 481 int len; 482 int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL; 483 len = strlen(poolname); 484 if (len <= 0 || len >= sizeof(pa.zev_poolname)) { 485 fprintf(stderr, "invalid poolname: %s\n", poolname); 486 return (EXIT_FAILURE); 487 } 488 strcpy(pa.zev_poolname, poolname); 489 pa.zev_poolname_len = len; 490 if (ioctl(fd, op, &pa)) { 491 perror("muting pool data failed"); 492 return (EXIT_FAILURE); 493 } 494 return (0); 495 } 496 497 int 498 zev_mute_pool(int fd, char *poolname) 499 { 500 return zev_mute_unmute_impl(fd, poolname, 1); 501 } 502 503 int 504 zev_unmute_pool(int fd, char *poolname) 505 { 506 return zev_mute_unmute_impl(fd, poolname, 0); 507 } 508 509 static int 510 zev_mark(int fd, char *arg) 511 { 512 zev_ioctl_mark_t *mark; 513 uint64_t guid; 514 int len; 515 char *p; 516 517 p = strchr(arg, ':'); 518 if (!p) { 519 fprintf(stderr, "expected value is <guid>:<payload>, " 520 "e.g. '123:hello'\n"); 521 exit (EXIT_FAILURE); 522 } 523 *p = '\n'; 524 p++; 525 526 errno = 0; 527 guid = strtoll(optarg, (char **)NULL, 10); 528 if (errno) { 529 fprintf(stderr, "guid must be a number.\n"); 530 exit (EXIT_FAILURE); 531 } 532 533 len = strlen(p); 534 535 mark = malloc(sizeof(*mark) + len + 1); 536 if (!mark) { 537 fprintf(stderr, "can't allocate mark structure: %s\n", 538 strerror(errno)); 539 exit (EXIT_FAILURE); 540 } 541 mark->zev_guid = guid; 542 mark->zev_mark_id = 0; 543 mark->zev_payload_len = len; 544 strcpy(ZEV_PAYLOAD(mark), p); 545 546 if (ioctl(fd, ZEV_IOC_MARK, mark)) { 547 perror("queueing mark failed"); 548 return (EXIT_FAILURE); 549 } 550 551 printf("mark id: %lu\n", mark->zev_mark_id); 552 return (0); 553 } 554 555 int 556 main(int argc, char **argv) 557 { 558 int fd; 559 int c; 560 int ops = 0; 561 extern char *optarg; 562 563 /* open device */ 564 fd = open(zev_device, O_RDONLY); 565 if (fd < 0) { 566 perror("opening zev device failed"); 567 return EXIT_FAILURE; 568 } 569 while ((c = getopt(argc, argv, "spdk:q:t:m:M:h?")) != -1) { 570 switch(c) { 571 case 's': 572 ops |= OP_STATISTICS; 573 break; 574 case 'p': 575 ops |= OP_POLL_EVENTS; 576 break; 577 case 'd': 578 zev_device = optarg; 579 break; 580 case 'q': 581 return zev_set_max_queue_len(fd, optarg); 582 case 't': 583 return zev_set_poll_wakeup_queue_len(fd, optarg); 584 case 'm': 585 return zev_mute_pool(fd, optarg); 586 case 'M': 587 return zev_unmute_pool(fd, optarg); 588 case 'k': 589 return zev_mark(fd, optarg); 590 case 'h': 591 case '?': 592 default: 593 usage(argv[0]); 594 } 595 } 596 if (!ops) 597 usage(argv[0]); 598 if (ops & OP_STATISTICS) 599 zev_statistics(fd); 600 if (ops & OP_POLL_EVENTS) 601 zev_poll_events(fd); 602 close(fd); 603 return EXIT_SUCCESS; 604 } 605 606