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 #include <sys/sysmacros.h> 11 #include <stdarg.h> 12 #include <sys/avl.h> 13 #include <sys/stat.h> 14 15 #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl" 16 17 #if !defined(offsetof) 18 #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 19 #endif 20 21 static char *zev_device = ZEV_DEVICE; 22 static int do_flush = 0; 23 24 static char *zev_op_name[] = { 25 "ERROR", 26 "MARK", 27 "ZFS_MOUNT", 28 "ZFS_UMOUNT", 29 "ZVOL_WRITE", 30 "ZVOL_TRUNCATE", 31 "ZNODE_CLOSE_AFTER_UPDATE", 32 "ZNODE_CREATE", 33 "ZNODE_MKDIR", 34 "ZNODE_MAKE_XATTR_DIR", 35 "ZNODE_REMOVE", 36 "ZNODE_RMDIR", 37 "ZNODE_LINK", 38 "ZNODE_SYMLINK", 39 "ZNODE_RENAME", 40 "ZNODE_WRITE", 41 "ZNODE_TRUNCATE", 42 "ZNODE_SETATTR", 43 "ZNODE_ACL", 44 NULL 45 }; 46 47 #define MD_STATISTICS 1 48 #define MD_POLL_EVENTS 2 49 #define MD_CHECKSUMS 3 50 #define MD_DEBUG_INFO 4 51 #define MD_LIST_QUEUES 5 52 #define MD_SET_GLOBAL_MAX_QUEUE_LEN 6 53 #define MD_SET_MAX_QUEUE_LEN 7 54 #define MD_SET_POLL_WAKEUP_QUEUE_LEN 8 55 #define MD_MUTE_POOL 9 56 #define MD_UNMUTE_POOL 10 57 #define MD_MARK 11 58 #define MD_ADD_QUEUE 12 59 #define MD_ADD_BLOCKING_QUEUE 13 60 #define MD_REMOVE_QUEUE 14 61 #define MD_QUEUE_BLOCKING 15 62 #define MD_QUEUE_NONBLOCKING 16 63 #define MD_QUEUE_PROPERTIES 17 64 #define MD_ZEVSTAT 18 65 #define MD_ZEV_REPORT 19 66 #define MD_DUMP_SPOOL 20 67 #define MD_GET_ZEV_VERSION 21 68 69 static int verbose = 0; 70 static int grep_friendly = 0; 71 72 #define MAX_GUID 10000 73 static int num_guid_filter = 0; 74 static uint64_t guid_filter[MAX_GUID]; 75 76 static void 77 zpf(char *fmt, ...) 78 { 79 va_list ap; 80 81 va_start(ap, fmt); 82 vprintf(fmt, ap); 83 va_end(ap); 84 if (grep_friendly) { 85 printf(" "); 86 } else { 87 printf("\n"); 88 } 89 } 90 91 static void 92 znl(void) 93 { 94 if (grep_friendly) 95 printf("\n"); 96 } 97 98 static void 99 sig2hex_direct(const uint8_t *sig, char *hex) 100 { 101 int i; 102 103 for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) { 104 sprintf(hex + 2 * i, "%02x", sig[i]); 105 } 106 hex[SHA1_DIGEST_LENGTH * 2] = '\0'; 107 } 108 109 static int 110 zev_statistics(int fd) 111 { 112 zev_statistics_t zs; 113 if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) { 114 perror("getting statistics data failed"); 115 return (EXIT_FAILURE); 116 } 117 printf("ZEV module state:\n"); 118 119 printf(" queue length in bytes : %lu\n", zs.zev_queue_len); 120 printf(" queue length limit : %lu\n", zs.zev_max_queue_len); 121 printf(" bytes read from device : %lu\n", zs.zev_bytes_read); 122 printf(" module internal errors : %lu\n\n", zs.zev_cnt_errors); 123 124 printf(" discarded events : %lu\n", 125 zs.zev_cnt_discarded_events); 126 printf(" discarded bytes : %lu\n\n", zs.zev_bytes_discarded); 127 128 printf("ZFS event statistics:\n"); 129 130 printf(" total ZFS events : %lu\n", zs.zev_cnt_total_events); 131 printf(" ZFS mount : %lu\n", zs.zev_cnt_zfs_mount); 132 printf(" ZFS umount : %lu\n", zs.zev_cnt_zfs_umount); 133 printf(" ZVOL write : %lu\n", zs.zev_cnt_zvol_write); 134 printf(" ZVOL truncate : %lu\n", zs.zev_cnt_zvol_truncate); 135 printf(" ZNODE close after update: %lu\n", 136 zs.zev_cnt_znode_close_after_update); 137 printf(" ZNODE create : %lu\n", zs.zev_cnt_znode_create); 138 printf(" ZNODE remove : %lu\n", zs.zev_cnt_znode_remove); 139 printf(" ZNODE link : %lu\n", zs.zev_cnt_znode_link); 140 printf(" ZNODE symlink : %lu\n", zs.zev_cnt_znode_symlink); 141 printf(" ZNODE rename : %lu\n", zs.zev_cnt_znode_rename); 142 printf(" ZNODE write : %lu\n", zs.zev_cnt_znode_write); 143 printf(" ZNODE truncate : %lu\n", 144 zs.zev_cnt_znode_truncate); 145 printf(" ZNODE setattr : %lu\n", zs.zev_cnt_znode_setattr); 146 printf(" ZNODE acl : %lu\n", zs.zev_cnt_znode_acl); 147 return EXIT_SUCCESS; 148 } 149 150 static void 151 zev_print_inode_info(char *name, zev_inode_info_t *info) 152 { 153 zpf(" %s.inode: %llu", name, info->ino); 154 zpf(" %s.gen: %llu", name, info->gen); 155 zpf(" %s.mtime: %llu", name, info->mtime); 156 zpf(" %s.ctime: %llu", name, info->ctime); 157 zpf(" %s.size: %llu", name, info->size); 158 zpf(" %s.mode: %llo", name, info->mode); 159 zpf(" %s.links: %llu", name, info->links); 160 zpf(" %s.type: %lu", name, info->type); 161 zpf(" %s.flags: %lu", name, info->flags); 162 } 163 164 static void 165 zev_print_mark_payload(zev_mark_t *rec) 166 { 167 int i; 168 int j; 169 uint8_t *p; 170 char c; 171 172 zpf(" payload:"); 173 p = (uint8_t *)ZEV_PAYLOAD(rec); 174 for (i=0; i<rec->payload_len; i+=16) { 175 printf(" "); 176 for (j=i; j<rec->payload_len && j<i+16; j++) { 177 printf("%02x ", p[j]); 178 if (j == i + 7) 179 printf(" "); 180 } 181 if (grep_friendly) 182 continue; 183 for (; j<i+16; j++) { 184 printf(" "); 185 if (j == i + 7) 186 printf(" "); 187 } 188 printf(" "); 189 for (j=i; j<rec->payload_len && j<i+16; j++) { 190 c = '.'; 191 if (p[j] >= ' ' && p[j] <= '~') 192 c = p[j]; 193 printf("%c", c); 194 if (j == i + 7) 195 printf(" "); 196 } 197 printf("\n"); 198 } 199 } 200 201 static void 202 zev_print_error(char *buf) 203 { 204 zev_error_t *rec = (zev_error_t *)buf; 205 time_t op_time = rec->op_time; 206 char *ct = ctime(&op_time); ct[24] = '\0'; 207 208 if (verbose) { 209 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 210 zpf(" guid: %llu", rec->guid); 211 zpf(" failed.op: %s", 212 zev_op_name[rec->failed_op - ZEV_OP_MIN]); 213 zpf(" message: %s", ZEV_ERRSTR(rec)); 214 znl(); 215 } else { 216 printf("%s %s: failed_op=%s msg=%s\n", 217 ct, zev_op_name[rec->op - ZEV_OP_MIN], 218 zev_op_name[rec->failed_op - ZEV_OP_MIN], 219 ZEV_ERRSTR(rec)); 220 } 221 } 222 223 static void 224 zev_print_mark(char *buf) 225 { 226 zev_mark_t *rec = (zev_mark_t *)buf; 227 time_t op_time = rec->op_time; 228 char *ct = ctime(&op_time); ct[24] = '\0'; 229 230 if (verbose) { 231 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 232 zpf(" guid: %llu", rec->guid); 233 zpf(" mark.id: %llu", rec->mark_id); 234 zpf(" payload.len: %llu", rec->payload_len); 235 if (rec->payload_len) 236 zev_print_mark_payload(rec); 237 znl(); 238 } else { 239 printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld " 240 "payload=\"%.*s\"\n", 241 ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, 242 rec->mark_id, rec->payload_len, 243 rec->payload_len, (char *)(rec + 1)); 244 } 245 } 246 247 static void 248 zev_print_zfs_mount(char *buf) 249 { 250 zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf; 251 time_t op_time = rec->op_time; 252 char *ct = ctime(&op_time); ct[24] = '\0'; 253 254 if (verbose) { 255 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 256 zpf(" guid: %llu", rec->guid); 257 zpf(" txg: %llu", rec->txg); 258 zpf(" dataset: %s", ZEV_DATASET(rec)); 259 zpf(" mountpoint: %s", ZEV_MOUNTPOINT(rec)); 260 zpf(" remount: %s", rec->remount ? "true" : "false"); 261 zev_print_inode_info("root", &rec->root); 262 znl(); 263 } else { 264 printf("%s %s: guid=%llu remount=%s dataset='%s' " 265 "mountpoint='%s'\n", 266 ct, zev_op_name[rec->op - ZEV_OP_MIN], 267 rec->guid, 268 rec->remount ? "true" : "false", 269 ZEV_DATASET(rec), 270 ZEV_MOUNTPOINT(rec)); 271 } 272 } 273 274 static void 275 zev_print_zfs_umount(char *buf) 276 { 277 zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf; 278 time_t op_time = rec->op_time; 279 char *ct = ctime(&op_time); ct[24] = '\0'; 280 281 if (verbose) { 282 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 283 zpf(" guid: %llu", rec->guid); 284 zpf(" txg: %llu", rec->txg); 285 zev_print_inode_info("covered", &rec->covered); 286 znl(); 287 } else { 288 printf("%s %s: guid=%llu\n", 289 ct, zev_op_name[rec->op - ZEV_OP_MIN], 290 rec->guid); 291 } 292 } 293 294 static void 295 zev_print_zvol_truncate(char *buf) 296 { 297 zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf; 298 time_t op_time = rec->op_time; 299 char *ct = ctime(&op_time); ct[24] = '\0'; 300 301 if (verbose) { 302 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 303 zpf(" guid: %llu", rec->guid); 304 zpf(" txg: %llu", rec->txg); 305 zpf(" offset: %llu", rec->offset); 306 zpf(" length: %llu", rec->length); 307 znl(); 308 } else { 309 printf("%s %s: guid=%llu offset=%llu length=%llu\n", 310 ct, zev_op_name[rec->op - ZEV_OP_MIN], 311 rec->guid, 312 rec->offset, 313 rec->length); 314 } 315 } 316 317 static void 318 zev_print_zvol_write(char *buf) 319 { 320 zev_print_zvol_truncate(buf); 321 } 322 323 static void 324 zev_print_znode_close_after_update(char *buf) 325 { 326 zev_znode_close_after_update_t *rec = 327 (zev_znode_close_after_update_t *)buf; 328 time_t op_time = rec->op_time; 329 char *ct = ctime(&op_time); ct[24] = '\0'; 330 331 if (verbose) { 332 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 333 zpf(" guid: %llu", rec->guid); 334 zev_print_inode_info("file", &rec->file); 335 znl(); 336 } else { 337 printf("%s %s: guid=%llu file=%llu.%llu\n", 338 ct, zev_op_name[rec->op - ZEV_OP_MIN], 339 rec->guid, 340 rec->file.ino, rec->file.gen); 341 } 342 } 343 344 static void 345 zev_print_znode_create(char *buf) 346 { 347 zev_znode_create_t *rec = (zev_znode_create_t *)buf; 348 time_t op_time = rec->op_time; 349 char *ct = ctime(&op_time); ct[24] = '\0'; 350 zev_sig_t *sig; 351 char sigval[(SHA1_DIGEST_LENGTH * 2) + 1]; 352 353 if (verbose) { 354 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 355 zpf(" guid: %llu", rec->guid); 356 zpf(" txg: %llu", rec->txg); 357 zpf(" name: '%s'", ZEV_NAME(rec)); 358 sig = &rec->signature; 359 sig2hex_direct(sig->value, sigval); 360 zpf(" sig: level %d, offset %llu, value %s", 361 sig->level, sig->block_offset, sigval); 362 zev_print_inode_info("file", &rec->file); 363 zev_print_inode_info("parent", &rec->parent); 364 znl(); 365 } else { 366 printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu " 367 "file.mtime=%llu, parent.mtime=%llu, name='%s'\n", 368 ct, zev_op_name[rec->op - ZEV_OP_MIN], 369 rec->guid, 370 rec->parent.ino, rec->parent.gen, 371 rec->file.ino, rec->file.gen, 372 rec->file.mtime, rec->parent.mtime, 373 ZEV_NAME(rec)); 374 } 375 } 376 377 static void 378 zev_print_znode_mkdir(char *buf) 379 { 380 zev_print_znode_create(buf); 381 } 382 383 static void 384 zev_print_znode_make_xattr_dir(char *buf) 385 { 386 zev_print_znode_create(buf); 387 } 388 389 static void 390 zev_print_znode_remove(char *buf) 391 { 392 zev_znode_remove_t *rec = (zev_znode_remove_t *)buf; 393 time_t op_time = rec->op_time; 394 char *ct = ctime(&op_time); ct[24] = '\0'; 395 396 if (verbose) { 397 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 398 zpf(" guid: %llu", rec->guid); 399 zpf(" txg: %llu", rec->txg); 400 zpf(" file.name: '%s'", ZEV_NAME(rec)); 401 zev_print_inode_info("file", &rec->file); 402 zev_print_inode_info("parent", &rec->parent); 403 znl(); 404 } else { 405 printf("%s %s: guid=%llu parent=%llu.%llu " 406 "file.mtime=%llu name='%s'\n", 407 ct, zev_op_name[rec->op - ZEV_OP_MIN], 408 rec->guid, 409 rec->parent.ino, rec->parent.gen, 410 rec->file.mtime, 411 ZEV_NAME(rec)); 412 } 413 } 414 415 static void 416 zev_print_znode_rmdir(char *buf) 417 { 418 zev_print_znode_remove(buf); 419 } 420 421 static void 422 zev_print_znode_link(char *buf) 423 { 424 zev_znode_link_t *rec = (zev_znode_link_t *)buf; 425 time_t op_time = rec->op_time; 426 char *ct = ctime(&op_time); ct[24] = '\0'; 427 428 if (verbose) { 429 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 430 zpf(" guid: %llu", rec->guid); 431 zpf(" txg: %llu", rec->txg); 432 zpf(" link.name: '%s'", ZEV_NAME(rec)); 433 zev_print_inode_info("file", &rec->file); 434 zev_print_inode_info("parent", &rec->parent); 435 znl(); 436 } else { 437 printf("%s %s: parent=%llu.%llu file=%llu.%llu " 438 "file.ctime=%llu parent.ctime=%llu name='%s'\n", 439 ct, zev_op_name[rec->op - ZEV_OP_MIN], 440 rec->parent.ino, rec->parent.gen, 441 rec->file.ino, rec->file.gen, 442 rec->file.ctime, rec->parent.ctime, 443 ZEV_NAME(rec)); 444 } 445 } 446 447 static void 448 zev_print_znode_symlink(char *buf) 449 { 450 zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf; 451 time_t op_time = rec->op_time; 452 char *ct = ctime(&op_time); ct[24] = '\0'; 453 zev_sig_t *sig; 454 char sigval[(SHA1_DIGEST_LENGTH * 2) + 1]; 455 456 if (verbose) { 457 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 458 zpf(" guid: %llu", rec->guid); 459 zpf(" txg: %llu", rec->txg); 460 zpf(" symlink.name: '%s'", ZEV_NAME(rec)); 461 zpf(" symlink.link: '%s'", ZEV_LINK(rec)); 462 sig = &rec->signature; 463 sig2hex_direct(sig->value, sigval); 464 zpf(" sig: level %d, offset %llu, value %s", 465 sig->level, sig->block_offset, sigval); 466 zev_print_inode_info("file", &rec->file); 467 zev_print_inode_info("parent", &rec->parent); 468 znl(); 469 } else { 470 printf("%s %s: parent=%llu.%llu file=%llu.%llu " 471 "name='%s' link='%s'\n", 472 ct, zev_op_name[rec->op - ZEV_OP_MIN], 473 rec->parent.ino, rec->parent.gen, 474 rec->file.ino, rec->file.gen, 475 ZEV_NAME(rec), 476 ZEV_LINK(rec)); 477 } 478 } 479 480 static void 481 zev_print_znode_rename(char *buf) 482 { 483 zev_znode_rename_t *rec = (zev_znode_rename_t *)buf; 484 time_t op_time = rec->op_time; 485 char *ct = ctime(&op_time); ct[24] = '\0'; 486 487 if (verbose) { 488 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 489 zpf(" guid: %llu", rec->guid); 490 zpf(" txg: %llu", rec->txg); 491 zpf(" file.srcname: '%s'", ZEV_SRCNAME(rec)); 492 zpf(" file.dstname: '%s'", ZEV_DSTNAME(rec)); 493 zev_print_inode_info("file", &rec->file); 494 if (rec->clobbered_file.ino) 495 zev_print_inode_info("clobbered_file", 496 &rec->clobbered_file); 497 zev_print_inode_info("srcdir", &rec->srcdir); 498 zev_print_inode_info("dstdir", &rec->dstdir); 499 znl(); 500 } else { 501 printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu " 502 "file=%llu.%llu file.mtime=%llu, file.ctime=%llu, " 503 "srcdir.mtime=%llu, srcdir.ctime=%llu, " 504 "dstdir.mtime=%llu, dstdir.ctime=%llu, " 505 "srcname='%s' dstname='%s'\n", 506 ct, zev_op_name[rec->op - ZEV_OP_MIN], 507 rec->srcdir.ino, rec->srcdir.gen, 508 rec->dstdir.ino, rec->dstdir.gen, 509 rec->file.ino, rec->file.gen, 510 rec->file.mtime, rec->file.ctime, 511 rec->srcdir.mtime, rec->srcdir.ctime, 512 rec->dstdir.mtime, rec->dstdir.ctime, 513 ZEV_SRCNAME(rec), 514 ZEV_DSTNAME(rec)); 515 } 516 } 517 518 static void 519 zev_print_znode_write(char *buf) 520 { 521 zev_znode_write_t *rec = (zev_znode_write_t *)buf; 522 time_t op_time = rec->op_time; 523 char *ct = ctime(&op_time); ct[24] = '\0'; 524 zev_sig_t *sig; 525 char sigval[(SHA1_DIGEST_LENGTH * 2) + 1]; 526 int i; 527 528 if (verbose) { 529 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 530 zpf(" guid: %llu", rec->guid); 531 zpf(" txg: %llu", rec->txg); 532 zpf(" offset: %llu", rec->offset); 533 zpf(" length: %llu", rec->length); 534 zev_print_inode_info("file", &rec->file); 535 znl(); 536 for (i=0; i<rec->signature_cnt; i++) { 537 sig = (zev_sig_t *)ZEV_SIGNATURES(rec); 538 sig += i; 539 sig2hex_direct(sig->value, sigval); 540 zpf(" sig: level %d, offset %llu, value %s", 541 sig->level, sig->block_offset, sigval); 542 } 543 } else { 544 printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n", 545 ct, zev_op_name[rec->op - ZEV_OP_MIN], 546 rec->file.ino, rec->file.gen, 547 rec->offset, rec->length); 548 } 549 } 550 551 static void 552 zev_print_znode_truncate(char *buf) 553 { 554 zev_print_znode_write(buf); 555 } 556 557 static void 558 zev_print_znode_setattr(char *buf) 559 { 560 zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf; 561 time_t op_time = rec->op_time; 562 char *ct = ctime(&op_time); ct[24] = '\0'; 563 564 if (verbose) { 565 zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]); 566 zpf(" guid: %llu", rec->guid); 567 zpf(" txg: %llu", rec->txg); 568 zev_print_inode_info("file", &rec->file); 569 znl(); 570 } else { 571 printf("%s %s: file=%llu.%llu mtime=%llu\n", 572 ct, zev_op_name[rec->op - ZEV_OP_MIN], 573 rec->file.ino, rec->file.gen, rec->file.mtime); 574 } 575 } 576 577 static void 578 zev_print_znode_acl(char *buf) 579 { 580 zev_print_znode_setattr(buf); 581 } 582 583 static void 584 zev_print_event(char *buf, int len) 585 { 586 int record_len; 587 int op; 588 589 record_len = *(uint32_t *)buf; 590 if (record_len != len) { 591 fprintf(stderr, "record length mismatch: got %d, expected %d\n", 592 record_len, len); 593 exit(1); 594 } 595 op = *((uint32_t *)buf + 1); 596 if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) { 597 fprintf(stderr, "unknown op code: %d\n", op); 598 exit(1); 599 } 600 if (num_guid_filter) { 601 uint64_t guid = *((uint64_t *)buf + 2); 602 int i; 603 604 for (i = 0; i < num_guid_filter; ++i) 605 if (guid_filter[i] == guid) 606 break; 607 608 if (i == num_guid_filter) 609 /* no match, filtered */ 610 return; 611 } 612 switch (op) { 613 case ZEV_OP_ERROR: 614 zev_print_error(buf); 615 break; 616 case ZEV_OP_MARK: 617 zev_print_mark(buf); 618 break; 619 case ZEV_OP_ZFS_MOUNT: 620 zev_print_zfs_mount(buf); 621 break; 622 case ZEV_OP_ZFS_UMOUNT: 623 zev_print_zfs_umount(buf); 624 break; 625 case ZEV_OP_ZVOL_TRUNCATE: 626 zev_print_zvol_truncate(buf); 627 break; 628 case ZEV_OP_ZVOL_WRITE: 629 zev_print_zvol_write(buf); 630 break; 631 case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE: 632 zev_print_znode_close_after_update(buf); 633 break; 634 case ZEV_OP_ZNODE_CREATE: 635 zev_print_znode_create(buf); 636 break; 637 case ZEV_OP_ZNODE_MKDIR: 638 zev_print_znode_mkdir(buf); 639 break; 640 case ZEV_OP_ZNODE_MAKE_XATTR_DIR: 641 zev_print_znode_make_xattr_dir(buf); 642 break; 643 case ZEV_OP_ZNODE_REMOVE: 644 zev_print_znode_remove(buf); 645 break; 646 case ZEV_OP_ZNODE_RMDIR: 647 zev_print_znode_rmdir(buf); 648 break; 649 case ZEV_OP_ZNODE_LINK: 650 zev_print_znode_link(buf); 651 break; 652 case ZEV_OP_ZNODE_SYMLINK: 653 zev_print_znode_symlink(buf); 654 break; 655 case ZEV_OP_ZNODE_RENAME: 656 zev_print_znode_rename(buf); 657 break; 658 case ZEV_OP_ZNODE_WRITE: 659 zev_print_znode_write(buf); 660 break; 661 case ZEV_OP_ZNODE_TRUNCATE: 662 zev_print_znode_truncate(buf); 663 break; 664 case ZEV_OP_ZNODE_SETATTR: 665 zev_print_znode_setattr(buf); 666 break; 667 case ZEV_OP_ZNODE_ACL: 668 zev_print_znode_acl(buf); 669 break; 670 default: 671 fprintf(stderr, "unhandled op code: %d\n", op); 672 exit(1); 673 } 674 if (do_flush) 675 fflush(stdout); 676 } 677 678 static int 679 zev_poll_events(int fd, int create_tmp_queue) 680 { 681 struct pollfd pfd[1]; 682 int ret; 683 char buf[4096]; 684 zev_event_t *ev; 685 int off = 0; 686 int q_fd; 687 688 if (create_tmp_queue) { 689 snprintf(buf, sizeof(buf), 690 "/devices/pseudo/zev@0:%s", ZEV_TMPQUEUE_DEVICE_NAME); 691 q_fd = open(buf, O_RDONLY); 692 if (q_fd < 0) { 693 perror("opening queue device failed"); 694 return (EXIT_FAILURE); 695 } 696 } else { 697 q_fd = fd; 698 } 699 700 while (1) { 701 pfd[0].fd = q_fd; 702 pfd[0].events = POLLIN; 703 ret = poll(pfd, 1, 1000); 704 if (ret < 0) { 705 perror("poll failed"); 706 close(q_fd); 707 return(EXIT_FAILURE); 708 } 709 if (!(pfd[0].revents & POLLIN)) 710 continue; 711 /* data available */ 712 ret = read(q_fd, buf, sizeof(buf)); 713 if (ret < 0) { 714 perror("read failed"); 715 close(q_fd); 716 return(EXIT_FAILURE); 717 } 718 if (ret == 0) 719 continue; 720 while (ret > off) { 721 ev = (zev_event_t *)(buf + off); 722 zev_print_event(buf + off, ev->header.record_len); 723 off += ev->header.record_len; 724 } 725 off = 0; 726 } 727 if (create_tmp_queue) 728 close(q_fd); 729 return EXIT_SUCCESS; 730 } 731 732 static int 733 zev_dump_spool(int fd) 734 { 735 int len; 736 char buf[4096]; 737 int off = 0; 738 739 while (1) { 740 len = read(fd, buf + off, sizeof(buf) - off); 741 if (len == -1) { 742 fprintf(stderr, "reading from spool failed: %s\n", 743 strerror(errno)); 744 return EXIT_FAILURE; 745 } 746 if (len == 0) 747 break; 748 749 len += off; 750 off = 0; 751 while (len > off + sizeof(uint32_t)) { 752 uint32_t evlen; 753 char *mp; 754 zev_event_t *ev; 755 756 ev = (zev_event_t *)(buf + off); 757 evlen = ev->header.record_len; 758 if (len < off + evlen + 1) 759 break; 760 mp = buf + off + evlen; 761 if (!memchr(mp, 0, len - off - evlen)) 762 break; 763 zev_print_event(buf + off, ev->header.record_len); 764 off += ev->header.record_len + strlen(mp) + 1; 765 } 766 767 memmove(buf, buf + off, len - off); 768 off = len - off; 769 } 770 771 return EXIT_SUCCESS; 772 } 773 774 static void 775 usage(char *progname) 776 { 777 fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname); 778 fprintf(stderr, "\n"); 779 fprintf(stderr, " Status information:\n"); 780 fprintf(stderr, " -s show zev statistics\n"); 781 fprintf(stderr, " -p poll for ZFS events\n"); 782 fprintf(stderr, " -f <name> dump events from spool\n"); 783 fprintf(stderr, " -D print zev module debug " 784 "information\n"); 785 fprintf(stderr, " -T <interval> <cnt> zevstat mode\n"); 786 fprintf(stderr, " -R <base filename> zevreport mode\n"); 787 fprintf(stderr, "\n"); 788 fprintf(stderr, " Tune zev module settings:\n"); 789 fprintf(stderr, " -Q <bytes> set maximum event queue " 790 "length\n"); 791 fprintf(stderr, " -m <pool> mute pool, no events for " 792 "this pool\n"); 793 fprintf(stderr, " -M <pool> unmute pool\n"); 794 fprintf(stderr, "\n"); 795 fprintf(stderr, " Queue management:\n"); 796 fprintf(stderr, " -l list queues\n"); 797 fprintf(stderr, " -a <name> add non-blocking queue\n"); 798 fprintf(stderr, " -A <name> add blocking queue\n"); 799 fprintf(stderr, " -r <name> remove queue\n"); 800 fprintf(stderr, " -b <name> make queue non-blocking " 801 "(default)\n"); 802 fprintf(stderr, " -B <name> make queue block when full\n"); 803 fprintf(stderr, " -P <name> display queue properties\n"); 804 fprintf(stderr, " -L <name> <bytes> set maximum event queue " 805 "length\n"); 806 fprintf(stderr, " -t <name> <bytes> set queue length poll " 807 "throttle\n"); 808 fprintf(stderr, "\n"); 809 fprintf(stderr, " Other options:\n"); 810 fprintf(stderr, " -d <dev> non-default device file. " 811 "('%s')\n", ZEV_DEVICE); 812 fprintf(stderr, " -q <name> use device file for this " 813 "queue name\n"); 814 fprintf(stderr, " -k <guid>:<payload> queue mark event\n"); 815 fprintf(stderr, " -c <filename> list file's content " 816 "checksums\n"); 817 fprintf(stderr, " -v verbose: additional output " 818 "for some operations\n"); 819 fprintf(stderr, " -g grep-friendly event output, " 820 "one event per line\n"); 821 fprintf(stderr, " -G <guid> filter event output by guid, " 822 "can be given more than once\n"); 823 fprintf(stderr, " -V query zev module version\n"); 824 fprintf(stderr, " -F flush output after each line\n"); 825 exit (EXIT_FAILURE); 826 } 827 828 static void 829 zevstat_usage(char *progname) 830 { 831 fprintf(stderr, "usage: %s [-v] <interval> [count]\n", progname); 832 fprintf(stderr, " -v verbose, show counters for all event types\n"); 833 exit (EXIT_FAILURE); 834 } 835 836 static void 837 zevreport_usage(char *progname) 838 { 839 fprintf(stderr, "usage: %s <output base filename>\n", progname); 840 exit (EXIT_FAILURE); 841 } 842 843 static int 844 zev_add_queue(int fd, char *arg, int blocking) 845 { 846 zev_ioctl_add_queue_t aq; 847 int namelen; 848 849 namelen = strlen(arg); 850 if (namelen > ZEV_MAX_QUEUE_NAME_LEN) { 851 fprintf(stderr, "queue name too long: %s\n", arg); 852 return (EXIT_FAILURE); 853 } 854 855 aq.zev_namelen = namelen; 856 strcpy(aq.zev_name, arg); 857 aq.zev_flags = ZEV_FL_PERSISTENT | ZEV_FL_INITIALLY_EMPTY; 858 if (blocking) { 859 aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL; 860 aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN; 861 } else { 862 aq.zev_max_queue_len = (1024 * 1024); 863 } 864 865 if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) { 866 perror("adding queue failed"); 867 return (EXIT_FAILURE); 868 } 869 return (0); 870 } 871 872 static int 873 zev_remove_queue(int fd, char *arg) 874 { 875 zev_ioctl_remove_queue_t aq; 876 int namelen; 877 878 namelen = strlen(arg); 879 if (namelen > ZEV_MAX_QUEUE_NAME_LEN) { 880 fprintf(stderr, "queue name too long: %s\n", arg); 881 return (EXIT_FAILURE); 882 } 883 884 aq.zev_queue_name.zev_namelen = namelen; 885 strcpy(aq.zev_queue_name.zev_name, arg); 886 887 if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) { 888 perror("removing queue failed"); 889 return (EXIT_FAILURE); 890 } 891 return (0); 892 } 893 894 static int 895 zev_set_global_max_queue_len(int fd, char *arg) 896 { 897 uint64_t maxqueuelen; 898 899 if (!arg) { 900 fprintf(stderr, "missing queue length parameter\n"); 901 return (EXIT_FAILURE); 902 } 903 904 errno = 0; 905 maxqueuelen = strtol(arg, (char **)NULL, 10); 906 if (errno) { 907 fprintf(stderr, "invalid queue length parameter: %s\n", arg); 908 return (EXIT_FAILURE); 909 } 910 if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) { 911 perror("setting max queue length failed"); 912 return (EXIT_FAILURE); 913 } 914 return (0); 915 } 916 917 static int 918 zev_mute_unmute_impl(int fd, char *poolname, int mute) 919 { 920 zev_ioctl_poolarg_t pa; 921 int len; 922 int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL; 923 len = strlen(poolname); 924 if (len <= 0 || len >= sizeof(pa.zev_poolname)) { 925 fprintf(stderr, "invalid poolname: %s\n", poolname); 926 return (EXIT_FAILURE); 927 } 928 strcpy(pa.zev_poolname, poolname); 929 pa.zev_poolname_len = len; 930 if (ioctl(fd, op, &pa)) { 931 perror("muting pool data failed"); 932 return (EXIT_FAILURE); 933 } 934 return (0); 935 } 936 937 int 938 zev_mute_pool(int fd, char *poolname) 939 { 940 return zev_mute_unmute_impl(fd, poolname, 1); 941 } 942 943 int 944 zev_unmute_pool(int fd, char *poolname) 945 { 946 return zev_mute_unmute_impl(fd, poolname, 0); 947 } 948 949 static int 950 zev_debug_info(int fd) 951 { 952 zev_ioctl_debug_info_t di; 953 954 if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) { 955 perror("getting zev debug info failed"); 956 return (EXIT_FAILURE); 957 } 958 959 printf("memory allocated: %llu bytes\n", di.zev_memory_allocated); 960 printf("checksum cache size: %llu\n", di.zev_chksum_cache_size); 961 printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits); 962 printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses); 963 return 0; 964 } 965 966 static int 967 zev_mark(int fd, char *arg) 968 { 969 zev_ioctl_mark_t *mark; 970 uint64_t guid; 971 int len; 972 char *p; 973 974 p = strchr(arg, ':'); 975 if (!p) { 976 fprintf(stderr, "expected value is <guid>:<payload>, " 977 "e.g. '123:hello'\n"); 978 exit (EXIT_FAILURE); 979 } 980 *p = '\n'; 981 p++; 982 983 errno = 0; 984 guid = strtoll(arg, (char **)NULL, 10); 985 if (errno) { 986 fprintf(stderr, "guid must be a number.\n"); 987 exit (EXIT_FAILURE); 988 } 989 990 len = strlen(p); 991 992 mark = malloc(sizeof(*mark) + len + 1); 993 if (!mark) { 994 fprintf(stderr, "can't allocate mark structure: %s\n", 995 strerror(errno)); 996 exit (EXIT_FAILURE); 997 } 998 mark->zev_guid = guid; 999 mark->zev_mark_id = 0; 1000 mark->zev_payload_len = len; 1001 strcpy(ZEV_PAYLOAD(mark), p); 1002 1003 if (ioctl(fd, ZEV_IOC_MARK, mark)) { 1004 perror("queueing mark failed"); 1005 return (EXIT_FAILURE); 1006 } 1007 1008 printf("mark id: %lu\n", mark->zev_mark_id); 1009 return (0); 1010 } 1011 1012 static int 1013 zev_queue_blocking(int fd, char *arg, int block) 1014 { 1015 zev_ioctl_get_queue_properties_t gqp; 1016 1017 gqp.zev_queue_name.zev_namelen = strlen(arg); 1018 if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { 1019 fprintf(stderr, "queue name too long.\n"); 1020 return EXIT_FAILURE; 1021 } 1022 strcpy(gqp.zev_queue_name.zev_name, arg); 1023 1024 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 1025 perror("getting queue properties failed"); 1026 return (EXIT_FAILURE); 1027 } 1028 if (block) { 1029 gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL; 1030 } else { 1031 gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL; 1032 } 1033 if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { 1034 perror("setting queue properties failed"); 1035 return (EXIT_FAILURE); 1036 } 1037 return (0); 1038 } 1039 1040 static int 1041 zev_set_max_queue_len(int fd, char *arg, char *len) 1042 { 1043 zev_ioctl_get_queue_properties_t gqp; 1044 1045 if (!len) { 1046 fprintf(stderr, "queue size parameter missing.\n"); 1047 return EXIT_FAILURE; 1048 } 1049 1050 gqp.zev_queue_name.zev_namelen = strlen(arg); 1051 if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { 1052 fprintf(stderr, "queue name too long.\n"); 1053 return EXIT_FAILURE; 1054 } 1055 strcpy(gqp.zev_queue_name.zev_name, arg); 1056 1057 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 1058 perror("getting queue properties failed"); 1059 return (EXIT_FAILURE); 1060 } 1061 gqp.zev_max_queue_len = atol(len); 1062 if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) { 1063 fprintf(stderr, "queue size parameter garbled.\n"); 1064 return (EXIT_FAILURE); 1065 } 1066 if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) { 1067 fprintf(stderr, "queue size parameter out of bounds.\n"); 1068 return (EXIT_FAILURE); 1069 } 1070 1071 if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { 1072 perror("setting queue properties failed"); 1073 return (EXIT_FAILURE); 1074 } 1075 return (0); 1076 } 1077 1078 static int 1079 zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len) 1080 { 1081 zev_ioctl_get_queue_properties_t gqp; 1082 1083 if (!len) { 1084 fprintf(stderr, "poll throttle parameter missing.\n"); 1085 return EXIT_FAILURE; 1086 } 1087 1088 gqp.zev_queue_name.zev_namelen = strlen(arg); 1089 if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { 1090 fprintf(stderr, "queue name too long.\n"); 1091 return EXIT_FAILURE; 1092 } 1093 strcpy(gqp.zev_queue_name.zev_name, arg); 1094 1095 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 1096 perror("getting queue properties failed"); 1097 return (EXIT_FAILURE); 1098 } 1099 gqp.zev_poll_wakeup_threshold = atol(len); 1100 if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) { 1101 fprintf(stderr, "poll throttle parameter garbled.\n"); 1102 return (EXIT_FAILURE); 1103 } 1104 if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) { 1105 fprintf(stderr, "poll throttle parameter out of bounds.\n"); 1106 return (EXIT_FAILURE); 1107 } 1108 1109 if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { 1110 perror("setting queue properties failed"); 1111 return (EXIT_FAILURE); 1112 } 1113 return (0); 1114 } 1115 1116 static int 1117 zev_queue_properties(int fd, char *arg) 1118 { 1119 zev_ioctl_get_queue_properties_t gqp; 1120 1121 gqp.zev_queue_name.zev_namelen = strlen(arg); 1122 if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { 1123 fprintf(stderr, "queue name too long.\n"); 1124 return EXIT_FAILURE; 1125 } 1126 strcpy(gqp.zev_queue_name.zev_name, arg); 1127 1128 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 1129 perror("getting queue properties failed"); 1130 return (EXIT_FAILURE); 1131 } 1132 1133 printf("queue : %s\n", arg); 1134 printf("max size : %" PRIu64 "\n", gqp.zev_max_queue_len); 1135 printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold); 1136 printf("persistent : %s\n", 1137 gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no"); 1138 printf("blocking : %s\n", 1139 gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no"); 1140 1141 return (0); 1142 } 1143 1144 static int 1145 zev_list_queues(int fd) 1146 { 1147 zev_ioctl_get_queue_properties_t gqp; 1148 zev_ioctl_get_queue_list_t gql; 1149 zev_ioctl_get_queue_statistics_t gs; 1150 uint64_t i; 1151 char name[ZEV_MAX_QUEUE_NAME_LEN+1]; 1152 zev_statistics_t zs; 1153 1154 if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) { 1155 perror("getting statistics data failed"); 1156 return (EXIT_FAILURE); 1157 } 1158 1159 if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) { 1160 perror("getting queue list failed"); 1161 return (EXIT_FAILURE); 1162 } 1163 1164 printf("Name Size " 1165 "Size%% Max Size Per Block\n"); 1166 1167 for (i=0; i<gql.zev_n_queues; i++) { 1168 strncpy(name, gql.zev_queue_name[i].zev_name, 1169 ZEV_MAX_QUEUE_NAME_LEN); 1170 name[gql.zev_queue_name[i].zev_namelen] = '\0'; 1171 1172 memcpy(gqp.zev_queue_name.zev_name, 1173 gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN); 1174 gqp.zev_queue_name.zev_namelen = 1175 gql.zev_queue_name[i].zev_namelen; 1176 1177 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 1178 if (errno == ENOENT) 1179 continue; 1180 perror("getting queue properties failed"); 1181 return (EXIT_FAILURE); 1182 } 1183 1184 memcpy(gs.zev_queue_name.zev_name, 1185 gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN); 1186 gs.zev_queue_name.zev_namelen = 1187 gql.zev_queue_name[i].zev_namelen; 1188 1189 if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) { 1190 if (errno == ENOENT) 1191 continue; 1192 perror("getting statistics data failed"); 1193 return (EXIT_FAILURE); 1194 } 1195 1196 if (gqp.zev_max_queue_len == 0) { 1197 gqp.zev_max_queue_len = zs.zev_max_queue_len; 1198 } 1199 printf("%-40s %-10" PRIu64 " %5.1f %-10" PRIu64 1200 " %-3s %-3s\n", 1201 name, 1202 gs.zev_statistics.zev_queue_len * 100.0 / 1203 gqp.zev_max_queue_len, 1204 gs.zev_statistics.zev_queue_len, 1205 gqp.zev_max_queue_len, 1206 gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no", 1207 gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? 1208 "yes" : "no"); 1209 } 1210 1211 return (0); 1212 } 1213 1214 static int 1215 zev_checksum(int dev_fd, char *filename) 1216 { 1217 int fd; 1218 offset_t off; 1219 offset_t data; 1220 zev_sig_t *sig; 1221 char *buf; 1222 zev_ioctl_get_signatures_t *gs; 1223 int i; 1224 char sigval[(SHA1_DIGEST_LENGTH * 2) + 1]; 1225 int buf_size; 1226 1227 /* control struct, one lv1 signature and up to 256 lv0 signatures */ 1228 buf_size = (1 + 256) * sizeof(zev_sig_t); 1229 buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size); 1230 if (!buf) { 1231 perror("can't allocate checksum buffer"); 1232 return (EXIT_FAILURE); 1233 } 1234 1235 fd = open(filename, O_RDONLY); 1236 if (fd < 0) { 1237 perror("can't open file"); 1238 return (EXIT_FAILURE); 1239 } 1240 1241 gs = (zev_ioctl_get_signatures_t *)buf; 1242 gs->zev_fd = fd; 1243 gs->zev_bufsize = buf_size; 1244 1245 off = 0; 1246 data = 0; 1247 while (1) { 1248 errno = 0; 1249 data = llseek(fd, off, SEEK_DATA); 1250 if (data < 0) { 1251 if (errno == ENXIO) /* no more data */ 1252 break; 1253 perror("llseek failed"); 1254 goto err; 1255 } 1256 data = P2ALIGN(data, ZEV_L1_SIZE); 1257 off = data + ZEV_L1_SIZE; 1258 1259 gs->zev_offset = data; 1260 gs->zev_len = ZEV_L1_SIZE; 1261 1262 if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) { 1263 perror("ioctl to get signatures failed"); 1264 goto err; 1265 } 1266 1267 for (i=0; i<gs->zev_signature_cnt; i++) { 1268 sig = (zev_sig_t *)ZEV_SIGNATURES(gs); 1269 sig += i; 1270 sig2hex_direct(sig->value, sigval); 1271 printf("level %d, offset %llu, value %s\n", 1272 sig->level, sig->block_offset, sigval); 1273 } 1274 } 1275 1276 free(buf); 1277 close(fd); 1278 return 0; 1279 err: 1280 free(buf); 1281 close(fd); 1282 return (EXIT_FAILURE); 1283 } 1284 1285 typedef struct zevstat { 1286 uint64_t ns_start; 1287 uint64_t events[ZEV_OP_MIN + ZEV_OP_MAX]; 1288 uint64_t guids; 1289 uint64_t total_events; 1290 uint64_t total_guids; 1291 avl_tree_t guids_interval; 1292 avl_tree_t guids_runtime; 1293 } zevstat_t; 1294 1295 typedef struct zev_guidtrack_t { 1296 uint64_t guid; 1297 avl_node_t avl_interval; 1298 avl_node_t avl_runtime; 1299 } zev_guidtrack_t; 1300 1301 zevstat_t zevstat; 1302 1303 static void 1304 zev_eventstat(char *buf, int len) 1305 { 1306 zev_header_t *rec = (zev_header_t *)buf; 1307 zev_guidtrack_t *gt; 1308 zev_guidtrack_t *gt_int; 1309 zev_guidtrack_t to_find; 1310 avl_index_t where; 1311 1312 zevstat.total_events++; 1313 zevstat.events[rec->op]++; 1314 1315 to_find.guid = rec->guid; 1316 gt = avl_find(&zevstat.guids_runtime, &to_find, &where); 1317 if (!gt) { 1318 gt = malloc(sizeof(*gt)); 1319 if (!gt) { 1320 perror("can't get guid tracking record"); 1321 exit (EXIT_FAILURE); 1322 } 1323 gt->guid = rec->guid; 1324 avl_insert(&zevstat.guids_runtime, gt, where); 1325 } 1326 gt_int = avl_find(&zevstat.guids_interval, &to_find, &where); 1327 if (!gt_int) 1328 avl_insert(&zevstat.guids_interval, gt, where); 1329 } 1330 1331 static void 1332 zev_eventstat_interval(FILE *out) 1333 { 1334 uint64_t events; 1335 int i; 1336 zev_guidtrack_t *gt; 1337 1338 events = 0; 1339 for (i = ZEV_OP_MIN; i <= ZEV_OP_MAX; i++) { 1340 events += zevstat.events[i]; 1341 } 1342 1343 if (verbose) { 1344 fprintf(out, "%u %6llu %6llu %6llu %6llu ", 1345 time(NULL), 1346 events, 1347 zevstat.total_events, 1348 avl_numnodes(&zevstat.guids_interval), 1349 avl_numnodes(&zevstat.guids_runtime)); 1350 for (i = ZEV_OP_MIN; i <= ZEV_OP_MAX; i++) 1351 fprintf(out, "%6llu ", zevstat.events[i]); 1352 fprintf(out, "\n"); 1353 } else { 1354 fprintf(out, "%u %6llu %6llu %6llu %6llu\n", 1355 time(NULL), 1356 events, 1357 zevstat.total_events, 1358 avl_numnodes(&zevstat.guids_interval), 1359 avl_numnodes(&zevstat.guids_runtime)); 1360 } 1361 memset(&zevstat.events, 0, sizeof(zevstat.events)); 1362 zevstat.guids = 0; 1363 while (gt = avl_first(&zevstat.guids_interval)) 1364 avl_remove(&zevstat.guids_interval, gt); 1365 fflush(out); 1366 } 1367 1368 static int 1369 zev_evcompar(const void *a, const void *b) 1370 { 1371 const zev_guidtrack_t *ga = a; 1372 const zev_guidtrack_t *gb = b; 1373 1374 if (ga->guid > gb->guid) 1375 return 1; 1376 if (ga->guid < gb->guid) 1377 return -1; 1378 return 0; 1379 } 1380 1381 static int 1382 zev_zevstat(int fd, char *s_interval, char *s_count, char *outfile) 1383 { 1384 uint64_t interval = 1000; 1385 uint64_t ms; 1386 uint64_t t_until; 1387 uint64_t t_now; 1388 int cnt = -1; 1389 struct pollfd pfd[1]; 1390 int ret; 1391 char buf[4096]; 1392 zev_event_t *ev; 1393 int off = 0; 1394 zev_ioctl_add_queue_t aq; 1395 int q_fd; 1396 zev_guidtrack_t *gt; 1397 FILE *out = stdout; 1398 struct stat st; 1399 char filename[MAXPATHLEN]; 1400 int retry; 1401 1402 if (outfile) { 1403 retry = 0; 1404 strncpy(filename, outfile, sizeof(filename)); 1405 while (stat(filename, &st) == 0) { 1406 /* file exists */ 1407 snprintf(filename, sizeof(filename), 1408 "%s.%d", outfile, retry); 1409 retry++; 1410 } 1411 out = fopen(filename, "wb+"); 1412 if (!out) { 1413 perror("opening output file failed"); 1414 return (EXIT_FAILURE); 1415 } 1416 } 1417 1418 memset(&zevstat, 0, sizeof(zevstat)); 1419 avl_create(&zevstat.guids_runtime, zev_evcompar, 1420 sizeof(zev_guidtrack_t), 1421 offsetof(zev_guidtrack_t, avl_runtime)); 1422 avl_create(&zevstat.guids_interval, zev_evcompar, 1423 sizeof(zev_guidtrack_t), 1424 offsetof(zev_guidtrack_t, avl_interval)); 1425 1426 if (s_interval) { 1427 interval = atol(s_interval); 1428 if (interval == 0) { 1429 fprintf(stderr, "invalid interval.\n"); 1430 return (EXIT_FAILURE); 1431 } 1432 interval *= 1000; 1433 } 1434 if (s_count) { 1435 cnt = atol(s_count); 1436 if (interval == 0) { 1437 fprintf(stderr, "invalid count.\n"); 1438 return (EXIT_FAILURE); 1439 } 1440 } 1441 1442 aq.zev_max_queue_len = 1024 * 1024; 1443 aq.zev_flags = ZEV_FL_INITIALLY_EMPTY; 1444 snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN, 1445 "zevstat.%ld.%ld", time(NULL), getpid()); 1446 aq.zev_namelen = strlen(aq.zev_name); 1447 1448 if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) { 1449 perror("adding temporary queue failed"); 1450 return (EXIT_FAILURE); 1451 } 1452 1453 snprintf(buf, sizeof(buf), 1454 "/devices/pseudo/zev@0:%s", aq.zev_name); 1455 q_fd = open(buf, O_RDONLY); 1456 if (q_fd < 0) { 1457 perror("opening queue device failed"); 1458 return (EXIT_FAILURE); 1459 } 1460 1461 pfd[0].fd = q_fd; 1462 pfd[0].events = POLLIN; 1463 1464 /* drain queue */ 1465 while ((ret = poll(pfd, 1, 0)) > 0) { 1466 if (read(q_fd, buf, sizeof(buf)) < 0) { 1467 perror("read failed"); 1468 close(q_fd); 1469 return(EXIT_FAILURE); 1470 } 1471 } 1472 if (ret < 0) { 1473 perror("poll failed"); 1474 close(q_fd); 1475 return(EXIT_FAILURE); 1476 } 1477 1478 fprintf(out, "timestamp events tevents guids tguids"); 1479 if (verbose) { 1480 fprintf(out, " error mark mount umount zvol_w "); 1481 fprintf(out, "zvol_t close create mkdir mxattr "); 1482 fprintf(out, "remove rmdir link symlnk rename "); 1483 fprintf(out, "write trunc setatt acl"); 1484 } 1485 fprintf(out, "\n"); 1486 while (cnt) { 1487 t_until = gethrtime() + (interval * 1000000); 1488 ms = interval; 1489 do { 1490 ret = poll(pfd, 1, ms); 1491 t_now = gethrtime(); 1492 if (t_now < t_until) { 1493 ms = t_until - t_now; 1494 ms /= 1000000ull; 1495 } 1496 if (ret < 0) { 1497 perror("poll failed"); 1498 close(q_fd); 1499 return(EXIT_FAILURE); 1500 } 1501 if (!(pfd[0].revents & POLLIN)) 1502 continue; 1503 /* data available */ 1504 ret = read(q_fd, buf, sizeof(buf)); 1505 if (ret < 0) { 1506 perror("read failed"); 1507 close(q_fd); 1508 return(EXIT_FAILURE); 1509 } 1510 if (ret == 0) 1511 continue; 1512 while (ret > off) { 1513 ev = (zev_event_t *)(buf + off); 1514 zev_eventstat(buf + off, ev->header.record_len); 1515 off += ev->header.record_len; 1516 } 1517 off = 0; 1518 } while ((t_now) < t_until && (ms > 0)); 1519 zev_eventstat_interval(out); 1520 if (cnt > 0) 1521 cnt--; 1522 } 1523 close(q_fd); 1524 if (outfile) 1525 fclose(out); 1526 while (gt = avl_first(&zevstat.guids_interval)) 1527 avl_remove(&zevstat.guids_interval, gt); 1528 while (gt = avl_first(&zevstat.guids_runtime)) { 1529 avl_remove(&zevstat.guids_runtime, gt); 1530 free(gt); 1531 } 1532 return EXIT_SUCCESS; 1533 } 1534 1535 static int 1536 zev_report(int fd, char *basename) 1537 { 1538 char filename[MAXPATHLEN]; 1539 char count[10]; 1540 time_t now; 1541 time_t midnight; 1542 struct tm tm; 1543 int minutes; 1544 int ret; 1545 1546 verbose++; 1547 while (1) { 1548 now = time(NULL); 1549 localtime_r(&now, &tm); 1550 snprintf(filename, sizeof(filename), "%s.%04d-%02d-%02d", 1551 basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 1552 tm.tm_sec = 0; 1553 tm.tm_min = 0; 1554 tm.tm_hour = 0; 1555 tm.tm_mday++; /* works for Jan 32nd, Feb 30th, etc. */ 1556 midnight = mktime(&tm); 1557 if (now % 60) 1558 sleep(60 - (now % 60)); 1559 minutes = (midnight - time(NULL)) / 60; 1560 snprintf(count, sizeof(count), "%d", minutes); 1561 ret = zev_zevstat(fd, "60", count, filename); 1562 if (ret) 1563 return EXIT_FAILURE; 1564 } 1565 return EXIT_SUCCESS; /* never reached */ 1566 } 1567 1568 static int 1569 zev_get_zev_version(int fd) 1570 { 1571 zev_ioctl_get_zev_version vi; 1572 1573 if (ioctl(fd, ZEV_IOC_GET_ZEV_VERSION, &vi)) { 1574 perror("getting zev cersion info failed"); 1575 return (EXIT_FAILURE); 1576 } 1577 1578 printf("zev major version: %llu\n", vi.zev_major_version); 1579 printf("zev minor version: %llu\n", vi.zev_minor_version); 1580 return 0; 1581 } 1582 1583 static void 1584 zev_sigint(int sig) 1585 { 1586 fflush(stdout); 1587 } 1588 1589 int 1590 main(int argc, char **argv) 1591 { 1592 int fd; 1593 int c; 1594 extern char *optarg; 1595 int create_tmp_queue = 1; 1596 char buf[MAXPATHLEN]; 1597 int mode = 0; 1598 char *arg = NULL; 1599 char *arg2 = NULL; 1600 char *p; 1601 1602 sigset(SIGINT, zev_sigint); 1603 1604 /* open device */ 1605 fd = open(zev_device, O_RDONLY); 1606 if (fd < 0) { 1607 perror("opening zev device failed"); 1608 return EXIT_FAILURE; 1609 } 1610 1611 p = strrchr(argv[0], '/'); 1612 if (!p) { 1613 p = argv[0]; 1614 } else { 1615 p++; 1616 } 1617 if (!strcmp(p, "zevstat")) { 1618 mode = MD_ZEVSTAT; 1619 if (argc < 2) 1620 zevstat_usage(argv[0]); 1621 if (!strcmp(argv[1], "-v")) { 1622 if (argc < 3) 1623 zevstat_usage(argv[0]); 1624 verbose++; 1625 arg = argv[2]; 1626 arg2 = argv[3]; 1627 } else { 1628 arg = argv[1]; 1629 arg2 = argv[2]; 1630 } 1631 return zev_zevstat(fd, arg, arg2, NULL); 1632 } else if(!strcmp(p, "zevreport")) { 1633 mode = MD_ZEV_REPORT; 1634 if (argc != 2) 1635 zevreport_usage(argv[0]); 1636 return zev_report(fd, argv[1]); 1637 } 1638 1639 while ((c = getopt(argc, argv, 1640 "a:A:b:B:c:d:Df:FgG:hk:lL:m:M:pP:q:Q:r:R:st:T:vV?")) != -1) { 1641 switch(c) { 1642 case 'g': 1643 grep_friendly++; 1644 verbose++; 1645 break; 1646 case 'v': 1647 verbose++; 1648 break; 1649 case 's': 1650 mode = MD_STATISTICS; 1651 break; 1652 case 'p': 1653 mode = MD_POLL_EVENTS; 1654 break; 1655 case 'c': 1656 mode = MD_CHECKSUMS; 1657 arg = optarg; 1658 break; 1659 case 'D': 1660 mode = MD_DEBUG_INFO; 1661 break; 1662 case 'd': 1663 close(fd); 1664 zev_device = optarg; 1665 fd = open(zev_device, O_RDONLY); 1666 if (fd < 0) { 1667 perror("opening zev device failed"); 1668 return EXIT_FAILURE; 1669 } 1670 create_tmp_queue = 0; 1671 break; 1672 case 'q': 1673 snprintf(buf, sizeof(buf), 1674 "/devices/pseudo/zev@0:%s", optarg); 1675 close(fd); 1676 zev_device = buf; 1677 fd = open(zev_device, O_RDONLY); 1678 if (fd < 0) { 1679 perror("opening zev device failed"); 1680 return EXIT_FAILURE; 1681 } 1682 create_tmp_queue = 0; 1683 break; 1684 case 'f': 1685 fd = open(optarg, O_RDONLY); 1686 if (fd < 0) { 1687 perror("opening spool file failed"); 1688 return EXIT_FAILURE; 1689 } 1690 mode = MD_DUMP_SPOOL; 1691 break; 1692 case 'l': 1693 mode = MD_LIST_QUEUES; 1694 break; 1695 case 'Q': 1696 mode = MD_SET_GLOBAL_MAX_QUEUE_LEN; 1697 arg = optarg; 1698 break; 1699 case 'L': 1700 mode = MD_SET_MAX_QUEUE_LEN; 1701 arg = optarg; 1702 arg2 = argv[optind]; 1703 break; 1704 case 'T': 1705 mode = MD_ZEVSTAT; 1706 arg = optarg; 1707 arg2 = argv[optind]; 1708 break; 1709 case 'R': 1710 mode = MD_ZEV_REPORT; 1711 arg = optarg; 1712 break; 1713 case 't': 1714 mode = MD_SET_POLL_WAKEUP_QUEUE_LEN; 1715 arg = optarg; 1716 arg2 = argv[optind]; 1717 break; 1718 case 'm': 1719 mode = MD_MUTE_POOL; 1720 arg = optarg; 1721 break; 1722 case 'M': 1723 mode = MD_UNMUTE_POOL; 1724 arg = optarg; 1725 break; 1726 case 'k': 1727 mode = MD_MARK; 1728 arg = optarg; 1729 break; 1730 case 'a': 1731 mode = MD_ADD_QUEUE; 1732 arg = optarg; 1733 break; 1734 case 'A': 1735 mode = MD_ADD_BLOCKING_QUEUE; 1736 arg = optarg; 1737 break; 1738 case 'r': 1739 mode = MD_REMOVE_QUEUE; 1740 arg = optarg; 1741 break; 1742 case 'b': 1743 mode = MD_QUEUE_BLOCKING; 1744 arg = optarg; 1745 break; 1746 case 'B': 1747 mode = MD_QUEUE_NONBLOCKING; 1748 arg = optarg; 1749 break; 1750 case 'P': 1751 mode = MD_QUEUE_PROPERTIES; 1752 arg = optarg; 1753 break; 1754 case 'G': 1755 if (num_guid_filter == MAX_GUID) { 1756 fprintf(stderr, 1757 "too many guids given, max is %d\n", MAX_GUID); 1758 exit(1); 1759 } 1760 guid_filter[num_guid_filter++] = atoll(optarg); 1761 break; 1762 case 'V': 1763 mode = MD_GET_ZEV_VERSION; 1764 break; 1765 case 'F': 1766 do_flush = 1; 1767 break; 1768 case 'h': 1769 case '?': 1770 default: 1771 usage(argv[0]); 1772 } 1773 } 1774 1775 switch (mode) { 1776 case MD_STATISTICS: 1777 return zev_statistics(fd); 1778 case MD_POLL_EVENTS: 1779 return zev_poll_events(fd, create_tmp_queue); 1780 case MD_DUMP_SPOOL: 1781 return zev_dump_spool(fd); 1782 case MD_CHECKSUMS: 1783 return zev_checksum(fd, arg); 1784 case MD_DEBUG_INFO: 1785 return zev_debug_info(fd); 1786 case MD_LIST_QUEUES: 1787 return zev_list_queues(fd); 1788 case MD_SET_GLOBAL_MAX_QUEUE_LEN: 1789 return zev_set_global_max_queue_len(fd, arg); 1790 case MD_SET_MAX_QUEUE_LEN: 1791 return zev_set_max_queue_len(fd, arg, arg2); 1792 case MD_SET_POLL_WAKEUP_QUEUE_LEN: 1793 return zev_set_poll_wakeup_queue_len(fd, arg, arg2); 1794 case MD_ZEVSTAT: 1795 return zev_zevstat(fd, arg, arg2, NULL); 1796 case MD_ZEV_REPORT: 1797 return zev_report(fd, arg); 1798 case MD_MUTE_POOL: 1799 return zev_mute_pool(fd, arg); 1800 case MD_UNMUTE_POOL: 1801 return zev_unmute_pool(fd, arg); 1802 case MD_MARK: 1803 return zev_mark(fd, arg); 1804 case MD_ADD_QUEUE: 1805 return zev_add_queue(fd, arg, 0); 1806 case MD_ADD_BLOCKING_QUEUE: 1807 return zev_add_queue(fd, arg, 1); 1808 case MD_REMOVE_QUEUE: 1809 return zev_remove_queue(fd, arg); 1810 case MD_QUEUE_BLOCKING: 1811 return zev_queue_blocking(fd, arg, 0); 1812 case MD_QUEUE_NONBLOCKING: 1813 return zev_queue_blocking(fd, arg, 1); 1814 case MD_QUEUE_PROPERTIES: 1815 return zev_queue_properties(fd, arg); 1816 case MD_GET_ZEV_VERSION: 1817 return zev_get_zev_version(fd); 1818 default: 1819 close(fd); 1820 usage(argv[0]); 1821 return EXIT_FAILURE; 1822 }; 1823 } 1824 1825