#include #include #include #include #include #include #include #include #include #include #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl" static char *zev_device = ZEV_DEVICE; static char *zev_op_name[] = { "ZEV_OP_ERROR", "ZEV_OP_MARK", "ZEV_OP_ZFS_MOUNT", "ZEV_OP_ZFS_UMOUNT", "ZEV_OP_ZVOL_WRITE", "ZEV_OP_ZVOL_TRUNCATE", "ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE", "ZEV_OP_ZNODE_CREATE", "ZEV_OP_ZNODE_MKDIR", "ZEV_OP_ZNODE_MAKE_XATTR_DIR", "ZEV_OP_ZNODE_REMOVE", "ZEV_OP_ZNODE_RMDIR", "ZEV_OP_ZNODE_LINK", "ZEV_OP_ZNODE_SYMLINK", "ZEV_OP_ZNODE_RENAME", "ZEV_OP_ZNODE_WRITE", "ZEV_OP_ZNODE_TRUNCATE", "ZEV_OP_ZNODE_SETATTR", "ZEV_OP_ZNODE_ACL", NULL }; static int verbose = 0; static int zev_statistics(int fd) { zev_statistics_t zs; if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) { perror("getting statistics data failed"); return (EXIT_FAILURE); } printf("ZEV module state:\n"); printf(" queue length in bytes : %lu\n", zs.zev_queue_len); printf(" queue length limit : %lu\n", zs.zev_max_queue_len); printf(" bytes read from device : %lu\n", zs.zev_bytes_read); printf(" module internal errors : %lu\n\n", zs.zev_cnt_errors); printf(" discarded events : %lu\n", zs.zev_cnt_discarded_events); printf(" discarded bytes : %lu\n\n", zs.zev_bytes_discarded); printf("ZFS event statistics:\n"); printf(" total ZFS events : %lu\n", zs.zev_cnt_total_events); printf(" ZFS mount : %lu\n", zs.zev_cnt_zfs_mount); printf(" ZFS umount : %lu\n", zs.zev_cnt_zfs_umount); printf(" ZVOL write : %lu\n", zs.zev_cnt_zvol_write); printf(" ZVOL truncate : %lu\n", zs.zev_cnt_zvol_truncate); printf(" ZNODE close after update: %lu\n", zs.zev_cnt_znode_close_after_update); printf(" ZNODE create : %lu\n", zs.zev_cnt_znode_create); printf(" ZNODE remove : %lu\n", zs.zev_cnt_znode_remove); printf(" ZNODE link : %lu\n", zs.zev_cnt_znode_link); printf(" ZNODE symlink : %lu\n", zs.zev_cnt_znode_symlink); printf(" ZNODE rename : %lu\n", zs.zev_cnt_znode_rename); printf(" ZNODE write : %lu\n", zs.zev_cnt_znode_write); printf(" ZNODE truncate : %lu\n", zs.zev_cnt_znode_truncate); printf(" ZNODE setattr : %lu\n", zs.zev_cnt_znode_setattr); printf(" ZNODE acl : %lu\n", zs.zev_cnt_znode_acl); return EXIT_SUCCESS; } static void zev_print_error(char *buf) { zev_error_t *rec = (zev_error_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: failed_op=%s msg=%s\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], zev_op_name[rec->failed_op - ZEV_OP_MIN], ZEV_ERRSTR(rec)); } static void zev_print_mark(char *buf) { zev_mark_t *rec = (zev_mark_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->mark_id, rec->payload_len); } static void zev_print_zfs_mount(char *buf) { zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: guid=%llu remount=%s dataset='%s' mountpoint='%s'\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->remount ? "true" : "false", ZEV_DATASET(rec), ZEV_MOUNTPOINT(rec)); } static void zev_print_zfs_umount(char *buf) { zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: guid=%llu\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid); } static void zev_print_zvol_truncate(char *buf) { zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: guid=%llu offset=%llu length=%llu\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->offset, rec->length); } static void zev_print_zvol_write(char *buf) { zev_print_zvol_truncate(buf); } static void zev_print_znode_close_after_update(char *buf) { zev_znode_close_after_update_t *rec = (zev_znode_close_after_update_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: guid=%llu file=%llu.%llu\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->file.ino, rec->file.gen); } static void zev_print_znode_create(char *buf) { zev_znode_create_t *rec = (zev_znode_create_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu " "file.mtime=%llu, parent.mtime=%llu, name='%s'\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->parent.ino, rec->parent.gen, rec->file.ino, rec->file.gen, rec->file.mtime, rec->parent.mtime, ZEV_NAME(rec)); } static void zev_print_znode_mkdir(char *buf) { zev_print_znode_create(buf); } static void zev_print_znode_make_xattr_dir(char *buf) { zev_print_znode_create(buf); } static void zev_print_znode_remove(char *buf) { zev_znode_remove_t *rec = (zev_znode_remove_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: guid=%llu parent=%llu.%llu file.mtime=%llu name='%s'\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->parent.ino, rec->parent.gen, rec->file.mtime, ZEV_NAME(rec)); } static void zev_print_znode_rmdir(char *buf) { zev_print_znode_remove(buf); } static void zev_print_znode_link(char *buf) { zev_znode_link_t *rec = (zev_znode_link_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: parent=%llu.%llu file=%llu.%llu " "file.ctime=%llu parent.ctime=%llu name='%s'\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->parent.ino, rec->parent.gen, rec->file.ino, rec->file.gen, rec->file.ctime, rec->parent.ctime, ZEV_NAME(rec)); printf("links: %d\n", rec->file.links); } static void zev_print_znode_symlink(char *buf) { zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: parent=%llu.%llu file=%llu.%llu name='%s' link='%s'\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->parent.ino, rec->parent.gen, rec->file.ino, rec->file.gen, ZEV_NAME(rec), ZEV_LINK(rec)); } static void zev_print_znode_rename(char *buf) { zev_znode_rename_t *rec = (zev_znode_rename_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu file=%llu.%llu " "file.mtime=%llu, file.ctime=%llu, srcdir.mtime=%llu, " "srcdir.ctime=%llu, dstdir.mtime=%llu, dstdir.ctime=%llu, " "srcname='%s' dstname='%s'\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->srcdir.ino, rec->srcdir.gen, rec->dstdir.ino, rec->dstdir.gen, rec->file.ino, rec->file.gen, rec->file.mtime, rec->file.ctime, rec->srcdir.mtime, rec->srcdir.ctime, rec->dstdir.mtime, rec->dstdir.ctime, ZEV_SRCNAME(rec), ZEV_DSTNAME(rec)); } static void sig2hex_direct(const uint8_t *sig, char *hex) { int i; for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) { sprintf(hex + 2 * i, "%02x", sig[i]); } hex[SHA1_DIGEST_LENGTH * 2] = '\0'; } static void zev_print_znode_write(char *buf) { zev_znode_write_t *rec = (zev_znode_write_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; zev_sig_t *sig; char sigval[(SHA1_DIGEST_LENGTH * 2) + 1]; int i; printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->file.ino, rec->file.gen, rec->offset, rec->length); if (verbose) { for (i=0; isignature_cnt; i++) { sig = (zev_sig_t *)ZEV_SIGNATURES(rec); sig += i; sig2hex_direct(sig->value, sigval); printf(" sig: level %d, offset %llu, value %s\n", sig->level, sig->block_offset, sigval); } } } static void zev_print_znode_truncate(char *buf) { zev_print_znode_write(buf); } static void zev_print_znode_setattr(char *buf) { zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf; time_t op_time = rec->op_time; char *ct = ctime(&op_time); ct[24] = '\0'; printf("%s %s: file=%llu.%llu mtime=%llu\n", ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->file.ino, rec->file.gen, rec->file.mtime); } static void zev_print_znode_acl(char *buf) { zev_print_znode_setattr(buf); } static void zev_print_event(char *buf, int len) { int record_len; int op; record_len = *(uint32_t *)buf; if (record_len != len) { fprintf(stderr, "record length mismatch: got %d, expected %d\n", record_len, len); exit(1); } op = *((uint32_t *)buf + 1); if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) { fprintf(stderr, "unknown op code: %d\n", op); exit(1); } switch (op) { case ZEV_OP_ERROR: zev_print_error(buf); break; case ZEV_OP_MARK: zev_print_mark(buf); break; case ZEV_OP_ZFS_MOUNT: zev_print_zfs_mount(buf); break; case ZEV_OP_ZFS_UMOUNT: zev_print_zfs_umount(buf); break; case ZEV_OP_ZVOL_TRUNCATE: zev_print_zvol_truncate(buf); break; case ZEV_OP_ZVOL_WRITE: zev_print_zvol_write(buf); break; case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE: zev_print_znode_close_after_update(buf); break; case ZEV_OP_ZNODE_CREATE: zev_print_znode_create(buf); break; case ZEV_OP_ZNODE_MKDIR: zev_print_znode_mkdir(buf); break; case ZEV_OP_ZNODE_MAKE_XATTR_DIR: zev_print_znode_make_xattr_dir(buf); break; case ZEV_OP_ZNODE_REMOVE: zev_print_znode_remove(buf); break; case ZEV_OP_ZNODE_RMDIR: zev_print_znode_rmdir(buf); break; case ZEV_OP_ZNODE_LINK: zev_print_znode_link(buf); break; case ZEV_OP_ZNODE_SYMLINK: zev_print_znode_symlink(buf); break; case ZEV_OP_ZNODE_RENAME: zev_print_znode_rename(buf); break; case ZEV_OP_ZNODE_WRITE: zev_print_znode_write(buf); break; case ZEV_OP_ZNODE_TRUNCATE: zev_print_znode_truncate(buf); break; case ZEV_OP_ZNODE_SETATTR: zev_print_znode_setattr(buf); break; case ZEV_OP_ZNODE_ACL: zev_print_znode_acl(buf); break; default: fprintf(stderr, "unhandled op code: %d\n", op); exit(1); } } static int zev_poll_events(int fd, int create_tmp_queue) { struct pollfd pfd[1]; int ret; char buf[4096]; zev_event_t *ev; int off = 0; zev_ioctl_add_queue_t aq; int q_fd; if (create_tmp_queue) { aq.zev_max_queue_len = 0; aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL; snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN, "zevadm.%ld.%ld", time(NULL), getpid()); aq.zev_namelen = strlen(aq.zev_name); if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) { perror("adding temporary queue failed"); return (EXIT_FAILURE); } snprintf(buf, sizeof(buf), "/devices/pseudo/zev@0:%s", aq.zev_name); q_fd = open(buf, O_RDONLY); if (q_fd < 0) { perror("opening queue device failed"); return (EXIT_FAILURE); } } else { q_fd = fd; } while (1) { pfd[0].fd = q_fd; pfd[0].events = POLLIN; ret = poll(pfd, 1, 1000); if (ret < 0) { perror("poll failed"); close(q_fd); return(EXIT_FAILURE); } if (!(pfd[0].revents & POLLIN)) continue; /* data available */ ret = read(q_fd, buf, sizeof(buf)); if (ret < 0) { perror("read failed"); close(q_fd); return(EXIT_FAILURE); } if (ret == 0) continue; while (ret > off) { ev = (zev_event_t *)(buf + off); zev_print_event(buf + off, ev->header.record_len); off += ev->header.record_len; } off = 0; } if (create_tmp_queue) close(q_fd); return EXIT_SUCCESS; } static void usage(char *progname) { fprintf(stderr, "usage: %s [-d ] [options]\n", progname); fprintf(stderr, "\n"); fprintf(stderr, " Status information:\n"); fprintf(stderr, " -s show zev statistics\n"); fprintf(stderr, " -p poll for ZFS events\n"); fprintf(stderr, " -D print zev module debug " "information\n"); fprintf(stderr, "\n"); fprintf(stderr, " Tune zev module settings:\n"); fprintf(stderr, " -Q set maximum event queue " "length\n"); fprintf(stderr, " -m mute pool, no events for " "this pool\n"); fprintf(stderr, " -M unmute pool\n"); fprintf(stderr, "\n"); fprintf(stderr, " Queue management:\n"); fprintf(stderr, " -l list queues\n"); fprintf(stderr, " -a add non-blocking queue\n"); fprintf(stderr, " -A add blocking queue\n"); fprintf(stderr, " -r remove queue\n"); fprintf(stderr, " -b make queue non-blocking " "(default)\n"); fprintf(stderr, " -B make queue block when full\n"); fprintf(stderr, " -P display queue properties\n"); fprintf(stderr, " -L set maximum event queue " "length\n"); fprintf(stderr, " -t set queue length poll " "throttle\n"); fprintf(stderr, "\n"); fprintf(stderr, " Other options:\n"); fprintf(stderr, " -d non-default device file. " "('%s')\n", ZEV_DEVICE); fprintf(stderr, " -q use device file for this " "queue name\n"); fprintf(stderr, " -k : queue mark event\n"); fprintf(stderr, " -c list file's content " "checksums\n"); fprintf(stderr, " -v verbose: addition output " "for some operations\n"); exit (EXIT_FAILURE); } static int zev_add_queue(int fd, char *arg, int blocking) { zev_ioctl_add_queue_t aq; int namelen; namelen = strlen(arg); if (namelen > ZEV_MAX_QUEUE_NAME_LEN) { fprintf(stderr, "queue name too long: %s\n", arg); return (EXIT_FAILURE); } aq.zev_namelen = namelen; strcpy(aq.zev_name, arg); aq.zev_flags = ZEV_FL_PERSISTENT; if (blocking) { aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL; aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN; } else { aq.zev_max_queue_len = (1024 * 1024); } if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) { perror("adding queue failed"); return (EXIT_FAILURE); } return (0); } static int zev_remove_queue(int fd, char *arg) { zev_ioctl_remove_queue_t aq; int namelen; namelen = strlen(arg); if (namelen > ZEV_MAX_QUEUE_NAME_LEN) { fprintf(stderr, "queue name too long: %s\n", arg); return (EXIT_FAILURE); } aq.zev_queue_name.zev_namelen = namelen; strcpy(aq.zev_queue_name.zev_name, arg); if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) { perror("removing queue failed"); return (EXIT_FAILURE); } return (0); } static int zev_set_global_max_queue_len(int fd, char *arg) { uint64_t maxqueuelen; errno = 0; maxqueuelen = strtol(arg, (char **)NULL, 10); if (errno) { fprintf(stderr, "invalid queue length parameter: %s\n", arg); return (EXIT_FAILURE); } if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) { perror("setting max queue length failed"); return (EXIT_FAILURE); } return (0); } static int zev_mute_unmute_impl(int fd, char *poolname, int mute) { zev_ioctl_poolarg_t pa; int len; int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL; len = strlen(poolname); if (len <= 0 || len >= sizeof(pa.zev_poolname)) { fprintf(stderr, "invalid poolname: %s\n", poolname); return (EXIT_FAILURE); } strcpy(pa.zev_poolname, poolname); pa.zev_poolname_len = len; if (ioctl(fd, op, &pa)) { perror("muting pool data failed"); return (EXIT_FAILURE); } return (0); } int zev_mute_pool(int fd, char *poolname) { return zev_mute_unmute_impl(fd, poolname, 1); } int zev_unmute_pool(int fd, char *poolname) { return zev_mute_unmute_impl(fd, poolname, 0); } static int zev_debug_info(int fd) { zev_ioctl_debug_info_t di; if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) { perror("getting zev debug info failed"); return (EXIT_FAILURE); } printf("memory allocated: %llu bytes\n", di.zev_memory_allocated); printf("checksum cache size: %llu\n", di.zev_chksum_cache_size); printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits); printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses); return 0; } static int zev_mark(int fd, char *arg) { zev_ioctl_mark_t *mark; uint64_t guid; int len; char *p; p = strchr(arg, ':'); if (!p) { fprintf(stderr, "expected value is :, " "e.g. '123:hello'\n"); exit (EXIT_FAILURE); } *p = '\n'; p++; errno = 0; guid = strtoll(arg, (char **)NULL, 10); if (errno) { fprintf(stderr, "guid must be a number.\n"); exit (EXIT_FAILURE); } len = strlen(p); mark = malloc(sizeof(*mark) + len + 1); if (!mark) { fprintf(stderr, "can't allocate mark structure: %s\n", strerror(errno)); exit (EXIT_FAILURE); } mark->zev_guid = guid; mark->zev_mark_id = 0; mark->zev_payload_len = len; strcpy(ZEV_PAYLOAD(mark), p); if (ioctl(fd, ZEV_IOC_MARK, mark)) { perror("queueing mark failed"); return (EXIT_FAILURE); } printf("mark id: %lu\n", mark->zev_mark_id); return (0); } static int zev_queue_blocking(int fd, char *arg, int block) { zev_ioctl_get_queue_properties_t gqp; gqp.zev_queue_name.zev_namelen = strlen(arg); if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { fprintf(stderr, "queue name too long.\n"); return EXIT_FAILURE; } strcpy(gqp.zev_queue_name.zev_name, arg); if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { perror("getting queue properties failed"); return (EXIT_FAILURE); } if (block) { gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL; } else { gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL; } if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { perror("setting queue properties failed"); return (EXIT_FAILURE); } return (0); } static int zev_set_max_queue_len(int fd, char *arg, char *len) { zev_ioctl_get_queue_properties_t gqp; if (!len) { fprintf(stderr, "queue size parameter missing.\n"); return EXIT_FAILURE; } gqp.zev_queue_name.zev_namelen = strlen(arg); if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { fprintf(stderr, "queue name too long.\n"); return EXIT_FAILURE; } strcpy(gqp.zev_queue_name.zev_name, arg); if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { perror("getting queue properties failed"); return (EXIT_FAILURE); } gqp.zev_max_queue_len = atol(len); if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) { fprintf(stderr, "queue size parameter garbled.\n"); return (EXIT_FAILURE); } if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) { fprintf(stderr, "queue size parameter out of bounds.\n"); return (EXIT_FAILURE); } if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { perror("setting queue properties failed"); return (EXIT_FAILURE); } return (0); } static int zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len) { zev_ioctl_get_queue_properties_t gqp; if (!len) { fprintf(stderr, "poll throttle parameter missing.\n"); return EXIT_FAILURE; } gqp.zev_queue_name.zev_namelen = strlen(arg); if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { fprintf(stderr, "queue name too long.\n"); return EXIT_FAILURE; } strcpy(gqp.zev_queue_name.zev_name, arg); if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { perror("getting queue properties failed"); return (EXIT_FAILURE); } gqp.zev_poll_wakeup_threshold = atol(len); if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) { fprintf(stderr, "poll throttle parameter garbled.\n"); return (EXIT_FAILURE); } if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) { fprintf(stderr, "poll throttle parameter out of bounds.\n"); return (EXIT_FAILURE); } if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) { perror("setting queue properties failed"); return (EXIT_FAILURE); } return (0); } static int zev_queue_properties(int fd, char *arg) { zev_ioctl_get_queue_properties_t gqp; gqp.zev_queue_name.zev_namelen = strlen(arg); if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) { fprintf(stderr, "queue name too long.\n"); return EXIT_FAILURE; } strcpy(gqp.zev_queue_name.zev_name, arg); if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) { perror("getting queue properties failed"); return (EXIT_FAILURE); } printf("queue : %s\n", arg); printf("max size : %" PRIu64 "\n", gqp.zev_max_queue_len); printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold); printf("persistent : %s\n", gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no"); printf("blocking : %s\n", gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no"); return (0); } static int zev_list_queues(int fd) { zev_ioctl_get_queue_properties_t gqp; zev_ioctl_get_queue_list_t gql; zev_ioctl_get_queue_statistics_t gs; uint64_t i; char name[ZEV_MAX_QUEUE_NAME_LEN+1]; if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) { perror("getting queue list failed"); return (EXIT_FAILURE); } printf("Name Size " "Max Size Wakeup Per Block\n"); for (i=0; izev_fd = fd; gs->zev_bufsize = buf_size; off = 0; data = 0; while (1) { errno = 0; data = llseek(fd, off, SEEK_DATA); if (data < 0) { if (errno == ENXIO) /* no more data */ break; perror("llseek failed"); goto err; } data = P2ALIGN(data, ZEV_L1_SIZE); off = data + ZEV_L1_SIZE; gs->zev_offset = data; gs->zev_len = ZEV_L1_SIZE; if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) { perror("ioctl to get signatures failed"); goto err; } for (i=0; izev_signature_cnt; i++) { sig = (zev_sig_t *)ZEV_SIGNATURES(gs); sig += i; sig2hex_direct(sig->value, sigval); printf("level %d, offset %llu, value %s\n", sig->level, sig->block_offset, sigval); } } free(buf); close(fd); return 0; err: free(buf); close(fd); return (EXIT_FAILURE); } int main(int argc, char **argv) { int fd; int c; extern char *optarg; int create_tmp_queue = 1; char buf[MAXPATHLEN]; /* open device */ fd = open(zev_device, O_RDONLY); if (fd < 0) { perror("opening zev device failed"); return EXIT_FAILURE; } while ((c = getopt(argc, argv, "vspc:d:Dlk:L:q:Qt:m:M:a:A:r:P:b:B:h?")) != -1){ switch(c) { case 'v': verbose++; break; case 's': return zev_statistics(fd); case 'p': return zev_poll_events(fd, create_tmp_queue); case 'c': return zev_checksum(fd, optarg); case 'D': return zev_debug_info(fd); case 'd': close(fd); zev_device = optarg; fd = open(zev_device, O_RDONLY); if (fd < 0) { perror("opening zev device failed"); return EXIT_FAILURE; } create_tmp_queue = 0; break; case 'q': snprintf(buf, sizeof(buf), "/devices/pseudo/zev@0:%s", optarg); close(fd); zev_device = buf; fd = open(zev_device, O_RDONLY); if (fd < 0) { perror("opening zev device failed"); return EXIT_FAILURE; } create_tmp_queue = 0; break; case 'l': return zev_list_queues(fd); case 'Q': return zev_set_global_max_queue_len(fd, optarg); case 'L': return zev_set_max_queue_len(fd, optarg, argv[optind]); case 't': return zev_set_poll_wakeup_queue_len(fd, optarg, argv[optind]); case 'm': return zev_mute_pool(fd, optarg); case 'M': return zev_unmute_pool(fd, optarg); case 'k': return zev_mark(fd, optarg); case 'a': return zev_add_queue(fd, optarg, 0); case 'A': return zev_add_queue(fd, optarg, 1); case 'r': return zev_remove_queue(fd, optarg); case 'b': return zev_queue_blocking(fd, optarg, 0); case 'B': return zev_queue_blocking(fd, optarg, 1); case 'P': return zev_queue_properties(fd, optarg); case 'h': case '?': default: usage(argv[0]); } } usage(argv[0]); close(fd); return EXIT_FAILURE; }