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