+static void *
+zfsdev_get_state_impl(minor_t minor, enum zfsdev_state_type which)
+{
+ zfsdev_state_t *zs;
+
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+
+ for (zs = list_head(&zfsdev_state_list); zs != NULL;
+ zs = list_next(&zfsdev_state_list, zs)) {
+ if (zs->zs_minor == minor) {
+ switch (which) {
+ case ZST_ONEXIT: return (zs->zs_onexit);
+ case ZST_ZEVENT: return (zs->zs_zevent);
+ case ZST_ALL: return (zs);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void *
+zfsdev_get_state(minor_t minor, enum zfsdev_state_type which)
+{
+ void *ptr;
+
+ mutex_enter(&zfsdev_state_lock);
+ ptr = zfsdev_get_state_impl(minor, which);
+ mutex_exit(&zfsdev_state_lock);
+
+ return ptr;
+}
+
+minor_t
+zfsdev_getminor(struct file *filp)
+{
+ ASSERT(filp != NULL);
+ ASSERT(filp->private_data != NULL);
+
+ return (((zfsdev_state_t *)filp->private_data)->zs_minor);
+}
+
+/*
+ * Find a free minor number. The zfsdev_state_list is expected to
+ * be short since it is only a list of currently open file handles.
+ */
+minor_t
+zfsdev_minor_alloc(void)
+{
+ static minor_t last_minor = 0;
+ minor_t m;
+
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+
+ for (m = last_minor + 1; m != last_minor; m++) {
+ if (m > ZFSDEV_MAX_MINOR)
+ m = 1;
+ if (zfsdev_get_state_impl(m, ZST_ALL) == NULL) {
+ last_minor = m;
+ return (m);
+ }
+ }
+
+ return (0);
+}
+
+static int
+zfsdev_state_init(struct file *filp)
+{
+ zfsdev_state_t *zs;
+ minor_t minor;
+
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+
+ minor = zfsdev_minor_alloc();
+ if (minor == 0)
+ return (ENXIO);
+
+ zs = kmem_zalloc( sizeof(zfsdev_state_t), KM_SLEEP);
+ if (zs == NULL)
+ return (ENOMEM);
+
+ zs->zs_file = filp;
+ zs->zs_minor = minor;
+ filp->private_data = zs;
+
+ zfs_onexit_init((zfs_onexit_t **)&zs->zs_onexit);
+ zfs_zevent_init((zfs_zevent_t **)&zs->zs_zevent);
+
+ list_insert_tail(&zfsdev_state_list, zs);
+
+ return (0);
+}
+
+static int
+zfsdev_state_destroy(struct file *filp)
+{
+ zfsdev_state_t *zs;
+
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+ ASSERT(filp->private_data != NULL);
+
+ zs = filp->private_data;
+ zfs_onexit_destroy(zs->zs_onexit);
+ zfs_zevent_destroy(zs->zs_zevent);
+
+ list_remove(&zfsdev_state_list, zs);
+ kmem_free(zs, sizeof(zfsdev_state_t));
+
+ return 0;
+}
+
+static int
+zfsdev_open(struct inode *ino, struct file *filp)
+{
+ int error;
+
+ mutex_enter(&zfsdev_state_lock);
+ error = zfsdev_state_init(filp);
+ mutex_exit(&zfsdev_state_lock);
+
+ return (-error);
+}
+