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