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