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 12 #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl" 13 14 static char *zev_device = ZEV_DEVICE; 15 16 static char *zev_op_name[] = { 17 "ZEV_OP_ERROR", 18 "ZEV_OP_MARK", 19 "ZEV_OP_ZFS_MOUNT", 20 "ZEV_OP_ZFS_UMOUNT", 21 "ZEV_OP_ZVOL_WRITE", 22 "ZEV_OP_ZVOL_TRUNCATE", 23 "ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE", 24 "ZEV_OP_ZNODE_CREATE", 25 "ZEV_OP_ZNODE_MKDIR", 26 "ZEV_OP_ZNODE_MAKE_XATTR_DIR", 27 "ZEV_OP_ZNODE_REMOVE", 28 "ZEV_OP_ZNODE_RMDIR", 29 "ZEV_OP_ZNODE_LINK", 30 "ZEV_OP_ZNODE_SYMLINK", 31 "ZEV_OP_ZNODE_RENAME", 32 "ZEV_OP_ZNODE_WRITE", 33 "ZEV_OP_ZNODE_TRUNCATE", 34 "ZEV_OP_ZNODE_SETATTR", 35 "ZEV_OP_ZNODE_ACL", 36 NULL 37 }; 38 39 static int verbose = 0; 40 41 static int 42 zev_statistics(int fd) 43 { 44 zev_statistics_t zs; 45 if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) { 46 perror("getting statistics data failed"); 47 return (EXIT_FAILURE); 48 } 49 printf("ZEV module state:\n"); 50 51 printf(" queue length in bytes : %lu\n", zs.zev_queue_len); 52 printf(" queue length limit : %lu\n", zs.zev_max_queue_len); 53 printf(" bytes read from device : %lu\n", zs.zev_bytes_read); 54 printf(" module internal errors : %lu\n\n", zs.zev_cnt_errors); 55 56 printf(" discarded events : %lu\n", 57 zs.zev_cnt_discarded_events); 58 printf(" discarded bytes : %lu\n\n", zs.zev_bytes_discarded); 59 60 printf("ZFS event statistics:\n"); 61 62 printf(" total ZFS events : %lu\n", zs.zev_cnt_total_events); 63 printf(" ZFS mount : %lu\n", zs.zev_cnt_zfs_mount); 64 printf(" ZFS umount : %lu\n", zs.zev_cnt_zfs_umount); 65 printf(" ZVOL write : %lu\n", zs.zev_cnt_zvol_write); 66 printf(" ZVOL truncate : %lu\n", zs.zev_cnt_zvol_truncate); 67 printf(" ZNODE close after update: %lu\n", 68 zs.zev_cnt_znode_close_after_update); 69 printf(" ZNODE create : %lu\n", zs.zev_cnt_znode_create); 70 printf(" ZNODE remove : %lu\n", zs.zev_cnt_znode_remove); 71 printf(" ZNODE link : %lu\n", zs.zev_cnt_znode_link); 72 printf(" ZNODE symlink : %lu\n", zs.zev_cnt_znode_symlink); 73 printf(" ZNODE rename : %lu\n", zs.zev_cnt_znode_rename); 74 printf(" ZNODE write : %lu\n", zs.zev_cnt_znode_write); 75 printf(" ZNODE truncate : %lu\n", 76 zs.zev_cnt_znode_truncate); 77 printf(" ZNODE setattr : %lu\n", zs.zev_cnt_znode_setattr); 78 printf(" ZNODE acl : %lu\n", zs.zev_cnt_znode_acl); 79 return EXIT_SUCCESS; 80 } 81 82 static void 83 zev_print_error(char *buf) 84 { 85 zev_error_t *rec = (zev_error_t *)buf; 86 time_t op_time = rec->op_time; 87 char *ct = ctime(&op_time); ct[24] = '\0'; 88 89 printf("%s %s: failed_op=%s msg=%s\n", 90 ct, zev_op_name[rec->op - ZEV_OP_MIN], 91 zev_op_name[rec->failed_op - ZEV_OP_MIN], ZEV_ERRSTR(rec)); 92 } 93 94 static void 95 zev_print_mark(char *buf) 96 { 97 zev_mark_t *rec = (zev_mark_t *)buf; 98 time_t op_time = rec->op_time; 99 char *ct = ctime(&op_time); ct[24] = '\0'; 100 101 printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n", 102 ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->mark_id, 103 rec->payload_len); 104 } 105 106 static void 107 zev_print_zfs_mount(char *buf) 108 { 109 zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf; 110 time_t op_time = rec->op_time; 111 char *ct = ctime(&op_time); ct[24] = '\0'; 112 113 printf("%s %s: guid=%llu remount=%s dataset='%s' mountpoint='%s'\n", 114 ct, zev_op_name[rec->op - ZEV_OP_MIN], 115 rec->guid, 116 rec->remount ? "true" : "false", 117 ZEV_DATASET(rec), 118 ZEV_MOUNTPOINT(rec)); 119 } 120 121 static void 122 zev_print_zfs_umount(char *buf) 123 { 124 zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf; 125 time_t op_time = rec->op_time; 126 char *ct = ctime(&op_time); ct[24] = '\0'; 127 128 printf("%s %s: guid=%llu\n", 129 ct, zev_op_name[rec->op - ZEV_OP_MIN], 130 rec->guid); 131 } 132 133 static void 134 zev_print_zvol_truncate(char *buf) 135 { 136 zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf; 137 time_t op_time = rec->op_time; 138 char *ct = ctime(&op_time); ct[24] = '\0'; 139 140 printf("%s %s: guid=%llu offset=%llu length=%llu\n", 141 ct, zev_op_name[rec->op - ZEV_OP_MIN], 142 rec->guid, 143 rec->offset, 144 rec->length); 145 } 146 147 static void 148 zev_print_zvol_write(char *buf) 149 { 150 zev_print_zvol_truncate(buf); 151 } 152 153 static void 154 zev_print_znode_close_after_update(char *buf) 155 { 156 zev_znode_close_after_update_t *rec = 157 (zev_znode_close_after_update_t *)buf; 158 time_t op_time = rec->op_time; 159 char *ct = ctime(&op_time); ct[24] = '\0'; 160 161 printf("%s %s: guid=%llu file=%llu.%llu\n", 162 ct, zev_op_name[rec->op - ZEV_OP_MIN], 163 rec->guid, 164 rec->file.ino, rec->file.gen); 165 } 166 167 static void 168 zev_print_znode_create(char *buf) 169 { 170 zev_znode_create_t *rec = (zev_znode_create_t *)buf; 171 time_t op_time = rec->op_time; 172 char *ct = ctime(&op_time); ct[24] = '\0'; 173 174 printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu " 175 "file.mtime=%llu, parent.mtime=%llu, name='%s'\n", 176 ct, zev_op_name[rec->op - ZEV_OP_MIN], 177 rec->guid, 178 rec->parent.ino, rec->parent.gen, 179 rec->file.ino, rec->file.gen, 180 rec->file.mtime, rec->parent.mtime, 181 ZEV_NAME(rec)); 182 } 183 184 static void 185 zev_print_znode_mkdir(char *buf) 186 { 187 zev_print_znode_create(buf); 188 } 189 190 static void 191 zev_print_znode_make_xattr_dir(char *buf) 192 { 193 zev_print_znode_create(buf); 194 } 195 196 static void 197 zev_print_znode_remove(char *buf) 198 { 199 zev_znode_remove_t *rec = (zev_znode_remove_t *)buf; 200 time_t op_time = rec->op_time; 201 char *ct = ctime(&op_time); ct[24] = '\0'; 202 203 printf("%s %s: guid=%llu parent=%llu.%llu file.mtime=%llu name='%s'\n", 204 ct, zev_op_name[rec->op - ZEV_OP_MIN], 205 rec->guid, 206 rec->parent.ino, rec->parent.gen, 207 rec->file.mtime, 208 ZEV_NAME(rec)); 209 } 210 211 static void 212 zev_print_znode_rmdir(char *buf) 213 { 214 zev_print_znode_remove(buf); 215 } 216 217 static void 218 zev_print_znode_link(char *buf) 219 { 220 zev_znode_link_t *rec = (zev_znode_link_t *)buf; 221 time_t op_time = rec->op_time; 222 char *ct = ctime(&op_time); ct[24] = '\0'; 223 224 printf("%s %s: parent=%llu.%llu file=%llu.%llu " 225 "file.ctime=%llu parent.ctime=%llu name='%s'\n", 226 ct, zev_op_name[rec->op - ZEV_OP_MIN], 227 rec->parent.ino, rec->parent.gen, 228 rec->file.ino, rec->file.gen, 229 rec->file.ctime, rec->parent.ctime, 230 ZEV_NAME(rec)); 231 printf("links: %d\n", rec->file.links); 232 } 233 234 static void 235 zev_print_znode_symlink(char *buf) 236 { 237 zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf; 238 time_t op_time = rec->op_time; 239 char *ct = ctime(&op_time); ct[24] = '\0'; 240 241 printf("%s %s: parent=%llu.%llu file=%llu.%llu name='%s' link='%s'\n", 242 ct, zev_op_name[rec->op - ZEV_OP_MIN], 243 rec->parent.ino, rec->parent.gen, 244 rec->file.ino, rec->file.gen, 245 ZEV_NAME(rec), 246 ZEV_LINK(rec)); 247 } 248 249 static void 250 zev_print_znode_rename(char *buf) 251 { 252 zev_znode_rename_t *rec = (zev_znode_rename_t *)buf; 253 time_t op_time = rec->op_time; 254 char *ct = ctime(&op_time); ct[24] = '\0'; 255 256 printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu file=%llu.%llu " 257 "file.mtime=%llu, file.ctime=%llu, srcdir.mtime=%llu, " 258 "srcdir.ctime=%llu, dstdir.mtime=%llu, dstdir.ctime=%llu, " 259 "srcname='%s' dstname='%s'\n", 260 ct, zev_op_name[rec->op - ZEV_OP_MIN], 261 rec->srcdir.ino, rec->srcdir.gen, 262 rec->dstdir.ino, rec->dstdir.gen, 263 rec->file.ino, rec->file.gen, 264 rec->file.mtime, rec->file.ctime, 265 rec->srcdir.mtime, rec->srcdir.ctime, 266 rec->dstdir.mtime, rec->dstdir.ctime, 267 ZEV_SRCNAME(rec), 268 ZEV_DSTNAME(rec)); 269 } 270 271 static void 272 sig2hex_direct(const uint8_t *sig, char *hex) 273 { 274 int i; 275 276 for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) { 277 sprintf(hex + 2 * i, "%02x", sig[i]); 278 } 279 hex[SHA1_DIGEST_LENGTH * 2] = '\0'; 280 } 281 282 static void 283 zev_print_znode_write(char *buf) 284 { 285 zev_znode_write_t *rec = (zev_znode_write_t *)buf; 286 time_t op_time = rec->op_time; 287 char *ct = ctime(&op_time); ct[24] = '\0'; 288 zev_sig_t *sig; 289 char sigval[(SHA1_DIGEST_LENGTH * 2) + 1]; 290 int i; 291 292 printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n", 293 ct, zev_op_name[rec->op - ZEV_OP_MIN], 294 rec->file.ino, rec->file.gen, 295 rec->offset, rec->length); 296 if (verbose) { 297 for (i=0; i<rec->signature_cnt; i++) { 298 sig = (zev_sig_t *)ZEV_SIGNATURES(rec); 299 sig += i; 300 sig2hex_direct(sig->value, sigval); 301 printf(" sig: level %d, offset %llu, value %s\n", 302 sig->level, sig->block_offset, sigval); 303 } 304 } 305 } 306 307 static void 308 zev_print_znode_truncate(char *buf) 309 { 310 zev_print_znode_write(buf); 311 } 312 313 static void 314 zev_print_znode_setattr(char *buf) 315 { 316 zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf; 317 time_t op_time = rec->op_time; 318 char *ct = ctime(&op_time); ct[24] = '\0'; 319 320 printf("%s %s: file=%llu.%llu mtime=%llu\n", 321 ct, zev_op_name[rec->op - ZEV_OP_MIN], 322 rec->file.ino, rec->file.gen, rec->file.mtime); 323 } 324 325 static void 326 zev_print_znode_acl(char *buf) 327 { 328 zev_print_znode_setattr(buf); 329 } 330 331 static void 332 zev_print_event(char *buf, int len) 333 { 334 int record_len; 335 int op; 336 337 record_len = *(uint32_t *)buf; 338 if (record_len != len) { 339 fprintf(stderr, "record length mismatch: got %d, expected %d\n", 340 record_len, len); 341 exit(1); 342 } 343 op = *((uint32_t *)buf + 1); 344 if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) { 345 fprintf(stderr, "unknown op code: %d\n", op); 346 exit(1); 347 } 348 switch (op) { 349 case ZEV_OP_ERROR: 350 zev_print_error(buf); 351 break; 352 case ZEV_OP_MARK: 353 zev_print_mark(buf); 354 break; 355 case ZEV_OP_ZFS_MOUNT: 356 zev_print_zfs_mount(buf); 357 break; 358 case ZEV_OP_ZFS_UMOUNT: 359 zev_print_zfs_umount(buf); 360 break; 361 case ZEV_OP_ZVOL_TRUNCATE: 362 zev_print_zvol_truncate(buf); 363 break; 364 case ZEV_OP_ZVOL_WRITE: 365 zev_print_zvol_write(buf); 366 break; 367 case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE: 368 zev_print_znode_close_after_update(buf); 369 break; 370 case ZEV_OP_ZNODE_CREATE: 371 zev_print_znode_create(buf); 372 break; 373 case ZEV_OP_ZNODE_MKDIR: 374 zev_print_znode_mkdir(buf); 375 break; 376 case ZEV_OP_ZNODE_MAKE_XATTR_DIR: 377 zev_print_znode_make_xattr_dir(buf); 378 break; 379 case ZEV_OP_ZNODE_REMOVE: 380 zev_print_znode_remove(buf); 381 break; 382 case ZEV_OP_ZNODE_RMDIR: 383 zev_print_znode_rmdir(buf); 384 break; 385 case ZEV_OP_ZNODE_LINK: 386 zev_print_znode_link(buf); 387 break; 388 case ZEV_OP_ZNODE_SYMLINK: 389 zev_print_znode_symlink(buf); 390 break; 391 case ZEV_OP_ZNODE_RENAME: 392 zev_print_znode_rename(buf); 393 break; 394 case ZEV_OP_ZNODE_WRITE: 395 zev_print_znode_write(buf); 396 break; 397 case ZEV_OP_ZNODE_TRUNCATE: 398 zev_print_znode_truncate(buf); 399 break; 400 case ZEV_OP_ZNODE_SETATTR: 401 zev_print_znode_setattr(buf); 402 break; 403 case ZEV_OP_ZNODE_ACL: 404 zev_print_znode_acl(buf); 405 break; 406 default: 407 fprintf(stderr, "unhandled op code: %d\n", op); 408 exit(1); 409 } 410 } 411 412 static int 413 zev_poll_events(int fd, int create_tmp_queue) 414 { 415 struct pollfd pfd[1]; 416 int ret; 417 char buf[4096]; 418 zev_event_t *ev; 419 int off = 0; 420 zev_ioctl_add_queue_t aq; 421 int q_fd; 422 423 if (create_tmp_queue) { 424 aq.zev_max_queue_len = 0; 425 aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL; 426 snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN, 427 "zevadm.%ld.%ld", time(NULL), getpid()); 428 aq.zev_namelen = strlen(aq.zev_name); 429 430 if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) { 431 perror("adding temporary queue failed"); 432 return (EXIT_FAILURE); 433 } 434 435 snprintf(buf, sizeof(buf), 436 "/devices/pseudo/zev@0:%s", aq.zev_name); 437 q_fd = open(buf, O_RDONLY); 438 if (q_fd < 0) { 439 perror("opening queue device failed"); 440 return (EXIT_FAILURE); 441 } 442 } else { 443 q_fd = fd; 444 } 445 446 while (1) { 447 pfd[0].fd = q_fd; 448 pfd[0].events = POLLIN; 449 ret = poll(pfd, 1, 1000); 450 if (ret < 0) { 451 perror("poll failed"); 452 close(q_fd); 453 return(EXIT_FAILURE); 454 } 455 if (!(pfd[0].revents & POLLIN)) 456 continue; 457 /* data available */ 458 ret = read(q_fd, buf, sizeof(buf)); 459 if (ret < 0) { 460 perror("read failed"); 461 close(q_fd); 462 return(EXIT_FAILURE); 463 } 464 if (ret == 0) 465 continue; 466 while (ret > off) { 467 ev = (zev_event_t *)(buf + off); 468 zev_print_event(buf + off, ev->header.record_len); 469 off += ev->header.record_len; 470 } 471 off = 0; 472 } 473 if (create_tmp_queue) 474 close(q_fd); 475 return EXIT_SUCCESS; 476 } 477 478 static void 479 usage(char *progname) 480 { 481 fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname); 482 fprintf(stderr, "\n"); 483 fprintf(stderr, " Status information:\n"); 484 fprintf(stderr, " -s show zev statistics\n"); 485 fprintf(stderr, " -p poll for ZFS events\n"); 486 fprintf(stderr, " -D print zev module debug " 487 "information\n"); 488 fprintf(stderr, "\n"); 489 fprintf(stderr, " Tune zev module settings:\n"); 490 fprintf(stderr, " -Q <bytes> set maximum event queue " 491 "length\n"); 492 fprintf(stderr, " -m <pool> mute pool, no events for " 493 "this pool\n"); 494 fprintf(stderr, " -M <pool> unmute pool\n"); 495 fprintf(stderr, "\n"); 496 fprintf(stderr, " Queue management:\n"); 497 fprintf(stderr, " -l list queues\n"); 498 fprintf(stderr, " -a <name> add non-blocking queue\n"); 499 fprintf(stderr, " -A <name> add blocking queue\n"); 500 fprintf(stderr, " -r <name> remove queue\n"); 501 fprintf(stderr, " -b <name> make queue non-blocking " 502 "(default)\n"); 503 fprintf(stderr, " -B <name> make queue block when full\n"); 504 fprintf(stderr, " -P <name> display queue properties\n"); 505 fprintf(stderr, " -L <name> <bytes> set maximum event queue " 506 "length\n"); 507 fprintf(stderr, " -t <name> <bytes> set queue length poll " 508 "throttle\n"); 509 fprintf(stderr, "\n"); 510 fprintf(stderr, " Other options:\n"); 511 fprintf(stderr, " -d <dev> non-default device file. " 512 "('%s')\n", ZEV_DEVICE); 513 fprintf(stderr, " -q <name> use device file for this " 514 "queue name\n"); 515 fprintf(stderr, " -k <guid>:<payload> queue mark event\n"); 516 fprintf(stderr, " -c <filename> list file's content " 517 "checksums\n"); 518 fprintf(stderr, " -v verbose: addition output " 519 "for some operations\n"); 520 exit (EXIT_FAILURE); 521 } 522 523 static int 524 zev_add_queue(int fd, char *arg, int blocking) 525 { 526 zev_ioctl_add_queue_t aq; 527 int namelen; 528 529 namelen = strlen(arg); 530 if (namelen > ZEV_MAX_QUEUE_NAME_LEN) { 531 fprintf(stderr, "queue name too long: %s\n", arg); 532 return (EXIT_FAILURE); 533 } 534 535 aq.zev_namelen = namelen; 536 strcpy(aq.zev_name, arg); 537 aq.zev_flags = ZEV_FL_PERSISTENT; 538 if (blocking) { 539 aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL; 540 aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN; 541 } else { 542 aq.zev_max_queue_len = (1024 * 1024); 543 } 544 545 if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) { 546 perror("adding queue failed"); 547 return (EXIT_FAILURE); 548 } 549 return (0); 550 } 551 552 static int 553 zev_remove_queue(int fd, char *arg) 554 { 555 zev_ioctl_remove_queue_t aq; 556 int namelen; 557 558 namelen = strlen(arg); 559 if (namelen > ZEV_MAX_QUEUE_NAME_LEN) { 560 fprintf(stderr, "queue name too long: %s\n", arg); 561 return (EXIT_FAILURE); 562 } 563 564 aq.zev_queue_name.zev_namelen = namelen; 565 strcpy(aq.zev_queue_name.zev_name, arg); 566 567 if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) { 568 perror("removing queue failed"); 569 return (EXIT_FAILURE); 570 } 571 return (0); 572 } 573 574 static int 575 zev_set_global_max_queue_len(int fd, char *arg) 576 { 577 uint64_t maxqueuelen; 578 579 errno = 0; 580 maxqueuelen = strtol(arg, (char **)NULL, 10); 581 if (errno) { 582 fprintf(stderr, "invalid queue length parameter: %s\n", arg); 583 return (EXIT_FAILURE); 584 } 585 if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) { 586 perror("setting max queue length failed"); 587 return (EXIT_FAILURE); 588 } 589 return (0); 590 } 591 592 static int 593 zev_mute_unmute_impl(int fd, char *poolname, int mute) 594 { 595 zev_ioctl_poolarg_t pa; 596 int len; 597 int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL; 598 len = strlen(poolname); 599 if (len <= 0 || len >= sizeof(pa.zev_poolname)) { 600 fprintf(stderr, "invalid poolname: %s\n", poolname); 601 return (EXIT_FAILURE); 602 } 603 strcpy(pa.zev_poolname, poolname); 604 pa.zev_poolname_len = len; 605 if (ioctl(fd, op, &pa)) { 606 perror("muting pool data failed"); 607 return (EXIT_FAILURE); 608 } 609 return (0); 610 } 611 612 int 613 zev_mute_pool(int fd, char *poolname) 614 { 615 return zev_mute_unmute_impl(fd, poolname, 1); 616 } 617 618 int 619 zev_unmute_pool(int fd, char *poolname) 620 { 621 return zev_mute_unmute_impl(fd, poolname, 0); 622 } 623 624 static int 625 zev_debug_info(int fd) 626 { 627 zev_ioctl_debug_info_t di; 628 629 if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) { 630 perror("getting zev debug info failed"); 631 return (EXIT_FAILURE); 632 } 633 634 printf("memory allocated: %llu bytes\n", di.zev_memory_allocated); 635 printf("checksum cache size: %llu\n", di.zev_chksum_cache_size); 636 printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits); 637 printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses); 638 return 0; 639 } 640 641 static int 642 zev_mark(int fd, char *arg) 643 { 644 zev_ioctl_mark_t *mark; 645 uint64_t guid; 646 int len; 647 char *p; 648 649 p = strchr(arg, ':'); 650 if (!p) { 651 fprintf(stderr, "expected value is <guid>:<payload>, " 652 "e.g. '123:hello'\n"); 653 exit (EXIT_FAILURE); 654 } 655 *p = '\n'; 656 p++; 657 658 errno = 0; 659 guid = strtoll(arg, (char **)NULL, 10); 660 if (errno) { 661 fprintf(stderr, "guid must be a number.\n"); 662 exit (EXIT_FAILURE); 663 } 664 665 len = strlen(p); 666 667 mark = malloc(sizeof(*mark) + len + 1); 668 if (!mark) { 669 fprintf(stderr, "can't allocate mark structure: %s\n", 670 strerror(errno)); 671 exit (EXIT_FAILURE); 672 } 673 mark->zev_guid = guid; 674 mark->zev_mark_id = 0; 675 mark->zev_payload_len = len; 676 strcpy(ZEV_PAYLOAD(mark), p); 677 678 if (ioctl(fd, ZEV_IOC_MARK, mark)) { 679 perror("queueing mark failed"); 680 return (EXIT_FAILURE); 681 } 682 683 printf("mark id: %lu\n", mark->zev_mark_id); 684 return (0); 685 } 686 687 static int 688 zev_queue_blocking(int fd, char *arg, int block) 689 { 690 zev_ioctl_get_queue_properties_t gqp; 691 692 gqp.zev_queue_name.zev_namelen = strlen(arg); 693 if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { 694 fprintf(stderr, "queue name too long.\n"); 695 return EXIT_FAILURE; 696 } 697 strcpy(gqp.zev_queue_name.zev_name, arg); 698 699 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 700 perror("getting queue properties failed"); 701 return (EXIT_FAILURE); 702 } 703 if (block) { 704 gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL; 705 } else { 706 gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL; 707 } 708 if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { 709 perror("setting queue properties failed"); 710 return (EXIT_FAILURE); 711 } 712 return (0); 713 } 714 715 static int 716 zev_set_max_queue_len(int fd, char *arg, char *len) 717 { 718 zev_ioctl_get_queue_properties_t gqp; 719 720 if (!len) { 721 fprintf(stderr, "queue size parameter missing.\n"); 722 return EXIT_FAILURE; 723 } 724 725 gqp.zev_queue_name.zev_namelen = strlen(arg); 726 if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { 727 fprintf(stderr, "queue name too long.\n"); 728 return EXIT_FAILURE; 729 } 730 strcpy(gqp.zev_queue_name.zev_name, arg); 731 732 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 733 perror("getting queue properties failed"); 734 return (EXIT_FAILURE); 735 } 736 gqp.zev_max_queue_len = atol(len); 737 if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) { 738 fprintf(stderr, "queue size parameter garbled.\n"); 739 return (EXIT_FAILURE); 740 } 741 if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) { 742 fprintf(stderr, "queue size parameter out of bounds.\n"); 743 return (EXIT_FAILURE); 744 } 745 746 if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { 747 perror("setting queue properties failed"); 748 return (EXIT_FAILURE); 749 } 750 return (0); 751 } 752 753 static int 754 zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len) 755 { 756 zev_ioctl_get_queue_properties_t gqp; 757 758 if (!len) { 759 fprintf(stderr, "poll throttle parameter missing.\n"); 760 return EXIT_FAILURE; 761 } 762 763 gqp.zev_queue_name.zev_namelen = strlen(arg); 764 if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { 765 fprintf(stderr, "queue name too long.\n"); 766 return EXIT_FAILURE; 767 } 768 strcpy(gqp.zev_queue_name.zev_name, arg); 769 770 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 771 perror("getting queue properties failed"); 772 return (EXIT_FAILURE); 773 } 774 gqp.zev_poll_wakeup_threshold = atol(len); 775 if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) { 776 fprintf(stderr, "poll throttle parameter garbled.\n"); 777 return (EXIT_FAILURE); 778 } 779 if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) { 780 fprintf(stderr, "poll throttle parameter out of bounds.\n"); 781 return (EXIT_FAILURE); 782 } 783 784 if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { 785 perror("setting queue properties failed"); 786 return (EXIT_FAILURE); 787 } 788 return (0); 789 } 790 791 static int 792 zev_queue_properties(int fd, char *arg) 793 { 794 zev_ioctl_get_queue_properties_t gqp; 795 796 gqp.zev_queue_name.zev_namelen = strlen(arg); 797 if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { 798 fprintf(stderr, "queue name too long.\n"); 799 return EXIT_FAILURE; 800 } 801 strcpy(gqp.zev_queue_name.zev_name, arg); 802 803 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 804 perror("getting queue properties failed"); 805 return (EXIT_FAILURE); 806 } 807 808 printf("queue : %s\n", arg); 809 printf("max size : %" PRIu64 "\n", gqp.zev_max_queue_len); 810 printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold); 811 printf("persistent : %s\n", 812 gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no"); 813 printf("blocking : %s\n", 814 gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no"); 815 816 return (0); 817 } 818 819 static int 820 zev_list_queues(int fd) 821 { 822 zev_ioctl_get_queue_properties_t gqp; 823 zev_ioctl_get_queue_list_t gql; 824 zev_ioctl_get_queue_statistics_t gs; 825 uint64_t i; 826 char name[ZEV_MAX_QUEUE_NAME_LEN+1]; 827 828 if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) { 829 perror("getting queue list failed"); 830 return (EXIT_FAILURE); 831 } 832 833 printf("Name Size " 834 "Max Size Wakeup Per Block\n"); 835 836 for (i=0; i<gql.zev_n_queues; i++) { 837 strncpy(name, gql.zev_queue_name[i].zev_name, 838 ZEV_MAX_QUEUE_NAME_LEN); 839 name[gql.zev_queue_name[i].zev_namelen] = '\0'; 840 841 memcpy(gqp.zev_queue_name.zev_name, 842 gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN); 843 gqp.zev_queue_name.zev_namelen = 844 gql.zev_queue_name[i].zev_namelen; 845 846 if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { 847 if (errno == ENOENT) 848 continue; 849 perror("getting queue properties failed"); 850 return (EXIT_FAILURE); 851 } 852 853 memcpy(gs.zev_queue_name.zev_name, 854 gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN); 855 gs.zev_queue_name.zev_namelen = 856 gql.zev_queue_name[i].zev_namelen; 857 858 if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) { 859 if (errno == ENOENT) 860 continue; 861 perror("getting statistics data failed"); 862 return (EXIT_FAILURE); 863 } 864 865 printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64 866 " %-3s %-3s\n", 867 name, 868 gs.zev_statistics.zev_queue_len, 869 gqp.zev_max_queue_len, 870 gqp.zev_poll_wakeup_threshold, 871 gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no", 872 gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? 873 "yes" : "no"); 874 } 875 876 return (0); 877 } 878 879 static int 880 zev_checksum(int dev_fd, char *filename) 881 { 882 int fd; 883 offset_t off; 884 offset_t data; 885 zev_sig_t *sig; 886 char *buf; 887 zev_ioctl_get_signatures_t *gs; 888 int i; 889 char sigval[(SHA1_DIGEST_LENGTH * 2) + 1]; 890 int buf_size; 891 892 /* control struct, one lv1 signature and up to 256 lv0 signatures */ 893 buf_size = (1 + 256) * sizeof(zev_sig_t); 894 buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size); 895 if (!buf) { 896 perror("can't allocate checksum buffer"); 897 return (EXIT_FAILURE); 898 } 899 900 fd = open(filename, O_RDONLY); 901 if (fd < 0) { 902 perror("can't open file"); 903 return (EXIT_FAILURE); 904 } 905 906 gs = (zev_ioctl_get_signatures_t *)buf; 907 gs->zev_fd = fd; 908 gs->zev_bufsize = buf_size; 909 910 off = 0; 911 data = 0; 912 while (1) { 913 errno = 0; 914 data = llseek(fd, off, SEEK_DATA); 915 if (data < 0) { 916 if (errno == ENXIO) /* no more data */ 917 break; 918 perror("llseek failed"); 919 goto err; 920 } 921 data = P2ALIGN(data, ZEV_L1_SIZE); 922 off = data + ZEV_L1_SIZE; 923 924 gs->zev_offset = data; 925 gs->zev_len = ZEV_L1_SIZE; 926 927 if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) { 928 perror("ioctl to get signatures failed"); 929 goto err; 930 } 931 932 for (i=0; i<gs->zev_signature_cnt; i++) { 933 sig = (zev_sig_t *)ZEV_SIGNATURES(gs); 934 sig += i; 935 sig2hex_direct(sig->value, sigval); 936 printf("level %d, offset %llu, value %s\n", 937 sig->level, sig->block_offset, sigval); 938 } 939 } 940 941 free(buf); 942 close(fd); 943 return 0; 944 err: 945 free(buf); 946 close(fd); 947 return (EXIT_FAILURE); 948 } 949 950 int 951 main(int argc, char **argv) 952 { 953 int fd; 954 int c; 955 extern char *optarg; 956 int create_tmp_queue = 1; 957 char buf[MAXPATHLEN]; 958 959 /* open device */ 960 fd = open(zev_device, O_RDONLY); 961 if (fd < 0) { 962 perror("opening zev device failed"); 963 return EXIT_FAILURE; 964 } 965 while ((c = getopt(argc, argv, 966 "vspc:d:Dlk:L:q:Qt:m:M:a:A:r:P:b:B:h?")) != -1){ 967 switch(c) { 968 case 'v': 969 verbose++; 970 break; 971 case 's': 972 return zev_statistics(fd); 973 case 'p': 974 return zev_poll_events(fd, create_tmp_queue); 975 case 'c': 976 return zev_checksum(fd, optarg); 977 case 'D': 978 return zev_debug_info(fd); 979 case 'd': 980 close(fd); 981 zev_device = optarg; 982 fd = open(zev_device, O_RDONLY); 983 if (fd < 0) { 984 perror("opening zev device failed"); 985 return EXIT_FAILURE; 986 } 987 create_tmp_queue = 0; 988 break; 989 case 'q': 990 snprintf(buf, sizeof(buf), 991 "/devices/pseudo/zev@0:%s", optarg); 992 close(fd); 993 zev_device = buf; 994 fd = open(zev_device, O_RDONLY); 995 if (fd < 0) { 996 perror("opening zev device failed"); 997 return EXIT_FAILURE; 998 } 999 create_tmp_queue = 0; 1000 break; 1001 case 'l': 1002 return zev_list_queues(fd); 1003 case 'Q': 1004 return zev_set_global_max_queue_len(fd, optarg); 1005 case 'L': 1006 return zev_set_max_queue_len(fd, optarg, argv[optind]); 1007 case 't': 1008 return zev_set_poll_wakeup_queue_len(fd, optarg, 1009 argv[optind]); 1010 case 'm': 1011 return zev_mute_pool(fd, optarg); 1012 case 'M': 1013 return zev_unmute_pool(fd, optarg); 1014 case 'k': 1015 return zev_mark(fd, optarg); 1016 case 'a': 1017 return zev_add_queue(fd, optarg, 0); 1018 case 'A': 1019 return zev_add_queue(fd, optarg, 1); 1020 case 'r': 1021 return zev_remove_queue(fd, optarg); 1022 case 'b': 1023 return zev_queue_blocking(fd, optarg, 0); 1024 case 'B': 1025 return zev_queue_blocking(fd, optarg, 1); 1026 case 'P': 1027 return zev_queue_properties(fd, optarg); 1028 case 'h': 1029 case '?': 1030 default: 1031 usage(argv[0]); 1032 } 1033 } 1034 usage(argv[0]); 1035 close(fd); 1036 return EXIT_FAILURE; 1037 } 1038 1039