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