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