xref: /titanic_52/usr/src/cmd/zevadm/zevadm.c (revision 6db5d4ec7067f6ac90788b6d5f24002d82d0f21e)
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 
17 #define ZEV_DEVICE "/devices/pseudo/zev@0:zev"
18 
19 static char *zev_device = ZEV_DEVICE;
20 
21 static char *zev_op_name[] = {
22 	"ZEV_OP_ERROR",
23 	"ZEV_OP_MARK",
24 	"ZEV_OP_ZFS_MOUNT",
25 	"ZEV_OP_ZFS_UMOUNT",
26 	"ZEV_OP_ZVOL_WRITE",
27 	"ZEV_OP_ZVOL_TRUNCATE",
28 	"ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE",
29 	"ZEV_OP_ZNODE_CREATE",
30 	"ZEV_OP_ZNODE_MKDIR",
31 	"ZEV_OP_ZNODE_MAKE_XATTR_DIR",
32 	"ZEV_OP_ZNODE_REMOVE",
33 	"ZEV_OP_ZNODE_RMDIR",
34 	"ZEV_OP_ZNODE_LINK",
35 	"ZEV_OP_ZNODE_SYMLINK",
36 	"ZEV_OP_ZNODE_RENAME",
37 	"ZEV_OP_ZNODE_WRITE",
38 	"ZEV_OP_ZNODE_TRUNCATE",
39 	"ZEV_OP_ZNODE_SETATTR",
40 	"ZEV_OP_ZNODE_ACL",
41 	NULL
42 };
43 
44 static void
45 zev_statistics(int fd)
46 {
47 	zev_statistics_t zs;
48 	if (ioctl(fd, ZEV_IOC_GET_STATISTICS, &zs)) {
49 		perror("getting statistics data failed");
50 		exit (EXIT_FAILURE);
51 	}
52 	printf("ZEV module state:\n");
53 
54 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
55 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
56 	printf("    poll wakeup throttle    : %lu\n\n",
57 	    zs.zev_poll_wakeup_queue_len);
58 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
59 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
60 
61 	printf("ZFS event statistics:\n");
62 
63 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
64 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
65 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
66 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
67 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
68 	printf("    ZNODE close after update: %lu\n",
69 	    zs.zev_cnt_znode_close_after_update);
70 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
71 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
72 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
73 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
74 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
75 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
76 	printf("    ZNODE truncate          : %lu\n",
77 	    zs.zev_cnt_znode_truncate);
78 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
79 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
80 }
81 
82 static void
83 zev_print_error(char *buf)
84 {
85 	zev_error_t *rec = (zev_error_t *)buf;
86 	time_t op_time = rec->op_time;
87 	char *ct = ctime(&op_time); ct[24] = '\0';
88 
89 	printf("%s %s: failed_op=%s msg=%s\n",
90 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
91 	       zev_op_name[rec->failed_op - ZEV_OP_MIN], ZEV_ERRSTR(rec));
92 }
93 
94 static void
95 zev_print_mark(char *buf)
96 {
97 	zev_mark_t *rec = (zev_mark_t *)buf;
98 	time_t op_time = rec->op_time;
99 	char *ct = ctime(&op_time); ct[24] = '\0';
100 
101 	printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n",
102 	       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->mark_id,
103 	       rec->payload_len);
104 }
105 
106 static void
107 zev_print_zfs_mount(char *buf)
108 {
109 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
110 	time_t op_time = rec->op_time;
111 	char *ct = ctime(&op_time); ct[24] = '\0';
112 
113 	printf("%s %s: guid=%llu remount=%s dataset='%s' mountpoint='%s'\n",
114 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
115 	       rec->guid,
116 	       rec->remount ? "true" : "false",
117 	       ZEV_DATASET(rec),
118 	       ZEV_MOUNTPOINT(rec));
119 }
120 
121 static void
122 zev_print_zfs_umount(char *buf)
123 {
124 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
125 	time_t op_time = rec->op_time;
126 	char *ct = ctime(&op_time); ct[24] = '\0';
127 
128 	printf("%s %s: guid=%llu\n",
129 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
130 	       rec->guid);
131 }
132 
133 static void
134 zev_print_zvol_truncate(char *buf)
135 {
136 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
137 	time_t op_time = rec->op_time;
138 	char *ct = ctime(&op_time); ct[24] = '\0';
139 
140 	printf("%s %s: guid=%llu offset=%llu length=%llu\n",
141 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
142 	       rec->guid,
143 	       rec->offset,
144 	       rec->length);
145 }
146 
147 static void
148 zev_print_zvol_write(char *buf)
149 {
150 	zev_print_zvol_truncate(buf);
151 }
152 
153 static void
154 zev_print_znode_close_after_update(char *buf)
155 {
156 	zev_znode_close_after_update_t *rec =
157 	    (zev_znode_close_after_update_t *)buf;
158 	time_t op_time = rec->op_time;
159 	char *ct = ctime(&op_time); ct[24] = '\0';
160 
161 	printf("%s %s: guid=%llu file=%llu.%llu\n",
162 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
163 	       rec->guid,
164 	       rec->file.ino, rec->file.gen);
165 }
166 
167 static void
168 zev_print_znode_create(char *buf)
169 {
170 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
171 	time_t op_time = rec->op_time;
172 	char *ct = ctime(&op_time); ct[24] = '\0';
173 
174 	printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
175 	       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
176 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
177 	       rec->guid,
178 	       rec->parent.ino, rec->parent.gen,
179 	       rec->file.ino, rec->file.gen,
180 	       rec->file.mtime, rec->parent.mtime,
181 	       ZEV_NAME(rec));
182 }
183 
184 static void
185 zev_print_znode_mkdir(char *buf)
186 {
187 	zev_print_znode_create(buf);
188 }
189 
190 static void
191 zev_print_znode_make_xattr_dir(char *buf)
192 {
193 	zev_print_znode_create(buf);
194 }
195 
196 static void
197 zev_print_znode_remove(char *buf)
198 {
199 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
200 	time_t op_time = rec->op_time;
201 	char *ct = ctime(&op_time); ct[24] = '\0';
202 
203 	printf("%s %s: guid=%llu parent=%llu.%llu file.mtime=%llu name='%s'\n",
204 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
205 	       rec->guid,
206 	       rec->parent.ino, rec->parent.gen,
207 	       rec->file.mtime,
208 	       ZEV_NAME(rec));
209 }
210 
211 static void
212 zev_print_znode_rmdir(char *buf)
213 {
214 	zev_print_znode_remove(buf);
215 }
216 
217 static void
218 zev_print_znode_link(char *buf)
219 {
220 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
221 	time_t op_time = rec->op_time;
222 	char *ct = ctime(&op_time); ct[24] = '\0';
223 
224 	printf("%s %s: parent=%llu.%llu file=%llu.%llu "
225 	       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
226 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
227 	       rec->parent.ino, rec->parent.gen,
228 	       rec->file.ino, rec->file.gen,
229 	       rec->file.ctime, rec->parent.ctime,
230 	       ZEV_NAME(rec));
231 	printf("links: %d\n", rec->file.links);
232 }
233 
234 static void
235 zev_print_znode_symlink(char *buf)
236 {
237 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
238 	time_t op_time = rec->op_time;
239 	char *ct = ctime(&op_time); ct[24] = '\0';
240 
241 	printf("%s %s: parent=%llu.%llu file=%llu.%llu name='%s' link='%s'\n",
242 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
243 	       rec->parent.ino, rec->parent.gen,
244 	       rec->file.ino, rec->file.gen,
245 	       ZEV_NAME(rec),
246 	       ZEV_LINK(rec));
247 }
248 
249 static void
250 zev_print_znode_rename(char *buf)
251 {
252 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
253 	time_t op_time = rec->op_time;
254 	char *ct = ctime(&op_time); ct[24] = '\0';
255 
256 	printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu file=%llu.%llu "
257 	       "file.mtime=%llu, file.ctime=%llu, srcdir.mtime=%llu, "
258 	       "srcdir.ctime=%llu, dstdir.mtime=%llu, dstdir.ctime=%llu, "
259 	       "srcname='%s' dstname='%s'\n",
260 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
261 	       rec->srcdir.ino, rec->srcdir.gen,
262 	       rec->dstdir.ino, rec->dstdir.gen,
263 	       rec->file.ino, rec->file.gen,
264 	       rec->file.mtime, rec->file.ctime,
265 	       rec->srcdir.mtime, rec->srcdir.ctime,
266 	       rec->dstdir.mtime, rec->dstdir.ctime,
267 	       ZEV_SRCNAME(rec),
268 	       ZEV_DSTNAME(rec));
269 }
270 
271 static void
272 zev_print_znode_write(char *buf)
273 {
274 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
275 	time_t op_time = rec->op_time;
276 	char *ct = ctime(&op_time); ct[24] = '\0';
277 
278 	printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
279 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
280 	       rec->file.ino, rec->file.gen,
281 	       rec->offset, rec->length);
282 }
283 
284 static void
285 zev_print_znode_truncate(char *buf)
286 {
287 	zev_print_znode_write(buf);
288 }
289 
290 static void
291 zev_print_znode_setattr(char *buf)
292 {
293 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
294 	time_t op_time = rec->op_time;
295 	char *ct = ctime(&op_time); ct[24] = '\0';
296 
297 	printf("%s %s: file=%llu.%llu mtime=%llu\n",
298 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
299 	       rec->file.ino, rec->file.gen, rec->file.mtime);
300 }
301 
302 static void
303 zev_print_znode_acl(char *buf)
304 {
305 	zev_print_znode_setattr(buf);
306 }
307 
308 static void
309 zev_print_event(char *buf, int len)
310 {
311 	int record_len;
312 	int op;
313 
314 	record_len = *(uint32_t *)buf;
315 	if (record_len != len) {
316 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
317 		        record_len, len);
318 		exit(1);
319 	}
320 	op = *((uint32_t *)buf + 1);
321 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
322 		fprintf(stderr, "unknown op code: %d\n", op);
323 		exit(1);
324 	}
325 	switch (op) {
326 	case ZEV_OP_ERROR:
327 		zev_print_error(buf);
328 		break;
329 	case ZEV_OP_MARK:
330 		zev_print_mark(buf);
331 		break;
332 	case ZEV_OP_ZFS_MOUNT:
333 		zev_print_zfs_mount(buf);
334 		break;
335 	case ZEV_OP_ZFS_UMOUNT:
336 		zev_print_zfs_umount(buf);
337 		break;
338 	case ZEV_OP_ZVOL_TRUNCATE:
339 		zev_print_zvol_truncate(buf);
340 		break;
341 	case ZEV_OP_ZVOL_WRITE:
342 		zev_print_zvol_write(buf);
343 		break;
344 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
345 		zev_print_znode_close_after_update(buf);
346 		break;
347 	case ZEV_OP_ZNODE_CREATE:
348 		zev_print_znode_create(buf);
349 		break;
350 	case ZEV_OP_ZNODE_MKDIR:
351 		zev_print_znode_mkdir(buf);
352 		break;
353 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
354 		zev_print_znode_make_xattr_dir(buf);
355 		break;
356 	case ZEV_OP_ZNODE_REMOVE:
357 		zev_print_znode_remove(buf);
358 		break;
359 	case ZEV_OP_ZNODE_RMDIR:
360 		zev_print_znode_rmdir(buf);
361 		break;
362 	case ZEV_OP_ZNODE_LINK:
363 		zev_print_znode_link(buf);
364 		break;
365 	case ZEV_OP_ZNODE_SYMLINK:
366 		zev_print_znode_symlink(buf);
367 		break;
368 	case ZEV_OP_ZNODE_RENAME:
369 		zev_print_znode_rename(buf);
370 		break;
371 	case ZEV_OP_ZNODE_WRITE:
372 		zev_print_znode_write(buf);
373 		break;
374 	case ZEV_OP_ZNODE_TRUNCATE:
375 		zev_print_znode_truncate(buf);
376 		break;
377 	case ZEV_OP_ZNODE_SETATTR:
378 		zev_print_znode_setattr(buf);
379 		break;
380 	case ZEV_OP_ZNODE_ACL:
381 		zev_print_znode_acl(buf);
382 		break;
383 	default:
384 		fprintf(stderr, "unhandled op code: %d\n", op);
385 		exit(1);
386 	}
387 }
388 
389 static void
390 zev_poll_events(int fd)
391 {
392 	struct pollfd pfd[1];
393 	int ret;
394 	char buf[4096];
395 	zev_event_t	*ev;
396 	int off = 0;
397 	while (1) {
398 		pfd[0].fd = fd;
399 		pfd[0].events = POLLIN;
400 		ret = poll(pfd, 1, 1000);
401 		if (ret < 0) {
402 			perror("poll failed");
403 			exit(EXIT_FAILURE);
404 		}
405 		if (!(pfd[0].revents & POLLIN))
406 			continue;
407 		/* data available */
408 		ret = read(fd, buf, sizeof(buf));
409 		if (ret < 0) {
410 			perror("read failed");
411 			exit(EXIT_FAILURE);
412 		}
413 		if (ret == 0)
414 			continue;
415 		while (ret > off) {
416 			ev = (zev_event_t *)(buf + off);
417 			zev_print_event(buf + off, ev->header.record_len);
418 			off += ev->header.record_len;
419 		}
420 		off = 0;
421 	}
422 	return;
423 }
424 
425 static void
426 usage(char *progname)
427 {
428 	fprintf(stderr, "usage: %s [-s] [-d <dev>]\n", progname);
429 	fprintf(stderr, "   -s         show zev statistics\n");
430 	fprintf(stderr, "   -p         poll for ZFS events\n");
431 	fprintf(stderr, "   -q <bytes> set maximum event queue length\n");
432 	fprintf(stderr, "   -t <bytes> set queue length poll throttle\n");
433 	fprintf(stderr, "   -m <pool>  mute pool, no events for this pool\n");
434 	fprintf(stderr, "   -M <pool>  unmute pool\n");
435 	fprintf(stderr, "   -d <dev>   device file to use. default is '%s'\n",
436 	    ZEV_DEVICE);
437 	fprintf(stderr, "   -k <guid>:<payload>   queue mark event\n");
438 	exit (EXIT_FAILURE);
439 }
440 
441 static int
442 zev_set_max_queue_len(int fd, char *optarg)
443 {
444 	uint64_t maxqueuelen;
445 
446 	errno = 0;
447 	maxqueuelen = strtol(optarg, (char **)NULL, 10);
448 	if (errno) {
449 		fprintf(stderr, "invalid queue length parameter: %s\n", optarg);
450 		return (EXIT_FAILURE);
451 	}
452 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
453 		perror("setting max queue length failed");
454 		return (EXIT_FAILURE);
455 	}
456 	return (0);
457 }
458 
459 static int
460 zev_set_poll_wakeup_queue_len(int fd, char *optarg)
461 {
462 	uint64_t queuelen;
463 
464 	errno = 0;
465 	queuelen = strtol(optarg, (char **)NULL, 10);
466 	if (errno) {
467 		fprintf(stderr, "invalid queue length parameter: %s\n", optarg);
468 		return (EXIT_FAILURE);
469 	}
470 	if (ioctl(fd, ZEV_IOC_SET_POLL_WAKEUP_QUEUE_LEN, &queuelen)) {
471 		perror("setting poll wakeup queue length failed");
472 		return (EXIT_FAILURE);
473 	}
474 	return (0);
475 }
476 
477 static int
478 zev_mute_unmute_impl(int fd, char *poolname, int mute)
479 {
480 	zev_ioctl_poolarg_t pa;
481 	int len;
482 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
483 	len = strlen(poolname);
484 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
485 		fprintf(stderr, "invalid poolname: %s\n", poolname);
486 		return (EXIT_FAILURE);
487 	}
488 	strcpy(pa.zev_poolname, poolname);
489 	pa.zev_poolname_len = len;
490 	if (ioctl(fd, op, &pa)) {
491 		perror("muting pool data failed");
492 		return (EXIT_FAILURE);
493 	}
494 	return (0);
495 }
496 
497 int
498 zev_mute_pool(int fd, char *poolname)
499 {
500 	return zev_mute_unmute_impl(fd, poolname, 1);
501 }
502 
503 int
504 zev_unmute_pool(int fd, char *poolname)
505 {
506 	return zev_mute_unmute_impl(fd, poolname, 0);
507 }
508 
509 static int
510 zev_mark(int fd, char *arg)
511 {
512 	zev_ioctl_mark_t *mark;
513 	uint64_t guid;
514 	int len;
515 	char *p;
516 
517 	p = strchr(arg, ':');
518 	if (!p) {
519 		fprintf(stderr, "expected value is <guid>:<payload>, "
520 		        "e.g. '123:hello'\n");
521 		exit (EXIT_FAILURE);
522 	}
523 	*p = '\n';
524 	p++;
525 
526 	errno = 0;
527 	guid = strtoll(optarg, (char **)NULL, 10);
528 	if (errno) {
529 		fprintf(stderr, "guid must be a number.\n");
530 		exit (EXIT_FAILURE);
531 	}
532 
533 	len = strlen(p);
534 
535 	mark = malloc(sizeof(*mark) + len + 1);
536 	if (!mark) {
537 		fprintf(stderr, "can't allocate mark structure: %s\n",
538 		        strerror(errno));
539 		exit (EXIT_FAILURE);
540 	}
541 	mark->zev_guid = guid;
542 	mark->zev_mark_id = 0;
543 	mark->zev_payload_len = len;
544 	strcpy(ZEV_PAYLOAD(mark), p);
545 
546 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
547 		perror("queueing mark failed");
548 		return (EXIT_FAILURE);
549 	}
550 
551 	printf("mark id: %lu\n", mark->zev_mark_id);
552 	return (0);
553 }
554 
555 int
556 main(int argc, char **argv)
557 {
558 	int fd;
559 	int c;
560 	int ops = 0;
561 	extern char *optarg;
562 
563 	/* open device */
564 	fd = open(zev_device, O_RDONLY);
565 	if (fd < 0) {
566 		perror("opening zev device failed");
567 		return EXIT_FAILURE;
568 	}
569 	while ((c = getopt(argc, argv, "spdk:q:t:m:M:h?")) != -1) {
570 		switch(c) {
571 		case 's':
572 			ops |= OP_STATISTICS;
573 			break;
574 		case 'p':
575 			ops |= OP_POLL_EVENTS;
576 			break;
577 		case 'd':
578 			zev_device = optarg;
579 			break;
580 		case 'q':
581 			return zev_set_max_queue_len(fd, optarg);
582 		case 't':
583 			return zev_set_poll_wakeup_queue_len(fd, optarg);
584 		case 'm':
585 			return zev_mute_pool(fd, optarg);
586 		case 'M':
587 			return zev_unmute_pool(fd, optarg);
588 		case 'k':
589 			return zev_mark(fd, optarg);
590 		case 'h':
591 		case '?':
592 		default:
593 			usage(argv[0]);
594 		}
595 	}
596 	if (!ops)
597 		usage(argv[0]);
598 	if (ops & OP_STATISTICS)
599 		zev_statistics(fd);
600 	if (ops & OP_POLL_EVENTS)
601 		zev_poll_events(fd);
602 	close(fd);
603 	return EXIT_SUCCESS;
604 }
605 
606