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