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