xref: /titanic_52/usr/src/cmd/zevadm/zevadm.c (revision 5e28636192c7a7f235ea1e835192fe00d17757cb)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <stropts.h>
6 #include <poll.h>
7 #include <string.h>
8 #include <sys/fs/zev.h>
9 #include <errno.h>
10 
11 #define OP_STATISTICS		(1 << 0)
12 #define OP_POLL_EVENTS		(1 << 1)
13 #define OP_MUTE_POOL		(1 << 2)
14 #define OP_UNMUTE_POOL		(1 << 3)
15 #define OP_SET_MAX_QUEUE_LEN	(1 << 4)
16 #define OP_DEBUG_INFO		(1 << 5)
17 
18 #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl"
19 
20 static char *zev_device = ZEV_DEVICE;
21 
22 static char *zev_op_name[] = {
23 	"ZEV_OP_ERROR",
24 	"ZEV_OP_MARK",
25 	"ZEV_OP_ZFS_MOUNT",
26 	"ZEV_OP_ZFS_UMOUNT",
27 	"ZEV_OP_ZVOL_WRITE",
28 	"ZEV_OP_ZVOL_TRUNCATE",
29 	"ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE",
30 	"ZEV_OP_ZNODE_CREATE",
31 	"ZEV_OP_ZNODE_MKDIR",
32 	"ZEV_OP_ZNODE_MAKE_XATTR_DIR",
33 	"ZEV_OP_ZNODE_REMOVE",
34 	"ZEV_OP_ZNODE_RMDIR",
35 	"ZEV_OP_ZNODE_LINK",
36 	"ZEV_OP_ZNODE_SYMLINK",
37 	"ZEV_OP_ZNODE_RENAME",
38 	"ZEV_OP_ZNODE_WRITE",
39 	"ZEV_OP_ZNODE_TRUNCATE",
40 	"ZEV_OP_ZNODE_SETATTR",
41 	"ZEV_OP_ZNODE_ACL",
42 	NULL
43 };
44 
45 static int verbose = 0;
46 
47 static int
48 zev_statistics(int fd)
49 {
50 	zev_statistics_t zs;
51 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
52 		perror("getting statistics data failed");
53 		return (EXIT_FAILURE);
54 	}
55 	printf("ZEV module state:\n");
56 
57 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
58 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
59 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
60 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
61 
62 	printf("    discarded events        : %lu\n",
63 	    zs.zev_cnt_discarded_events);
64 	printf("    discarded bytes         : %lu\n\n", zs.zev_bytes_discarded);
65 
66 	printf("ZFS event statistics:\n");
67 
68 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
69 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
70 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
71 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
72 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
73 	printf("    ZNODE close after update: %lu\n",
74 	    zs.zev_cnt_znode_close_after_update);
75 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
76 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
77 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
78 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
79 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
80 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
81 	printf("    ZNODE truncate          : %lu\n",
82 	    zs.zev_cnt_znode_truncate);
83 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
84 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
85 	return EXIT_SUCCESS;
86 }
87 
88 static void
89 zev_print_error(char *buf)
90 {
91 	zev_error_t *rec = (zev_error_t *)buf;
92 	time_t op_time = rec->op_time;
93 	char *ct = ctime(&op_time); ct[24] = '\0';
94 
95 	printf("%s %s: failed_op=%s msg=%s\n",
96 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
97 	       zev_op_name[rec->failed_op - ZEV_OP_MIN], ZEV_ERRSTR(rec));
98 }
99 
100 static void
101 zev_print_mark(char *buf)
102 {
103 	zev_mark_t *rec = (zev_mark_t *)buf;
104 	time_t op_time = rec->op_time;
105 	char *ct = ctime(&op_time); ct[24] = '\0';
106 
107 	printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n",
108 	       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->mark_id,
109 	       rec->payload_len);
110 }
111 
112 static void
113 zev_print_zfs_mount(char *buf)
114 {
115 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
116 	time_t op_time = rec->op_time;
117 	char *ct = ctime(&op_time); ct[24] = '\0';
118 
119 	printf("%s %s: guid=%llu remount=%s dataset='%s' mountpoint='%s'\n",
120 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
121 	       rec->guid,
122 	       rec->remount ? "true" : "false",
123 	       ZEV_DATASET(rec),
124 	       ZEV_MOUNTPOINT(rec));
125 }
126 
127 static void
128 zev_print_zfs_umount(char *buf)
129 {
130 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
131 	time_t op_time = rec->op_time;
132 	char *ct = ctime(&op_time); ct[24] = '\0';
133 
134 	printf("%s %s: guid=%llu\n",
135 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
136 	       rec->guid);
137 }
138 
139 static void
140 zev_print_zvol_truncate(char *buf)
141 {
142 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
143 	time_t op_time = rec->op_time;
144 	char *ct = ctime(&op_time); ct[24] = '\0';
145 
146 	printf("%s %s: guid=%llu offset=%llu length=%llu\n",
147 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
148 	       rec->guid,
149 	       rec->offset,
150 	       rec->length);
151 }
152 
153 static void
154 zev_print_zvol_write(char *buf)
155 {
156 	zev_print_zvol_truncate(buf);
157 }
158 
159 static void
160 zev_print_znode_close_after_update(char *buf)
161 {
162 	zev_znode_close_after_update_t *rec =
163 	    (zev_znode_close_after_update_t *)buf;
164 	time_t op_time = rec->op_time;
165 	char *ct = ctime(&op_time); ct[24] = '\0';
166 
167 	printf("%s %s: guid=%llu file=%llu.%llu\n",
168 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
169 	       rec->guid,
170 	       rec->file.ino, rec->file.gen);
171 }
172 
173 static void
174 zev_print_znode_create(char *buf)
175 {
176 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
177 	time_t op_time = rec->op_time;
178 	char *ct = ctime(&op_time); ct[24] = '\0';
179 
180 	printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
181 	       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
182 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
183 	       rec->guid,
184 	       rec->parent.ino, rec->parent.gen,
185 	       rec->file.ino, rec->file.gen,
186 	       rec->file.mtime, rec->parent.mtime,
187 	       ZEV_NAME(rec));
188 }
189 
190 static void
191 zev_print_znode_mkdir(char *buf)
192 {
193 	zev_print_znode_create(buf);
194 }
195 
196 static void
197 zev_print_znode_make_xattr_dir(char *buf)
198 {
199 	zev_print_znode_create(buf);
200 }
201 
202 static void
203 zev_print_znode_remove(char *buf)
204 {
205 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
206 	time_t op_time = rec->op_time;
207 	char *ct = ctime(&op_time); ct[24] = '\0';
208 
209 	printf("%s %s: guid=%llu parent=%llu.%llu file.mtime=%llu name='%s'\n",
210 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
211 	       rec->guid,
212 	       rec->parent.ino, rec->parent.gen,
213 	       rec->file.mtime,
214 	       ZEV_NAME(rec));
215 }
216 
217 static void
218 zev_print_znode_rmdir(char *buf)
219 {
220 	zev_print_znode_remove(buf);
221 }
222 
223 static void
224 zev_print_znode_link(char *buf)
225 {
226 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
227 	time_t op_time = rec->op_time;
228 	char *ct = ctime(&op_time); ct[24] = '\0';
229 
230 	printf("%s %s: parent=%llu.%llu file=%llu.%llu "
231 	       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
232 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
233 	       rec->parent.ino, rec->parent.gen,
234 	       rec->file.ino, rec->file.gen,
235 	       rec->file.ctime, rec->parent.ctime,
236 	       ZEV_NAME(rec));
237 	printf("links: %d\n", rec->file.links);
238 }
239 
240 static void
241 zev_print_znode_symlink(char *buf)
242 {
243 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
244 	time_t op_time = rec->op_time;
245 	char *ct = ctime(&op_time); ct[24] = '\0';
246 
247 	printf("%s %s: parent=%llu.%llu file=%llu.%llu name='%s' link='%s'\n",
248 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
249 	       rec->parent.ino, rec->parent.gen,
250 	       rec->file.ino, rec->file.gen,
251 	       ZEV_NAME(rec),
252 	       ZEV_LINK(rec));
253 }
254 
255 static void
256 zev_print_znode_rename(char *buf)
257 {
258 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
259 	time_t op_time = rec->op_time;
260 	char *ct = ctime(&op_time); ct[24] = '\0';
261 
262 	printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu file=%llu.%llu "
263 	       "file.mtime=%llu, file.ctime=%llu, srcdir.mtime=%llu, "
264 	       "srcdir.ctime=%llu, dstdir.mtime=%llu, dstdir.ctime=%llu, "
265 	       "srcname='%s' dstname='%s'\n",
266 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
267 	       rec->srcdir.ino, rec->srcdir.gen,
268 	       rec->dstdir.ino, rec->dstdir.gen,
269 	       rec->file.ino, rec->file.gen,
270 	       rec->file.mtime, rec->file.ctime,
271 	       rec->srcdir.mtime, rec->srcdir.ctime,
272 	       rec->dstdir.mtime, rec->dstdir.ctime,
273 	       ZEV_SRCNAME(rec),
274 	       ZEV_DSTNAME(rec));
275 }
276 
277 static void
278 sig2hex_direct(const uint8_t *sig, char *hex)
279 {
280 	int     i;
281 
282 	for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) {
283 		sprintf(hex + 2 * i, "%02x", sig[i]);
284 	}
285 	hex[SHA1_DIGEST_LENGTH * 2] = '\0';
286 }
287 
288 static void
289 zev_print_znode_write(char *buf)
290 {
291 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
292 	time_t op_time = rec->op_time;
293 	char *ct = ctime(&op_time); ct[24] = '\0';
294 	zev_sig_t *sig;
295 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
296 	int i;
297 
298 	printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
299 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
300 	       rec->file.ino, rec->file.gen,
301 	       rec->offset, rec->length);
302 	if (verbose) {
303 		for (i=0; i<rec->signature_cnt; i++) {
304 			sig = (zev_sig_t *)ZEV_SIGNATURES(rec);
305 			sig += i;
306 			sig2hex_direct(sig->value, sigval);
307 			printf("  sig: level %d, offset %llu, value %s\n",
308 			       sig->level, sig->block_offset, sigval);
309 		}
310 	}
311 }
312 
313 static void
314 zev_print_znode_truncate(char *buf)
315 {
316 	zev_print_znode_write(buf);
317 }
318 
319 static void
320 zev_print_znode_setattr(char *buf)
321 {
322 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
323 	time_t op_time = rec->op_time;
324 	char *ct = ctime(&op_time); ct[24] = '\0';
325 
326 	printf("%s %s: file=%llu.%llu mtime=%llu\n",
327 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
328 	       rec->file.ino, rec->file.gen, rec->file.mtime);
329 }
330 
331 static void
332 zev_print_znode_acl(char *buf)
333 {
334 	zev_print_znode_setattr(buf);
335 }
336 
337 static void
338 zev_print_event(char *buf, int len)
339 {
340 	int record_len;
341 	int op;
342 
343 	record_len = *(uint32_t *)buf;
344 	if (record_len != len) {
345 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
346 		        record_len, len);
347 		exit(1);
348 	}
349 	op = *((uint32_t *)buf + 1);
350 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
351 		fprintf(stderr, "unknown op code: %d\n", op);
352 		exit(1);
353 	}
354 	switch (op) {
355 	case ZEV_OP_ERROR:
356 		zev_print_error(buf);
357 		break;
358 	case ZEV_OP_MARK:
359 		zev_print_mark(buf);
360 		break;
361 	case ZEV_OP_ZFS_MOUNT:
362 		zev_print_zfs_mount(buf);
363 		break;
364 	case ZEV_OP_ZFS_UMOUNT:
365 		zev_print_zfs_umount(buf);
366 		break;
367 	case ZEV_OP_ZVOL_TRUNCATE:
368 		zev_print_zvol_truncate(buf);
369 		break;
370 	case ZEV_OP_ZVOL_WRITE:
371 		zev_print_zvol_write(buf);
372 		break;
373 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
374 		zev_print_znode_close_after_update(buf);
375 		break;
376 	case ZEV_OP_ZNODE_CREATE:
377 		zev_print_znode_create(buf);
378 		break;
379 	case ZEV_OP_ZNODE_MKDIR:
380 		zev_print_znode_mkdir(buf);
381 		break;
382 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
383 		zev_print_znode_make_xattr_dir(buf);
384 		break;
385 	case ZEV_OP_ZNODE_REMOVE:
386 		zev_print_znode_remove(buf);
387 		break;
388 	case ZEV_OP_ZNODE_RMDIR:
389 		zev_print_znode_rmdir(buf);
390 		break;
391 	case ZEV_OP_ZNODE_LINK:
392 		zev_print_znode_link(buf);
393 		break;
394 	case ZEV_OP_ZNODE_SYMLINK:
395 		zev_print_znode_symlink(buf);
396 		break;
397 	case ZEV_OP_ZNODE_RENAME:
398 		zev_print_znode_rename(buf);
399 		break;
400 	case ZEV_OP_ZNODE_WRITE:
401 		zev_print_znode_write(buf);
402 		break;
403 	case ZEV_OP_ZNODE_TRUNCATE:
404 		zev_print_znode_truncate(buf);
405 		break;
406 	case ZEV_OP_ZNODE_SETATTR:
407 		zev_print_znode_setattr(buf);
408 		break;
409 	case ZEV_OP_ZNODE_ACL:
410 		zev_print_znode_acl(buf);
411 		break;
412 	default:
413 		fprintf(stderr, "unhandled op code: %d\n", op);
414 		exit(1);
415 	}
416 }
417 
418 static int
419 zev_poll_events(int fd, int create_tmp_queue)
420 {
421 	struct pollfd pfd[1];
422 	int ret;
423 	char buf[4096];
424 	zev_event_t *ev;
425 	int off = 0;
426 	zev_ioctl_add_queue_t aq;
427 	int q_fd;
428 
429 	if (create_tmp_queue) {
430 		aq.zev_max_queue_len = 0;
431 		aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
432 		snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
433 			 "zevadm.%ld.%ld", time(NULL), getpid());
434 		aq.zev_namelen = strlen(aq.zev_name);
435 
436 		if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
437 			perror("adding temporary queue failed");
438 			return (EXIT_FAILURE);
439 		}
440 
441 		snprintf(buf, sizeof(buf),
442 		         "/devices/pseudo/zev@0:%s", aq.zev_name);
443 		q_fd = open(buf, O_RDONLY);
444 		if (q_fd < 0) {
445 			perror("opening queue device failed");
446 			return (EXIT_FAILURE);
447 		}
448 	} else {
449 		q_fd = fd;
450 	}
451 
452 	while (1) {
453 		pfd[0].fd = q_fd;
454 		pfd[0].events = POLLIN;
455 		ret = poll(pfd, 1, 1000);
456 		if (ret < 0) {
457 			perror("poll failed");
458 			close(q_fd);
459 			return(EXIT_FAILURE);
460 		}
461 		if (!(pfd[0].revents & POLLIN))
462 			continue;
463 		/* data available */
464 		ret = read(q_fd, buf, sizeof(buf));
465 		if (ret < 0) {
466 			perror("read failed");
467 			close(q_fd);
468 			return(EXIT_FAILURE);
469 		}
470 		if (ret == 0)
471 			continue;
472 		while (ret > off) {
473 			ev = (zev_event_t *)(buf + off);
474 			zev_print_event(buf + off, ev->header.record_len);
475 			off += ev->header.record_len;
476 		}
477 		off = 0;
478 	}
479 	if (create_tmp_queue)
480 		close(q_fd);
481 	return EXIT_SUCCESS;
482 }
483 
484 static void
485 usage(char *progname)
486 {
487 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
488 	fprintf(stderr, "\n");
489 	fprintf(stderr, " Status information:\n");
490 	fprintf(stderr, "   -s                   show zev statistics\n");
491 	fprintf(stderr, "   -p                   poll for ZFS events\n");
492 	fprintf(stderr, "   -D                   print zev module debug "
493 	        "information\n");
494 	fprintf(stderr, "\n");
495 	fprintf(stderr, " Tune zev module settings:\n");
496 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
497 	        "length\n");
498 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
499 	        "this pool\n");
500 	fprintf(stderr, "   -M <pool>            unmute pool\n");
501 	fprintf(stderr, "\n");
502 	fprintf(stderr, " Queue management:\n");
503 	fprintf(stderr, "   -l                   list queues\n");
504 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
505 	fprintf(stderr, "   -A <name>            add blocking queue\n");
506 	fprintf(stderr, "   -r <name>            remove queue\n");
507 	fprintf(stderr, "   -b <name>            make queue non-blocking "
508 	        "(default)\n");
509 	fprintf(stderr, "   -B <name>            make queue block when full\n");
510 	fprintf(stderr, "   -P <name>            display queue properties\n");
511 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
512 	        "length\n");
513 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
514 	        "throttle\n");
515 	fprintf(stderr, "\n");
516 	fprintf(stderr, " Other options:\n");
517 	fprintf(stderr, "   -d <dev>             non-default device file. "
518 	        "('%s')\n", ZEV_DEVICE);
519 	fprintf(stderr, "   -q <name>            use device file for this "
520 		"queue name\n");
521 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
522 	fprintf(stderr, "   -v                   verbose: addition output "
523 	        "for some operations\n");
524 	exit (EXIT_FAILURE);
525 }
526 
527 static int
528 zev_add_queue(int fd, char *arg, int blocking)
529 {
530 	zev_ioctl_add_queue_t aq;
531 	int namelen;
532 
533 	namelen = strlen(arg);
534 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
535 		fprintf(stderr, "queue name too long: %s\n", arg);
536 		return (EXIT_FAILURE);
537 	}
538 
539 	aq.zev_namelen = namelen;
540 	strcpy(aq.zev_name, arg);
541 	aq.zev_flags = ZEV_FL_PERSISTENT;
542 	if (blocking) {
543 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
544 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
545 	} else {
546 		aq.zev_max_queue_len = (1024 * 1024);
547 	}
548 
549 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
550 		perror("adding queue failed");
551 		return (EXIT_FAILURE);
552 	}
553 	return (0);
554 }
555 
556 static int
557 zev_remove_queue(int fd, char *arg)
558 {
559 	zev_ioctl_remove_queue_t aq;
560 	int namelen;
561 
562 	namelen = strlen(arg);
563 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
564 		fprintf(stderr, "queue name too long: %s\n", arg);
565 		return (EXIT_FAILURE);
566 	}
567 
568 	aq.zev_queue_name.zev_namelen = namelen;
569 	strcpy(aq.zev_queue_name.zev_name, arg);
570 
571 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
572 		perror("removing queue failed");
573 		return (EXIT_FAILURE);
574 	}
575 	return (0);
576 }
577 
578 static int
579 zev_set_global_max_queue_len(int fd, char *arg)
580 {
581 	uint64_t maxqueuelen;
582 
583 	errno = 0;
584 	maxqueuelen = strtol(arg, (char **)NULL, 10);
585 	if (errno) {
586 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
587 		return (EXIT_FAILURE);
588 	}
589 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
590 		perror("setting max queue length failed");
591 		return (EXIT_FAILURE);
592 	}
593 	return (0);
594 }
595 
596 static int
597 zev_mute_unmute_impl(int fd, char *poolname, int mute)
598 {
599 	zev_ioctl_poolarg_t pa;
600 	int len;
601 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
602 	len = strlen(poolname);
603 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
604 		fprintf(stderr, "invalid poolname: %s\n", poolname);
605 		return (EXIT_FAILURE);
606 	}
607 	strcpy(pa.zev_poolname, poolname);
608 	pa.zev_poolname_len = len;
609 	if (ioctl(fd, op, &pa)) {
610 		perror("muting pool data failed");
611 		return (EXIT_FAILURE);
612 	}
613 	return (0);
614 }
615 
616 int
617 zev_mute_pool(int fd, char *poolname)
618 {
619 	return zev_mute_unmute_impl(fd, poolname, 1);
620 }
621 
622 int
623 zev_unmute_pool(int fd, char *poolname)
624 {
625 	return zev_mute_unmute_impl(fd, poolname, 0);
626 }
627 
628 static int
629 zev_debug_info(int fd)
630 {
631 	zev_ioctl_debug_info_t di;
632 
633 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
634 		perror("getting zev debug info failed");
635 		return (EXIT_FAILURE);
636 	}
637 
638 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
639 	printf("checksum cache size: %llu\n", di.zev_chksum_cache_size);
640 	printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits);
641 	printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses);
642 	return 0;
643 }
644 
645 static int
646 zev_mark(int fd, char *arg)
647 {
648 	zev_ioctl_mark_t *mark;
649 	uint64_t guid;
650 	int len;
651 	char *p;
652 
653 	p = strchr(arg, ':');
654 	if (!p) {
655 		fprintf(stderr, "expected value is <guid>:<payload>, "
656 		        "e.g. '123:hello'\n");
657 		exit (EXIT_FAILURE);
658 	}
659 	*p = '\n';
660 	p++;
661 
662 	errno = 0;
663 	guid = strtoll(arg, (char **)NULL, 10);
664 	if (errno) {
665 		fprintf(stderr, "guid must be a number.\n");
666 		exit (EXIT_FAILURE);
667 	}
668 
669 	len = strlen(p);
670 
671 	mark = malloc(sizeof(*mark) + len + 1);
672 	if (!mark) {
673 		fprintf(stderr, "can't allocate mark structure: %s\n",
674 		        strerror(errno));
675 		exit (EXIT_FAILURE);
676 	}
677 	mark->zev_guid = guid;
678 	mark->zev_mark_id = 0;
679 	mark->zev_payload_len = len;
680 	strcpy(ZEV_PAYLOAD(mark), p);
681 
682 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
683 		perror("queueing mark failed");
684 		return (EXIT_FAILURE);
685 	}
686 
687 	printf("mark id: %lu\n", mark->zev_mark_id);
688 	return (0);
689 }
690 
691 static int
692 zev_queue_blocking(int fd, char *arg, int block)
693 {
694 	zev_ioctl_get_queue_properties_t gqp;
695 
696 	gqp.zev_queue_name.zev_namelen = strlen(arg);
697 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
698 		fprintf(stderr, "queue name too long.\n");
699 		return EXIT_FAILURE;
700 	}
701 	strcpy(gqp.zev_queue_name.zev_name, arg);
702 
703 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
704 		perror("getting queue properties failed");
705 		return (EXIT_FAILURE);
706 	}
707 	if (block) {
708 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
709 	} else {
710 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
711 	}
712 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
713 		perror("setting queue properties failed");
714 		return (EXIT_FAILURE);
715 	}
716 	return (0);
717 }
718 
719 static int
720 zev_set_max_queue_len(int fd, char *arg, char *len)
721 {
722 	zev_ioctl_get_queue_properties_t gqp;
723 
724 	if (!len) {
725 		fprintf(stderr, "queue size parameter missing.\n");
726 		return EXIT_FAILURE;
727 	}
728 
729 	gqp.zev_queue_name.zev_namelen = strlen(arg);
730 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
731 		fprintf(stderr, "queue name too long.\n");
732 		return EXIT_FAILURE;
733 	}
734 	strcpy(gqp.zev_queue_name.zev_name, arg);
735 
736 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
737 		perror("getting queue properties failed");
738 		return (EXIT_FAILURE);
739 	}
740 	gqp.zev_max_queue_len = atol(len);
741 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
742 		fprintf(stderr, "queue size parameter garbled.\n");
743 		return (EXIT_FAILURE);
744 	}
745 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
746 		fprintf(stderr, "queue size parameter out of bounds.\n");
747 		return (EXIT_FAILURE);
748 	}
749 
750 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
751 		perror("setting queue properties failed");
752 		return (EXIT_FAILURE);
753 	}
754 	return (0);
755 }
756 
757 static int
758 zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
759 {
760 	zev_ioctl_get_queue_properties_t gqp;
761 
762 	if (!len) {
763 		fprintf(stderr, "poll throttle parameter missing.\n");
764 		return EXIT_FAILURE;
765 	}
766 
767 	gqp.zev_queue_name.zev_namelen = strlen(arg);
768 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
769 		fprintf(stderr, "queue name too long.\n");
770 		return EXIT_FAILURE;
771 	}
772 	strcpy(gqp.zev_queue_name.zev_name, arg);
773 
774 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
775 		perror("getting queue properties failed");
776 		return (EXIT_FAILURE);
777 	}
778 	gqp.zev_poll_wakeup_threshold = atol(len);
779 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
780 		fprintf(stderr, "poll throttle parameter garbled.\n");
781 		return (EXIT_FAILURE);
782 	}
783 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
784 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
785 		return (EXIT_FAILURE);
786 	}
787 
788 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
789 		perror("setting queue properties failed");
790 		return (EXIT_FAILURE);
791 	}
792 	return (0);
793 }
794 
795 static int
796 zev_queue_properties(int fd, char *arg)
797 {
798 	zev_ioctl_get_queue_properties_t gqp;
799 
800 	gqp.zev_queue_name.zev_namelen = strlen(arg);
801 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
802 		fprintf(stderr, "queue name too long.\n");
803 		return EXIT_FAILURE;
804 	}
805 	strcpy(gqp.zev_queue_name.zev_name, arg);
806 
807 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
808 		perror("getting queue properties failed");
809 		return (EXIT_FAILURE);
810 	}
811 
812 	printf("queue        : %s\n", arg);
813 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
814 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
815 	printf("persistent   : %s\n",
816 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
817 	printf("blocking     : %s\n",
818 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
819 
820 	return (0);
821 }
822 
823 static int
824 zev_list_queues(int fd)
825 {
826 	zev_ioctl_get_queue_properties_t gqp;
827 	zev_ioctl_get_queue_list_t gql;
828 	zev_ioctl_get_queue_statistics_t gs;
829 	uint64_t	i;
830 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
831 
832 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
833 		perror("getting queue list failed");
834 		return (EXIT_FAILURE);
835 	}
836 
837 	printf("Name                                     Size       "
838 	       "Max Size   Wakeup Per Block\n");
839 
840 	for (i=0; i<gql.zev_n_queues; i++) {
841 		strncpy(name, gql.zev_queue_name[i].zev_name,
842 		        ZEV_MAX_QUEUE_NAME_LEN);
843 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
844 
845 		memcpy(gqp.zev_queue_name.zev_name,
846 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
847 		gqp.zev_queue_name.zev_namelen =
848 		    gql.zev_queue_name[i].zev_namelen;
849 
850 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
851 			if (errno == ENOENT)
852 				continue;
853 			perror("getting queue properties failed");
854 			return (EXIT_FAILURE);
855 		}
856 
857 		memcpy(gs.zev_queue_name.zev_name,
858 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
859 		gs.zev_queue_name.zev_namelen =
860 		    gql.zev_queue_name[i].zev_namelen;
861 
862 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
863 			if (errno == ENOENT)
864 				continue;
865 			perror("getting statistics data failed");
866 			return (EXIT_FAILURE);
867 		}
868 
869 		printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64
870 		       " %-3s %-3s\n",
871 			name,
872 			gs.zev_statistics.zev_queue_len,
873 			gqp.zev_max_queue_len,
874 			gqp.zev_poll_wakeup_threshold,
875 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
876 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
877 				 "yes" : "no");
878 	}
879 
880 	return (0);
881 }
882 
883 int
884 main(int argc, char **argv)
885 {
886 	int fd;
887 	int c;
888 	extern char *optarg;
889 	int create_tmp_queue = 1;
890 	char buf[MAXPATHLEN];
891 
892 	/* open device */
893 	fd = open(zev_device, O_RDONLY);
894 	if (fd < 0) {
895 		perror("opening zev device failed");
896 		return EXIT_FAILURE;
897 	}
898 	while ((c = getopt(argc, argv,
899 	                   "vspd:Dlk:L:q:Qt:m:M:a:A:r:P:b:B:h?")) != -1){
900 		switch(c) {
901 		case 'v':
902 			verbose++;
903 			break;
904 		case 's':
905 			return zev_statistics(fd);
906 		case 'p':
907 			return zev_poll_events(fd, create_tmp_queue);
908 		case 'D':
909 			return zev_debug_info(fd);
910 		case 'd':
911 			close(fd);
912 			zev_device = optarg;
913 			fd = open(zev_device, O_RDONLY);
914 			if (fd < 0) {
915 				perror("opening zev device failed");
916 				return EXIT_FAILURE;
917 			}
918 			create_tmp_queue = 0;
919 			break;
920 		case 'q':
921 			snprintf(buf, sizeof(buf),
922 				 "/devices/pseudo/zev@0:%s", optarg);
923 			close(fd);
924 			zev_device = buf;
925 			fd = open(zev_device, O_RDONLY);
926 			if (fd < 0) {
927 				perror("opening zev device failed");
928 				return EXIT_FAILURE;
929 			}
930 			create_tmp_queue = 0;
931 			break;
932 		case 'l':
933 			return zev_list_queues(fd);
934 		case 'Q':
935 			return zev_set_global_max_queue_len(fd, optarg);
936 		case 'L':
937 			return zev_set_max_queue_len(fd, optarg, argv[optind]);
938 		case 't':
939 			return zev_set_poll_wakeup_queue_len(fd, optarg,
940 			                                     argv[optind]);
941 		case 'm':
942 			return zev_mute_pool(fd, optarg);
943 		case 'M':
944 			return zev_unmute_pool(fd, optarg);
945 		case 'k':
946 			return zev_mark(fd, optarg);
947 		case 'a':
948 			return zev_add_queue(fd, optarg, 0);
949 		case 'A':
950 			return zev_add_queue(fd, optarg, 1);
951 		case 'r':
952 			return zev_remove_queue(fd, optarg);
953 		case 'b':
954 			return zev_queue_blocking(fd, optarg, 0);
955 		case 'B':
956 			return zev_queue_blocking(fd, optarg, 1);
957 		case 'P':
958 			return zev_queue_properties(fd, optarg);
959 		case 'h':
960 		case '?':
961 		default:
962 			usage(argv[0]);
963 		}
964 	}
965 	usage(argv[0]);
966 	close(fd);
967 	return EXIT_FAILURE;
968 }
969 
970