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