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 17 #define ZEV_DEVICE "/devices/pseudo/zev@0:zev" 18 19 static char *zev_device = ZEV_DEVICE; 20 21 static char *zev_op_name[] = { 22 "ZEV_OP_ERROR", 23 "ZEV_OP_ZFS_MOUNT", 24 "ZEV_OP_ZFS_UMOUNT", 25 "ZEV_OP_ZVOL_WRITE", 26 "ZEV_OP_ZVOL_TRUNCATE", 27 "ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE", 28 "ZEV_OP_ZNODE_CREATE", 29 "ZEV_OP_ZNODE_MKDIR", 30 "ZEV_OP_ZNODE_MAKE_XATTR_DIR", 31 "ZEV_OP_ZNODE_REMOVE", 32 "ZEV_OP_ZNODE_RMDIR", 33 "ZEV_OP_ZNODE_LINK", 34 "ZEV_OP_ZNODE_SYMLINK", 35 "ZEV_OP_ZNODE_RENAME", 36 "ZEV_OP_ZNODE_WRITE", 37 "ZEV_OP_ZNODE_TRUNCATE", 38 "ZEV_OP_ZNODE_SETATTR", 39 "ZEV_OP_ZNODE_ACL", 40 NULL 41 }; 42 43 static void 44 zev_statistics(int fd) 45 { 46 zev_statistics_t zs; 47 if (ioctl(fd, ZEV_IOC_GET_STATISTICS, &zs)) { 48 perror("getting statistics data failed"); 49 exit (EXIT_FAILURE); 50 } 51 printf("ZEV module state:\n"); 52 53 printf(" queue length in bytes : %lu\n", zs.zev_queue_len); 54 printf(" queue length limit : %lu\n", zs.zev_max_queue_len); 55 printf(" poll wakeup throttle : %lu\n\n", 56 zs.zev_poll_wakeup_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("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 } 80 81 static void 82 zev_print_error(char *buf) 83 { 84 zev_error_t *rec = (zev_error_t *)buf; 85 time_t op_time = rec->op_time; 86 char *ct = ctime(&op_time); ct[24] = '\0'; 87 88 printf("%s %s: failed_op=%s msg=%s\n", 89 ct, zev_op_name[rec->op - ZEV_OP_MIN], 90 zev_op_name[rec->failed_op - ZEV_OP_MIN], ZEV_ERRSTR(rec)); 91 } 92 93 static void 94 zev_print_zfs_mount(char *buf) 95 { 96 zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf; 97 time_t op_time = rec->op_time; 98 char *ct = ctime(&op_time); ct[24] = '\0'; 99 100 printf("%s %s: guid=%llu remount=%s dataset='%s' mountpoint='%s'\n", 101 ct, zev_op_name[rec->op - ZEV_OP_MIN], 102 rec->guid, 103 rec->remount ? "true" : "false", 104 ZEV_DATASET(rec), 105 ZEV_MOUNTPOINT(rec)); 106 } 107 108 static void 109 zev_print_zfs_umount(char *buf) 110 { 111 zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf; 112 time_t op_time = rec->op_time; 113 char *ct = ctime(&op_time); ct[24] = '\0'; 114 115 printf("%s %s: guid=%llu\n", 116 ct, zev_op_name[rec->op - ZEV_OP_MIN], 117 rec->guid); 118 } 119 120 static void 121 zev_print_zvol_truncate(char *buf) 122 { 123 zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf; 124 time_t op_time = rec->op_time; 125 char *ct = ctime(&op_time); ct[24] = '\0'; 126 127 printf("%s %s: guid=%llu offset=%llu length=%llu\n", 128 ct, zev_op_name[rec->op - ZEV_OP_MIN], 129 rec->guid, 130 rec->offset, 131 rec->length); 132 } 133 134 static void 135 zev_print_zvol_write(char *buf) 136 { 137 zev_print_zvol_truncate(buf); 138 } 139 140 static void 141 zev_print_znode_close_after_update(char *buf) 142 { 143 zev_znode_close_after_update_t *rec = 144 (zev_znode_close_after_update_t *)buf; 145 time_t op_time = rec->op_time; 146 char *ct = ctime(&op_time); ct[24] = '\0'; 147 148 printf("%s %s: guid=%llu file=%llu.%llu\n", 149 ct, zev_op_name[rec->op - ZEV_OP_MIN], 150 rec->guid, 151 rec->file.ino, rec->file.gen); 152 } 153 154 static void 155 zev_print_znode_create(char *buf) 156 { 157 zev_znode_create_t *rec = (zev_znode_create_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 parent=%llu.%llu file=%llu.%llu name='%s'\n", 162 ct, zev_op_name[rec->op - ZEV_OP_MIN], 163 rec->guid, 164 rec->parent.ino, rec->parent.gen, 165 rec->file.ino, rec->file.gen, 166 ZEV_NAME(rec)); 167 } 168 169 static void 170 zev_print_znode_mkdir(char *buf) 171 { 172 zev_print_znode_create(buf); 173 } 174 175 static void 176 zev_print_znode_make_xattr_dir(char *buf) 177 { 178 zev_print_znode_create(buf); 179 } 180 181 static void 182 zev_print_znode_remove(char *buf) 183 { 184 zev_znode_remove_t *rec = (zev_znode_remove_t *)buf; 185 time_t op_time = rec->op_time; 186 char *ct = ctime(&op_time); ct[24] = '\0'; 187 188 printf("%s %s: guid=%llu parent=%llu.%llu name='%s'\n", 189 ct, zev_op_name[rec->op - ZEV_OP_MIN], 190 rec->guid, 191 rec->parent.ino, rec->parent.gen, 192 ZEV_NAME(rec)); 193 } 194 195 static void 196 zev_print_znode_rmdir(char *buf) 197 { 198 zev_print_znode_remove(buf); 199 } 200 201 static void 202 zev_print_znode_link(char *buf) 203 { 204 zev_znode_link_t *rec = (zev_znode_link_t *)buf; 205 time_t op_time = rec->op_time; 206 char *ct = ctime(&op_time); ct[24] = '\0'; 207 208 printf("%s %s: parent=%llu.%llu file=%llu.%llu name='%s'\n", 209 ct, zev_op_name[rec->op - ZEV_OP_MIN], 210 rec->parent.ino, rec->parent.gen, 211 rec->file.ino, rec->file.gen, 212 ZEV_NAME(rec)); 213 printf("links: %d\n", rec->file.links); 214 } 215 216 static void 217 zev_print_znode_symlink(char *buf) 218 { 219 zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf; 220 time_t op_time = rec->op_time; 221 char *ct = ctime(&op_time); ct[24] = '\0'; 222 223 printf("%s %s: parent=%llu.%llu file=%llu.%llu name='%s' link='%s'\n", 224 ct, zev_op_name[rec->op - ZEV_OP_MIN], 225 rec->parent.ino, rec->parent.gen, 226 rec->file.ino, rec->file.gen, 227 ZEV_NAME(rec), 228 ZEV_LINK(rec)); 229 } 230 231 static void 232 zev_print_znode_rename(char *buf) 233 { 234 zev_znode_rename_t *rec = (zev_znode_rename_t *)buf; 235 time_t op_time = rec->op_time; 236 char *ct = ctime(&op_time); ct[24] = '\0'; 237 238 printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu file=%llu.%llu " 239 "srcname='%s' dstname='%s'\n", 240 ct, zev_op_name[rec->op - ZEV_OP_MIN], 241 rec->srcdir.ino, rec->srcdir.gen, 242 rec->dstdir.ino, rec->dstdir.gen, 243 rec->file.ino, rec->file.gen, 244 ZEV_SRCNAME(rec), 245 ZEV_DSTNAME(rec)); 246 } 247 248 static void 249 zev_print_znode_write(char *buf) 250 { 251 zev_znode_write_t *rec = (zev_znode_write_t *)buf; 252 time_t op_time = rec->op_time; 253 char *ct = ctime(&op_time); ct[24] = '\0'; 254 255 printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n", 256 ct, zev_op_name[rec->op - ZEV_OP_MIN], 257 rec->file.ino, rec->file.gen, 258 rec->offset, rec->length); 259 } 260 261 static void 262 zev_print_znode_truncate(char *buf) 263 { 264 zev_print_znode_write(buf); 265 } 266 267 static void 268 zev_print_znode_setattr(char *buf) 269 { 270 zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf; 271 time_t op_time = rec->op_time; 272 char *ct = ctime(&op_time); ct[24] = '\0'; 273 274 printf("%s %s: file=%llu.%llu\n", 275 ct, zev_op_name[rec->op - ZEV_OP_MIN], 276 rec->file.ino, rec->file.gen); 277 } 278 279 static void 280 zev_print_znode_acl(char *buf) 281 { 282 zev_print_znode_setattr(buf); 283 } 284 285 static void 286 zev_print_event(char *buf, int len) 287 { 288 int record_len; 289 int op; 290 291 record_len = *(uint32_t *)buf; 292 if (record_len != len) { 293 fprintf(stderr, "record length mismatch: got %d, expected %d\n", 294 record_len, len); 295 exit(1); 296 } 297 op = *((uint32_t *)buf + 1); 298 if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) { 299 fprintf(stderr, "unknown op code: %d\n", op); 300 exit(1); 301 } 302 switch (op) { 303 case ZEV_OP_ERROR: 304 zev_print_error(buf); 305 break; 306 case ZEV_OP_ZFS_MOUNT: 307 zev_print_zfs_mount(buf); 308 break; 309 case ZEV_OP_ZFS_UMOUNT: 310 zev_print_zfs_umount(buf); 311 break; 312 case ZEV_OP_ZVOL_TRUNCATE: 313 zev_print_zvol_truncate(buf); 314 break; 315 case ZEV_OP_ZVOL_WRITE: 316 zev_print_zvol_write(buf); 317 break; 318 case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE: 319 zev_print_znode_close_after_update(buf); 320 break; 321 case ZEV_OP_ZNODE_CREATE: 322 zev_print_znode_create(buf); 323 break; 324 case ZEV_OP_ZNODE_MKDIR: 325 zev_print_znode_mkdir(buf); 326 break; 327 case ZEV_OP_ZNODE_MAKE_XATTR_DIR: 328 zev_print_znode_make_xattr_dir(buf); 329 break; 330 case ZEV_OP_ZNODE_REMOVE: 331 zev_print_znode_remove(buf); 332 break; 333 case ZEV_OP_ZNODE_RMDIR: 334 zev_print_znode_rmdir(buf); 335 break; 336 case ZEV_OP_ZNODE_LINK: 337 zev_print_znode_link(buf); 338 break; 339 case ZEV_OP_ZNODE_SYMLINK: 340 zev_print_znode_symlink(buf); 341 break; 342 case ZEV_OP_ZNODE_RENAME: 343 zev_print_znode_rename(buf); 344 break; 345 case ZEV_OP_ZNODE_WRITE: 346 zev_print_znode_write(buf); 347 break; 348 case ZEV_OP_ZNODE_TRUNCATE: 349 zev_print_znode_truncate(buf); 350 break; 351 case ZEV_OP_ZNODE_SETATTR: 352 zev_print_znode_setattr(buf); 353 break; 354 case ZEV_OP_ZNODE_ACL: 355 zev_print_znode_acl(buf); 356 break; 357 default: 358 fprintf(stderr, "unhandled op code: %d\n", op); 359 exit(1); 360 } 361 } 362 363 static void 364 zev_poll_events(int fd) 365 { 366 struct pollfd pfd[1]; 367 int ret; 368 char buf[4096]; 369 zev_event_t *ev; 370 int off = 0; 371 while (1) { 372 pfd[0].fd = fd; 373 pfd[0].events = POLLIN; 374 ret = poll(pfd, 1, 1000); 375 if (ret < 0) { 376 perror("poll failed"); 377 exit(EXIT_FAILURE); 378 } 379 if (!(pfd[0].revents & POLLIN)) 380 continue; 381 /* data available */ 382 ret = read(fd, buf, sizeof(buf)); 383 if (ret < 0) { 384 perror("read failed"); 385 exit(EXIT_FAILURE); 386 } 387 if (ret == 0) 388 continue; 389 while (ret > off) { 390 ev = (zev_event_t *)(buf + off); 391 zev_print_event(buf + off, ev->header.record_len); 392 off += ev->header.record_len; 393 } 394 off = 0; 395 } 396 return; 397 } 398 399 static void 400 usage(char *progname) 401 { 402 fprintf(stderr, "usage: %s [-s] [-d <dev>]\n", progname); 403 fprintf(stderr, " -s show zev statistics\n"); 404 fprintf(stderr, " -p poll for ZFS events\n"); 405 fprintf(stderr, " -q <bytes> set maximum event queue length\n"); 406 fprintf(stderr, " -t <bytes> set queue length poll throttle\n"); 407 fprintf(stderr, " -m <pool> mute pool, no events for this pool\n"); 408 fprintf(stderr, " -M <pool> unmute pool\n"); 409 fprintf(stderr, " -d <dev> device file to use. default is '%s'\n", 410 ZEV_DEVICE); 411 exit (EXIT_FAILURE); 412 } 413 414 static int 415 zev_set_max_queue_len(int fd, char *optarg) 416 { 417 uint64_t maxqueuelen; 418 419 errno = 0; 420 maxqueuelen = strtol(optarg, (char **)NULL, 10); 421 if (errno) { 422 fprintf(stderr, "invalid queue length parameter: %s\n", optarg); 423 return (EXIT_FAILURE); 424 } 425 if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) { 426 perror("setting max queue length failed"); 427 return (EXIT_FAILURE); 428 } 429 return (0); 430 } 431 432 static int 433 zev_set_poll_wakeup_queue_len(int fd, char *optarg) 434 { 435 uint64_t queuelen; 436 437 errno = 0; 438 queuelen = strtol(optarg, (char **)NULL, 10); 439 if (errno) { 440 fprintf(stderr, "invalid queue length parameter: %s\n", optarg); 441 return (EXIT_FAILURE); 442 } 443 if (ioctl(fd, ZEV_IOC_SET_POLL_WAKEUP_QUEUE_LEN, &queuelen)) { 444 perror("setting poll wakeup queue length failed"); 445 return (EXIT_FAILURE); 446 } 447 return (0); 448 } 449 450 static int 451 zev_mute_unmute_impl(int fd, char *poolname, int mute) 452 { 453 zev_ioctl_poolarg_t pa; 454 int len; 455 int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL; 456 len = strlen(poolname); 457 if (len <= 0 || len >= sizeof(pa.zev_poolname)) { 458 fprintf(stderr, "invalid poolname: %s\n", poolname); 459 return (EXIT_FAILURE); 460 } 461 strcpy(pa.zev_poolname, poolname); 462 pa.zev_poolname_len = len; 463 if (ioctl(fd, op, &pa)) { 464 perror("muting pool data failed"); 465 return (EXIT_FAILURE); 466 } 467 return (0); 468 } 469 470 int 471 zev_mute_pool(int fd, char *poolname) 472 { 473 return zev_mute_unmute_impl(fd, poolname, 1); 474 } 475 476 int 477 zev_unmute_pool(int fd, char *poolname) 478 { 479 return zev_mute_unmute_impl(fd, poolname, 0); 480 } 481 482 int 483 main(int argc, char **argv) 484 { 485 int fd; 486 int c; 487 int ops = 0; 488 extern char *optarg; 489 490 /* open device */ 491 fd = open(zev_device, O_RDONLY); 492 if (fd < 0) { 493 perror("opening zev device failed"); 494 return EXIT_FAILURE; 495 } 496 while ((c = getopt(argc, argv, "spdq:t:m:M:h?")) != -1) { 497 switch(c) { 498 case 's': 499 ops |= OP_STATISTICS; 500 break; 501 case 'p': 502 ops |= OP_POLL_EVENTS; 503 break; 504 case 'd': 505 zev_device = optarg; 506 break; 507 case 'q': 508 return zev_set_max_queue_len(fd, optarg); 509 case 't': 510 return zev_set_poll_wakeup_queue_len(fd, optarg); 511 case 'm': 512 return zev_mute_pool(fd, optarg); 513 case 'M': 514 return zev_unmute_pool(fd, optarg); 515 case 'h': 516 case '?': 517 default: 518 usage(argv[0]); 519 } 520 } 521 if (!ops) 522 usage(argv[0]); 523 if (ops & OP_STATISTICS) 524 zev_statistics(fd); 525 if (ops & OP_POLL_EVENTS) 526 zev_poll_events(fd); 527 close(fd); 528 return EXIT_SUCCESS; 529 } 530 531