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