xref: /titanic_51/usr/src/cmd/zevadm/zevadm.c (revision 443f0cd248340bfc3902f473d869ff9e472d2ff8)
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 		zev_print_inode_info("srcdir", &rec->srcdir);
484 		zev_print_inode_info("dstdir", &rec->dstdir);
485 		znl();
486 	} else {
487 		printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu "
488 		       "file=%llu.%llu file.mtime=%llu, file.ctime=%llu, "
489 		       "srcdir.mtime=%llu, srcdir.ctime=%llu, "
490 		       "dstdir.mtime=%llu, dstdir.ctime=%llu, "
491 		       "srcname='%s' dstname='%s'\n",
492 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
493 		       rec->srcdir.ino, rec->srcdir.gen,
494 		       rec->dstdir.ino, rec->dstdir.gen,
495 		       rec->file.ino, rec->file.gen,
496 		       rec->file.mtime, rec->file.ctime,
497 		       rec->srcdir.mtime, rec->srcdir.ctime,
498 		       rec->dstdir.mtime, rec->dstdir.ctime,
499 		       ZEV_SRCNAME(rec),
500 		       ZEV_DSTNAME(rec));
501 	}
502 }
503 
504 static void
505 zev_print_znode_write(char *buf)
506 {
507 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
508 	time_t op_time = rec->op_time;
509 	char *ct = ctime(&op_time); ct[24] = '\0';
510 	zev_sig_t *sig;
511 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
512 	int i;
513 
514 	if (verbose) {
515 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
516 		zpf("  guid: %llu", rec->guid);
517 		zpf("  txg: %llu", rec->txg);
518 		zpf("  offset: %llu", rec->offset);
519 		zpf("  length: %llu", rec->length);
520 		zev_print_inode_info("file", &rec->file);
521 		znl();
522 		for (i=0; i<rec->signature_cnt; i++) {
523 			sig = (zev_sig_t *)ZEV_SIGNATURES(rec);
524 			sig += i;
525 			sig2hex_direct(sig->value, sigval);
526 			zpf("  sig: level %d, offset %llu, value %s",
527 			    sig->level, sig->block_offset, sigval);
528 		}
529 	} else {
530 		printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
531 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
532 		       rec->file.ino, rec->file.gen,
533 		       rec->offset, rec->length);
534 	}
535 }
536 
537 static void
538 zev_print_znode_truncate(char *buf)
539 {
540 	zev_print_znode_write(buf);
541 }
542 
543 static void
544 zev_print_znode_setattr(char *buf)
545 {
546 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
547 	time_t op_time = rec->op_time;
548 	char *ct = ctime(&op_time); ct[24] = '\0';
549 
550 	if (verbose) {
551 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
552 		zpf("  guid: %llu", rec->guid);
553 		zpf("  txg: %llu", rec->txg);
554 		zev_print_inode_info("file", &rec->file);
555 		znl();
556 	} else {
557 		printf("%s %s: file=%llu.%llu mtime=%llu\n",
558 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
559 		       rec->file.ino, rec->file.gen, rec->file.mtime);
560 	}
561 }
562 
563 static void
564 zev_print_znode_acl(char *buf)
565 {
566 	zev_print_znode_setattr(buf);
567 }
568 
569 static void
570 zev_print_event(char *buf, int len)
571 {
572 	int record_len;
573 	int op;
574 
575 	record_len = *(uint32_t *)buf;
576 	if (record_len != len) {
577 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
578 		        record_len, len);
579 		exit(1);
580 	}
581 	op = *((uint32_t *)buf + 1);
582 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
583 		fprintf(stderr, "unknown op code: %d\n", op);
584 		exit(1);
585 	}
586 	switch (op) {
587 	case ZEV_OP_ERROR:
588 		zev_print_error(buf);
589 		break;
590 	case ZEV_OP_MARK:
591 		zev_print_mark(buf);
592 		break;
593 	case ZEV_OP_ZFS_MOUNT:
594 		zev_print_zfs_mount(buf);
595 		break;
596 	case ZEV_OP_ZFS_UMOUNT:
597 		zev_print_zfs_umount(buf);
598 		break;
599 	case ZEV_OP_ZVOL_TRUNCATE:
600 		zev_print_zvol_truncate(buf);
601 		break;
602 	case ZEV_OP_ZVOL_WRITE:
603 		zev_print_zvol_write(buf);
604 		break;
605 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
606 		zev_print_znode_close_after_update(buf);
607 		break;
608 	case ZEV_OP_ZNODE_CREATE:
609 		zev_print_znode_create(buf);
610 		break;
611 	case ZEV_OP_ZNODE_MKDIR:
612 		zev_print_znode_mkdir(buf);
613 		break;
614 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
615 		zev_print_znode_make_xattr_dir(buf);
616 		break;
617 	case ZEV_OP_ZNODE_REMOVE:
618 		zev_print_znode_remove(buf);
619 		break;
620 	case ZEV_OP_ZNODE_RMDIR:
621 		zev_print_znode_rmdir(buf);
622 		break;
623 	case ZEV_OP_ZNODE_LINK:
624 		zev_print_znode_link(buf);
625 		break;
626 	case ZEV_OP_ZNODE_SYMLINK:
627 		zev_print_znode_symlink(buf);
628 		break;
629 	case ZEV_OP_ZNODE_RENAME:
630 		zev_print_znode_rename(buf);
631 		break;
632 	case ZEV_OP_ZNODE_WRITE:
633 		zev_print_znode_write(buf);
634 		break;
635 	case ZEV_OP_ZNODE_TRUNCATE:
636 		zev_print_znode_truncate(buf);
637 		break;
638 	case ZEV_OP_ZNODE_SETATTR:
639 		zev_print_znode_setattr(buf);
640 		break;
641 	case ZEV_OP_ZNODE_ACL:
642 		zev_print_znode_acl(buf);
643 		break;
644 	default:
645 		fprintf(stderr, "unhandled op code: %d\n", op);
646 		exit(1);
647 	}
648 }
649 
650 static int
651 zev_poll_events(int fd, int create_tmp_queue)
652 {
653 	struct pollfd pfd[1];
654 	int ret;
655 	char buf[4096];
656 	zev_event_t *ev;
657 	int off = 0;
658 	zev_ioctl_add_queue_t aq;
659 	int q_fd;
660 
661 	if (create_tmp_queue) {
662 		aq.zev_max_queue_len = 0;
663 		aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
664 		snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
665 			 "zevadm.%ld.%ld", time(NULL), getpid());
666 		aq.zev_namelen = strlen(aq.zev_name);
667 
668 		if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
669 			perror("adding temporary queue failed");
670 			return (EXIT_FAILURE);
671 		}
672 
673 		snprintf(buf, sizeof(buf),
674 		         "/devices/pseudo/zev@0:%s", aq.zev_name);
675 		q_fd = open(buf, O_RDONLY);
676 		if (q_fd < 0) {
677 			perror("opening queue device failed");
678 			return (EXIT_FAILURE);
679 		}
680 	} else {
681 		q_fd = fd;
682 	}
683 
684 	while (1) {
685 		pfd[0].fd = q_fd;
686 		pfd[0].events = POLLIN;
687 		ret = poll(pfd, 1, 1000);
688 		if (ret < 0) {
689 			perror("poll failed");
690 			close(q_fd);
691 			return(EXIT_FAILURE);
692 		}
693 		if (!(pfd[0].revents & POLLIN))
694 			continue;
695 		/* data available */
696 		ret = read(q_fd, buf, sizeof(buf));
697 		if (ret < 0) {
698 			perror("read failed");
699 			close(q_fd);
700 			return(EXIT_FAILURE);
701 		}
702 		if (ret == 0)
703 			continue;
704 		while (ret > off) {
705 			ev = (zev_event_t *)(buf + off);
706 			zev_print_event(buf + off, ev->header.record_len);
707 			off += ev->header.record_len;
708 		}
709 		off = 0;
710 	}
711 	if (create_tmp_queue)
712 		close(q_fd);
713 	return EXIT_SUCCESS;
714 }
715 
716 static void
717 usage(char *progname)
718 {
719 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
720 	fprintf(stderr, "\n");
721 	fprintf(stderr, " Status information:\n");
722 	fprintf(stderr, "   -s                   show zev statistics\n");
723 	fprintf(stderr, "   -p                   poll for ZFS events\n");
724 	fprintf(stderr, "   -D                   print zev module debug "
725 	        "information\n");
726 	fprintf(stderr, "   -T <interval> <cnt>  zevstat mode\n");
727 	fprintf(stderr, "   -R <base filename>   zevreport mode\n");
728 	fprintf(stderr, "\n");
729 	fprintf(stderr, " Tune zev module settings:\n");
730 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
731 	        "length\n");
732 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
733 	        "this pool\n");
734 	fprintf(stderr, "   -M <pool>            unmute pool\n");
735 	fprintf(stderr, "\n");
736 	fprintf(stderr, " Queue management:\n");
737 	fprintf(stderr, "   -l                   list queues\n");
738 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
739 	fprintf(stderr, "   -A <name>            add blocking queue\n");
740 	fprintf(stderr, "   -r <name>            remove queue\n");
741 	fprintf(stderr, "   -b <name>            make queue non-blocking "
742 	        "(default)\n");
743 	fprintf(stderr, "   -B <name>            make queue block when full\n");
744 	fprintf(stderr, "   -P <name>            display queue properties\n");
745 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
746 	        "length\n");
747 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
748 	        "throttle\n");
749 	fprintf(stderr, "\n");
750 	fprintf(stderr, " Other options:\n");
751 	fprintf(stderr, "   -d <dev>             non-default device file. "
752 	        "('%s')\n", ZEV_DEVICE);
753 	fprintf(stderr, "   -q <name>            use device file for this "
754 		"queue name\n");
755 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
756 	fprintf(stderr, "   -c <filename>        list file's content "
757 		"checksums\n");
758 	fprintf(stderr, "   -v                   verbose: additional output "
759 	        "for some operations\n");
760 	fprintf(stderr, "   -g                   grep-friendly event output, "
761 	        "one event per line\n");
762 	exit (EXIT_FAILURE);
763 }
764 
765 static void
766 zevstat_usage(char *progname)
767 {
768 	fprintf(stderr, "usage: %s [-v] <interval> [count]\n", progname);
769 	fprintf(stderr, "   -v   verbose, show counters for all event types\n");
770 	exit (EXIT_FAILURE);
771 }
772 
773 static void
774 zevreport_usage(char *progname)
775 {
776 	fprintf(stderr, "usage: %s <output base filename>\n", progname);
777 	exit (EXIT_FAILURE);
778 }
779 
780 static int
781 zev_add_queue(int fd, char *arg, int blocking)
782 {
783 	zev_ioctl_add_queue_t aq;
784 	int namelen;
785 
786 	namelen = strlen(arg);
787 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
788 		fprintf(stderr, "queue name too long: %s\n", arg);
789 		return (EXIT_FAILURE);
790 	}
791 
792 	aq.zev_namelen = namelen;
793 	strcpy(aq.zev_name, arg);
794 	aq.zev_flags = ZEV_FL_PERSISTENT | ZEV_FL_INITIALLY_EMPTY;
795 	if (blocking) {
796 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
797 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
798 	} else {
799 		aq.zev_max_queue_len = (1024 * 1024);
800 	}
801 
802 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
803 		perror("adding queue failed");
804 		return (EXIT_FAILURE);
805 	}
806 	return (0);
807 }
808 
809 static int
810 zev_remove_queue(int fd, char *arg)
811 {
812 	zev_ioctl_remove_queue_t aq;
813 	int namelen;
814 
815 	namelen = strlen(arg);
816 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
817 		fprintf(stderr, "queue name too long: %s\n", arg);
818 		return (EXIT_FAILURE);
819 	}
820 
821 	aq.zev_queue_name.zev_namelen = namelen;
822 	strcpy(aq.zev_queue_name.zev_name, arg);
823 
824 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
825 		perror("removing queue failed");
826 		return (EXIT_FAILURE);
827 	}
828 	return (0);
829 }
830 
831 static int
832 zev_set_global_max_queue_len(int fd, char *arg)
833 {
834 	uint64_t maxqueuelen;
835 
836 	if (!arg) {
837 		fprintf(stderr, "missing queue length parameter\n");
838 		return (EXIT_FAILURE);
839 	}
840 
841 	errno = 0;
842 	maxqueuelen = strtol(arg, (char **)NULL, 10);
843 	if (errno) {
844 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
845 		return (EXIT_FAILURE);
846 	}
847 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
848 		perror("setting max queue length failed");
849 		return (EXIT_FAILURE);
850 	}
851 	return (0);
852 }
853 
854 static int
855 zev_mute_unmute_impl(int fd, char *poolname, int mute)
856 {
857 	zev_ioctl_poolarg_t pa;
858 	int len;
859 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
860 	len = strlen(poolname);
861 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
862 		fprintf(stderr, "invalid poolname: %s\n", poolname);
863 		return (EXIT_FAILURE);
864 	}
865 	strcpy(pa.zev_poolname, poolname);
866 	pa.zev_poolname_len = len;
867 	if (ioctl(fd, op, &pa)) {
868 		perror("muting pool data failed");
869 		return (EXIT_FAILURE);
870 	}
871 	return (0);
872 }
873 
874 int
875 zev_mute_pool(int fd, char *poolname)
876 {
877 	return zev_mute_unmute_impl(fd, poolname, 1);
878 }
879 
880 int
881 zev_unmute_pool(int fd, char *poolname)
882 {
883 	return zev_mute_unmute_impl(fd, poolname, 0);
884 }
885 
886 static int
887 zev_debug_info(int fd)
888 {
889 	zev_ioctl_debug_info_t di;
890 
891 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
892 		perror("getting zev debug info failed");
893 		return (EXIT_FAILURE);
894 	}
895 
896 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
897 	printf("checksum cache size: %llu\n", di.zev_chksum_cache_size);
898 	printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits);
899 	printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses);
900 	return 0;
901 }
902 
903 static int
904 zev_mark(int fd, char *arg)
905 {
906 	zev_ioctl_mark_t *mark;
907 	uint64_t guid;
908 	int len;
909 	char *p;
910 
911 	p = strchr(arg, ':');
912 	if (!p) {
913 		fprintf(stderr, "expected value is <guid>:<payload>, "
914 		        "e.g. '123:hello'\n");
915 		exit (EXIT_FAILURE);
916 	}
917 	*p = '\n';
918 	p++;
919 
920 	errno = 0;
921 	guid = strtoll(arg, (char **)NULL, 10);
922 	if (errno) {
923 		fprintf(stderr, "guid must be a number.\n");
924 		exit (EXIT_FAILURE);
925 	}
926 
927 	len = strlen(p);
928 
929 	mark = malloc(sizeof(*mark) + len + 1);
930 	if (!mark) {
931 		fprintf(stderr, "can't allocate mark structure: %s\n",
932 		        strerror(errno));
933 		exit (EXIT_FAILURE);
934 	}
935 	mark->zev_guid = guid;
936 	mark->zev_mark_id = 0;
937 	mark->zev_payload_len = len;
938 	strcpy(ZEV_PAYLOAD(mark), p);
939 
940 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
941 		perror("queueing mark failed");
942 		return (EXIT_FAILURE);
943 	}
944 
945 	printf("mark id: %lu\n", mark->zev_mark_id);
946 	return (0);
947 }
948 
949 static int
950 zev_queue_blocking(int fd, char *arg, int block)
951 {
952 	zev_ioctl_get_queue_properties_t gqp;
953 
954 	gqp.zev_queue_name.zev_namelen = strlen(arg);
955 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
956 		fprintf(stderr, "queue name too long.\n");
957 		return EXIT_FAILURE;
958 	}
959 	strcpy(gqp.zev_queue_name.zev_name, arg);
960 
961 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
962 		perror("getting queue properties failed");
963 		return (EXIT_FAILURE);
964 	}
965 	if (block) {
966 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
967 	} else {
968 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
969 	}
970 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
971 		perror("setting queue properties failed");
972 		return (EXIT_FAILURE);
973 	}
974 	return (0);
975 }
976 
977 static int
978 zev_set_max_queue_len(int fd, char *arg, char *len)
979 {
980 	zev_ioctl_get_queue_properties_t gqp;
981 
982 	if (!len) {
983 		fprintf(stderr, "queue size parameter missing.\n");
984 		return EXIT_FAILURE;
985 	}
986 
987 	gqp.zev_queue_name.zev_namelen = strlen(arg);
988 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
989 		fprintf(stderr, "queue name too long.\n");
990 		return EXIT_FAILURE;
991 	}
992 	strcpy(gqp.zev_queue_name.zev_name, arg);
993 
994 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
995 		perror("getting queue properties failed");
996 		return (EXIT_FAILURE);
997 	}
998 	gqp.zev_max_queue_len = atol(len);
999 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
1000 		fprintf(stderr, "queue size parameter garbled.\n");
1001 		return (EXIT_FAILURE);
1002 	}
1003 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
1004 		fprintf(stderr, "queue size parameter out of bounds.\n");
1005 		return (EXIT_FAILURE);
1006 	}
1007 
1008 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
1009 		perror("setting queue properties failed");
1010 		return (EXIT_FAILURE);
1011 	}
1012 	return (0);
1013 }
1014 
1015 static int
1016 zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
1017 {
1018 	zev_ioctl_get_queue_properties_t gqp;
1019 
1020 	if (!len) {
1021 		fprintf(stderr, "poll throttle parameter missing.\n");
1022 		return EXIT_FAILURE;
1023 	}
1024 
1025 	gqp.zev_queue_name.zev_namelen = strlen(arg);
1026 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1027 		fprintf(stderr, "queue name too long.\n");
1028 		return EXIT_FAILURE;
1029 	}
1030 	strcpy(gqp.zev_queue_name.zev_name, arg);
1031 
1032 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1033 		perror("getting queue properties failed");
1034 		return (EXIT_FAILURE);
1035 	}
1036 	gqp.zev_poll_wakeup_threshold = atol(len);
1037 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
1038 		fprintf(stderr, "poll throttle parameter garbled.\n");
1039 		return (EXIT_FAILURE);
1040 	}
1041 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
1042 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
1043 		return (EXIT_FAILURE);
1044 	}
1045 
1046 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
1047 		perror("setting queue properties failed");
1048 		return (EXIT_FAILURE);
1049 	}
1050 	return (0);
1051 }
1052 
1053 static int
1054 zev_queue_properties(int fd, char *arg)
1055 {
1056 	zev_ioctl_get_queue_properties_t gqp;
1057 
1058 	gqp.zev_queue_name.zev_namelen = strlen(arg);
1059 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1060 		fprintf(stderr, "queue name too long.\n");
1061 		return EXIT_FAILURE;
1062 	}
1063 	strcpy(gqp.zev_queue_name.zev_name, arg);
1064 
1065 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1066 		perror("getting queue properties failed");
1067 		return (EXIT_FAILURE);
1068 	}
1069 
1070 	printf("queue        : %s\n", arg);
1071 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
1072 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
1073 	printf("persistent   : %s\n",
1074 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
1075 	printf("blocking     : %s\n",
1076 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
1077 
1078 	return (0);
1079 }
1080 
1081 static int
1082 zev_list_queues(int fd)
1083 {
1084 	zev_ioctl_get_queue_properties_t gqp;
1085 	zev_ioctl_get_queue_list_t gql;
1086 	zev_ioctl_get_queue_statistics_t gs;
1087 	uint64_t	i;
1088 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
1089 
1090 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
1091 		perror("getting queue list failed");
1092 		return (EXIT_FAILURE);
1093 	}
1094 
1095 	printf("Name                                     Size       "
1096 	       "Max Size   Wakeup Per Block\n");
1097 
1098 	for (i=0; i<gql.zev_n_queues; i++) {
1099 		strncpy(name, gql.zev_queue_name[i].zev_name,
1100 		        ZEV_MAX_QUEUE_NAME_LEN);
1101 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
1102 
1103 		memcpy(gqp.zev_queue_name.zev_name,
1104 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
1105 		gqp.zev_queue_name.zev_namelen =
1106 		    gql.zev_queue_name[i].zev_namelen;
1107 
1108 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1109 			if (errno == ENOENT)
1110 				continue;
1111 			perror("getting queue properties failed");
1112 			return (EXIT_FAILURE);
1113 		}
1114 
1115 		memcpy(gs.zev_queue_name.zev_name,
1116 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
1117 		gs.zev_queue_name.zev_namelen =
1118 		    gql.zev_queue_name[i].zev_namelen;
1119 
1120 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
1121 			if (errno == ENOENT)
1122 				continue;
1123 			perror("getting statistics data failed");
1124 			return (EXIT_FAILURE);
1125 		}
1126 
1127 		printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64
1128 		       " %-3s %-3s\n",
1129 			name,
1130 			gs.zev_statistics.zev_queue_len,
1131 			gqp.zev_max_queue_len,
1132 			gqp.zev_poll_wakeup_threshold,
1133 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
1134 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
1135 				 "yes" : "no");
1136 	}
1137 
1138 	return (0);
1139 }
1140 
1141 static int
1142 zev_checksum(int dev_fd, char *filename)
1143 {
1144 	int fd;
1145 	offset_t off;
1146 	offset_t data;
1147 	zev_sig_t *sig;
1148 	char *buf;
1149 	zev_ioctl_get_signatures_t *gs;
1150 	int i;
1151 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
1152 	int buf_size;
1153 
1154 	/* control struct, one lv1 signature and up to 256 lv0 signatures */
1155 	buf_size = (1 + 256) * sizeof(zev_sig_t);
1156 	buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size);
1157 	if (!buf) {
1158 		perror("can't allocate checksum buffer");
1159 		return (EXIT_FAILURE);
1160 	}
1161 
1162 	fd = open(filename, O_RDONLY);
1163 	if (fd < 0) {
1164 		perror("can't open file");
1165 		return (EXIT_FAILURE);
1166 	}
1167 
1168 	gs = (zev_ioctl_get_signatures_t *)buf;
1169 	gs->zev_fd = fd;
1170 	gs->zev_bufsize = buf_size;
1171 
1172 	off = 0;
1173 	data = 0;
1174 	while (1) {
1175 		errno = 0;
1176 		data = llseek(fd, off, SEEK_DATA);
1177 		if (data < 0) {
1178 			if (errno == ENXIO)	/* no more data */
1179 				break;
1180 			perror("llseek failed");
1181 			goto err;
1182 		}
1183 		data = P2ALIGN(data, ZEV_L1_SIZE);
1184 		off = data + ZEV_L1_SIZE;
1185 
1186 		gs->zev_offset = data;
1187 		gs->zev_len = ZEV_L1_SIZE;
1188 
1189 		if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) {
1190 			perror("ioctl to get signatures failed");
1191 			goto err;
1192 		}
1193 
1194 		for (i=0; i<gs->zev_signature_cnt; i++) {
1195 			sig = (zev_sig_t *)ZEV_SIGNATURES(gs);
1196 			sig += i;
1197 			sig2hex_direct(sig->value, sigval);
1198 			printf("level %d, offset %llu, value %s\n",
1199 			       sig->level, sig->block_offset, sigval);
1200 		}
1201 	}
1202 
1203 	free(buf);
1204 	close(fd);
1205 	return 0;
1206 err:
1207 	free(buf);
1208 	close(fd);
1209 	return (EXIT_FAILURE);
1210 }
1211 
1212 typedef struct zevstat {
1213 	uint64_t	ns_start;
1214 	uint64_t	events[ZEV_OP_MIN + ZEV_OP_MAX];
1215 	uint64_t	guids;
1216 	uint64_t	total_events;
1217 	uint64_t	total_guids;
1218 	avl_tree_t	guids_interval;
1219 	avl_tree_t	guids_runtime;
1220 } zevstat_t;
1221 
1222 typedef struct zev_guidtrack_t {
1223 	uint64_t	guid;
1224 	avl_node_t	avl_interval;
1225 	avl_node_t	avl_runtime;
1226 } zev_guidtrack_t;
1227 
1228 zevstat_t zevstat;
1229 
1230 static void
1231 zev_eventstat(char *buf, int len)
1232 {
1233 	zev_header_t *rec = (zev_header_t *)buf;
1234 	zev_guidtrack_t *gt;
1235 	zev_guidtrack_t *gt_int;
1236 	zev_guidtrack_t to_find;
1237 	avl_index_t where;
1238 
1239 	zevstat.total_events++;
1240 	zevstat.events[rec->op]++;
1241 
1242 	to_find.guid = rec->guid;
1243 	gt = avl_find(&zevstat.guids_runtime, &to_find, &where);
1244 	if (!gt) {
1245 		gt = malloc(sizeof(*gt));
1246 		if (!gt) {
1247 			perror("can't get guid tracking record");
1248 			exit (EXIT_FAILURE);
1249 		}
1250 		gt->guid = rec->guid;
1251 		avl_insert(&zevstat.guids_runtime, gt, where);
1252 	}
1253 	gt_int = avl_find(&zevstat.guids_interval, &to_find, &where);
1254 	if (!gt_int)
1255 		avl_insert(&zevstat.guids_interval, gt, where);
1256 }
1257 
1258 static void
1259 zev_eventstat_interval(FILE *out)
1260 {
1261 	uint64_t events;
1262 	int i;
1263 	zev_guidtrack_t *gt;
1264 
1265 	events = 0;
1266 	for (i = ZEV_OP_MIN; i <= ZEV_OP_MAX; i++) {
1267 		events += zevstat.events[i];
1268 	}
1269 
1270 	if (verbose) {
1271 		fprintf(out, "%u  %6llu  %6llu %6llu %6llu  ",
1272 		        time(NULL),
1273 		        events,
1274 		        zevstat.total_events,
1275 		        avl_numnodes(&zevstat.guids_interval),
1276 		        avl_numnodes(&zevstat.guids_runtime));
1277 		for (i = ZEV_OP_MIN; i <= ZEV_OP_MAX; i++)
1278 			fprintf(out, "%6llu ", zevstat.events[i]);
1279 		fprintf(out, "\n");
1280 	} else {
1281 		fprintf(out, "%u  %6llu  %6llu %6llu %6llu\n",
1282 		        time(NULL),
1283 		        events,
1284 		        zevstat.total_events,
1285 		        avl_numnodes(&zevstat.guids_interval),
1286 		        avl_numnodes(&zevstat.guids_runtime));
1287 	}
1288 	memset(&zevstat.events, 0, sizeof(zevstat.events));
1289 	zevstat.guids = 0;
1290 	while (gt = avl_first(&zevstat.guids_interval))
1291 		avl_remove(&zevstat.guids_interval, gt);
1292 	fflush(out);
1293 }
1294 
1295 static int
1296 zev_evcompar(const void *a, const void *b)
1297 {
1298 	const zev_guidtrack_t *ga = a;
1299 	const zev_guidtrack_t *gb = b;
1300 
1301 	if (ga->guid > gb->guid)
1302 		return 1;
1303 	if (ga->guid < gb->guid)
1304 		return -1;
1305 	return 0;
1306 }
1307 
1308 static int
1309 zev_zevstat(int fd, char *s_interval, char *s_count, char *outfile)
1310 {
1311 	uint64_t interval = 1000;
1312 	uint64_t ms;
1313 	uint64_t t_until;
1314 	uint64_t t_now;
1315 	int cnt = -1;
1316 	struct pollfd pfd[1];
1317 	int ret;
1318 	char buf[4096];
1319 	zev_event_t *ev;
1320 	int off = 0;
1321 	zev_ioctl_add_queue_t aq;
1322 	int q_fd;
1323 	zev_guidtrack_t *gt;
1324 	FILE *out = stdout;
1325 	struct stat st;
1326 	char filename[MAXPATHLEN];
1327 	int retry;
1328 
1329 	if (outfile) {
1330 		retry = 0;
1331 		strncpy(filename, outfile, sizeof(filename));
1332 		while (stat(filename, &st) == 0) {
1333 			/* file exists */
1334 			snprintf(filename, sizeof(filename),
1335 			         "%s.%d", outfile, retry);
1336 			retry++;
1337 		}
1338 		out = fopen(filename, "wb+");
1339 		if (!out) {
1340 			perror("opening output file failed");
1341 			return (EXIT_FAILURE);
1342 		}
1343 	}
1344 
1345 	memset(&zevstat, 0, sizeof(zevstat));
1346 	avl_create(&zevstat.guids_runtime, zev_evcompar,
1347 	           sizeof(zev_guidtrack_t),
1348 	           offsetof(zev_guidtrack_t, avl_runtime));
1349 	avl_create(&zevstat.guids_interval, zev_evcompar,
1350 	           sizeof(zev_guidtrack_t),
1351 	           offsetof(zev_guidtrack_t, avl_interval));
1352 
1353 	if (s_interval) {
1354 		interval = atol(s_interval);
1355 		if (interval == 0) {
1356 			fprintf(stderr, "invalid interval.\n");
1357 			return (EXIT_FAILURE);
1358 		}
1359 		interval *= 1000;
1360 	}
1361 	if (s_count) {
1362 		cnt = atol(s_count);
1363 		if (interval == 0) {
1364 			fprintf(stderr, "invalid count.\n");
1365 			return (EXIT_FAILURE);
1366 		}
1367 	}
1368 
1369 	aq.zev_max_queue_len = 1024 * 1024;
1370 	aq.zev_flags = ZEV_FL_INITIALLY_EMPTY;
1371 	snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
1372 		 "zevstat.%ld.%ld", time(NULL), getpid());
1373 	aq.zev_namelen = strlen(aq.zev_name);
1374 
1375 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
1376 		perror("adding temporary queue failed");
1377 		return (EXIT_FAILURE);
1378 	}
1379 
1380 	snprintf(buf, sizeof(buf),
1381 		 "/devices/pseudo/zev@0:%s", aq.zev_name);
1382 	q_fd = open(buf, O_RDONLY);
1383 	if (q_fd < 0) {
1384 		perror("opening queue device failed");
1385 		return (EXIT_FAILURE);
1386 	}
1387 
1388 	pfd[0].fd = q_fd;
1389 	pfd[0].events = POLLIN;
1390 
1391 	/* drain queue */
1392 	while ((ret = poll(pfd, 1, 0)) > 0) {
1393 		if (read(q_fd, buf, sizeof(buf)) < 0) {
1394 			perror("read failed");
1395 			close(q_fd);
1396 			return(EXIT_FAILURE);
1397 		}
1398 	}
1399 	if (ret < 0) {
1400 		perror("poll failed");
1401 		close(q_fd);
1402 		return(EXIT_FAILURE);
1403 	}
1404 
1405 	fprintf(out, "timestamp   events tevents  guids tguids");
1406 	if (verbose) {
1407 		fprintf(out, "   error   mark  mount umount zvol_w ");
1408 		fprintf(out, "zvol_t  close create  mkdir mxattr ");
1409 		fprintf(out, "remove  rmdir   link symlnk rename  ");
1410 		fprintf(out, "write  trunc setatt    acl");
1411 	}
1412 	fprintf(out, "\n");
1413 	while (cnt) {
1414 		t_until = gethrtime() + (interval * 1000000);
1415 		ms = interval;
1416 		do {
1417 			ret = poll(pfd, 1, ms);
1418 			t_now = gethrtime();
1419 			if (t_now < t_until) {
1420 				ms = t_until - t_now;
1421 				ms /= 1000000ull;
1422 			}
1423 			if (ret < 0) {
1424 				perror("poll failed");
1425 				close(q_fd);
1426 				return(EXIT_FAILURE);
1427 			}
1428 			if (!(pfd[0].revents & POLLIN))
1429 				continue;
1430 			/* data available */
1431 			ret = read(q_fd, buf, sizeof(buf));
1432 			if (ret < 0) {
1433 				perror("read failed");
1434 				close(q_fd);
1435 				return(EXIT_FAILURE);
1436 			}
1437 			if (ret == 0)
1438 				continue;
1439 			while (ret > off) {
1440 				ev = (zev_event_t *)(buf + off);
1441 				zev_eventstat(buf + off, ev->header.record_len);
1442 				off += ev->header.record_len;
1443 			}
1444 			off = 0;
1445 		} while ((t_now) < t_until && (ms > 0));
1446 		zev_eventstat_interval(out);
1447 		if (cnt > 0)
1448 			cnt--;
1449 	}
1450 	close(q_fd);
1451 	if (outfile)
1452 		fclose(out);
1453 	while (gt = avl_first(&zevstat.guids_interval))
1454 		avl_remove(&zevstat.guids_interval, gt);
1455 	while (gt = avl_first(&zevstat.guids_runtime)) {
1456 		avl_remove(&zevstat.guids_runtime, gt);
1457 		free(gt);
1458 	}
1459 	return EXIT_SUCCESS;
1460 }
1461 
1462 static int
1463 zev_report(int fd, char *basename)
1464 {
1465 	char filename[MAXPATHLEN];
1466 	char count[10];
1467 	time_t now;
1468 	time_t midnight;
1469 	struct tm tm;
1470 	int minutes;
1471 	int ret;
1472 
1473 	verbose++;
1474 	while (1) {
1475 		now = time(NULL);
1476 		localtime_r(&now, &tm);
1477 		snprintf(filename, sizeof(filename), "%s.%04d-%02d-%02d",
1478 		         basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
1479 		tm.tm_sec = 0;
1480 		tm.tm_min = 0;
1481 		tm.tm_hour = 0;
1482 		tm.tm_mday++;  /* works for Jan 32nd, Feb 30th, etc. */
1483 		midnight = mktime(&tm);
1484 		if (now % 60)
1485 			sleep(60 - (now % 60));
1486 		minutes = (midnight - time(NULL)) / 60;
1487 		snprintf(count, sizeof(count), "%d", minutes);
1488 		ret = zev_zevstat(fd, "60", count, filename);
1489 		if (ret)
1490 			return EXIT_FAILURE;
1491 	}
1492 	return EXIT_SUCCESS; /* never reached */
1493 }
1494 
1495 int
1496 main(int argc, char **argv)
1497 {
1498 	int fd;
1499 	int c;
1500 	extern char *optarg;
1501 	int create_tmp_queue = 1;
1502 	char buf[MAXPATHLEN];
1503 	int mode = 0;
1504 	char *arg = NULL;
1505 	char *arg2 = NULL;
1506 	char *p;
1507 
1508 	/* open device */
1509 	fd = open(zev_device, O_RDONLY);
1510 	if (fd < 0) {
1511 		perror("opening zev device failed");
1512 		return EXIT_FAILURE;
1513 	}
1514 
1515 	p = strrchr(argv[0], '/');
1516 	if (!p) {
1517 		p = argv[0];
1518 	} else {
1519 		p++;
1520 	}
1521 	if (!strcmp(p, "zevstat")) {
1522 		mode = MD_ZEVSTAT;
1523 		if (argc < 2)
1524 			zevstat_usage(argv[0]);
1525 		if (!strcmp(argv[1], "-v")) {
1526 			if (argc < 3)
1527 				zevstat_usage(argv[0]);
1528 			verbose++;
1529 			arg = argv[2];
1530 			arg2 = argv[3];
1531 		} else {
1532 			arg = argv[1];
1533 			arg2 = argv[2];
1534 		}
1535 		return zev_zevstat(fd, arg, arg2, NULL);
1536 	} else if(!strcmp(p, "zevreport")) {
1537 		mode = MD_ZEV_REPORT;
1538 		if (argc != 2)
1539 			zevreport_usage(argv[0]);
1540 		return zev_report(fd, argv[1]);
1541 	}
1542 
1543 	while ((c = getopt(argc, argv,
1544 	                   "gvspc:d:Dlk:L:q:Q:t:m:M:a:A:r:P:b:B:T:R:h?")) != -1){
1545 		switch(c) {
1546 		case 'g':
1547 			grep_friendly++;
1548 			verbose++;
1549 			break;
1550 		case 'v':
1551 			verbose++;
1552 			break;
1553 		case 's':
1554 			mode = MD_STATISTICS;
1555 			break;
1556 		case 'p':
1557 			mode = MD_POLL_EVENTS;
1558 			break;
1559 		case 'c':
1560 			mode = MD_CHECKSUMS;
1561 			arg = optarg;
1562 			break;
1563 		case 'D':
1564 			mode = MD_DEBUG_INFO;
1565 			break;
1566 		case 'd':
1567 			close(fd);
1568 			zev_device = optarg;
1569 			fd = open(zev_device, O_RDONLY);
1570 			if (fd < 0) {
1571 				perror("opening zev device failed");
1572 				return EXIT_FAILURE;
1573 			}
1574 			create_tmp_queue = 0;
1575 			break;
1576 		case 'q':
1577 			snprintf(buf, sizeof(buf),
1578 				 "/devices/pseudo/zev@0:%s", optarg);
1579 			close(fd);
1580 			zev_device = buf;
1581 			fd = open(zev_device, O_RDONLY);
1582 			if (fd < 0) {
1583 				perror("opening zev device failed");
1584 				return EXIT_FAILURE;
1585 			}
1586 			create_tmp_queue = 0;
1587 			break;
1588 		case 'l':
1589 			mode = MD_LIST_QUEUES;
1590 			break;
1591 		case 'Q':
1592 			mode = MD_SET_GLOBAL_MAX_QUEUE_LEN;
1593 			arg = optarg;
1594 			break;
1595 		case 'L':
1596 			mode = MD_SET_MAX_QUEUE_LEN;
1597 			arg = optarg;
1598 			arg2 = argv[optind];
1599 			break;
1600 		case 'T':
1601 			mode = MD_ZEVSTAT;
1602 			arg = optarg;
1603 			arg2 = argv[optind];
1604 			break;
1605 		case 'R':
1606 			mode = MD_ZEV_REPORT;
1607 			arg = optarg;
1608 			break;
1609 		case 't':
1610 			mode = MD_SET_POLL_WAKEUP_QUEUE_LEN;
1611 			arg = optarg;
1612 			arg2 = argv[optind];
1613 			break;
1614 		case 'm':
1615 			mode = MD_MUTE_POOL;
1616 			arg = optarg;
1617 			break;
1618 		case 'M':
1619 			mode = MD_UNMUTE_POOL;
1620 			arg = optarg;
1621 			break;
1622 		case 'k':
1623 			mode = MD_MARK;
1624 			arg = optarg;
1625 			break;
1626 		case 'a':
1627 			mode = MD_ADD_QUEUE;
1628 			arg = optarg;
1629 			break;
1630 		case 'A':
1631 			mode = MD_ADD_BLOCKING_QUEUE;
1632 			arg = optarg;
1633 			break;
1634 		case 'r':
1635 			mode = MD_REMOVE_QUEUE;
1636 			arg = optarg;
1637 			break;
1638 		case 'b':
1639 			mode = MD_QUEUE_BLOCKING;
1640 			arg = optarg;
1641 			break;
1642 		case 'B':
1643 			mode = MD_QUEUE_NONBLOCKING;
1644 			arg = optarg;
1645 			break;
1646 		case 'P':
1647 			mode = MD_QUEUE_PROPERTIES;
1648 			arg = optarg;
1649 			break;
1650 		case 'h':
1651 		case '?':
1652 		default:
1653 			usage(argv[0]);
1654 		}
1655 	}
1656 
1657 	switch (mode) {
1658 	case MD_STATISTICS:
1659 		return zev_statistics(fd);
1660 	case MD_POLL_EVENTS:
1661 		return zev_poll_events(fd, create_tmp_queue);
1662 	case MD_CHECKSUMS:
1663 		return zev_checksum(fd, arg);
1664 	case MD_DEBUG_INFO:
1665 		return zev_debug_info(fd);
1666 	case MD_LIST_QUEUES:
1667 		return zev_list_queues(fd);
1668 	case MD_SET_GLOBAL_MAX_QUEUE_LEN:
1669 		return zev_set_global_max_queue_len(fd, arg);
1670 	case MD_SET_MAX_QUEUE_LEN:
1671 		return zev_set_max_queue_len(fd, arg, arg2);
1672 	case MD_SET_POLL_WAKEUP_QUEUE_LEN:
1673 		return zev_set_poll_wakeup_queue_len(fd, arg, arg2);
1674 	case MD_ZEVSTAT:
1675 		return zev_zevstat(fd, arg, arg2, NULL);
1676 	case MD_ZEV_REPORT:
1677 		return zev_report(fd, arg);
1678 	case MD_MUTE_POOL:
1679 		return zev_mute_pool(fd, arg);
1680 	case MD_UNMUTE_POOL:
1681 		return zev_unmute_pool(fd, arg);
1682 	case MD_MARK:
1683 		return zev_mark(fd, arg);
1684 	case MD_ADD_QUEUE:
1685 		return zev_add_queue(fd, arg, 0);
1686 	case MD_ADD_BLOCKING_QUEUE:
1687 		return zev_add_queue(fd, arg, 1);
1688 	case MD_REMOVE_QUEUE:
1689 		return zev_remove_queue(fd, arg);
1690 	case MD_QUEUE_BLOCKING:
1691 		return zev_queue_blocking(fd, arg, 0);
1692 	case MD_QUEUE_NONBLOCKING:
1693 		return zev_queue_blocking(fd, arg, 1);
1694 	case MD_QUEUE_PROPERTIES:
1695 		return zev_queue_properties(fd, arg);
1696 	default:
1697 		close(fd);
1698 		usage(argv[0]);
1699 		return EXIT_FAILURE;
1700 	};
1701 }
1702 
1703