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