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