Open pools asynchronously after module load
[zfs.git] / module / zfs / zvol.c
index b0d59fe..e35c91b 100644 (file)
@@ -1214,8 +1214,9 @@ zvol_alloc(dev_t dev, const char *name)
        int error = 0;
 
        zv = kmem_zalloc(sizeof (zvol_state_t), KM_SLEEP);
-       if (zv == NULL)
-               goto out;
+
+       spin_lock_init(&zv->zv_lock);
+       list_link_init(&zv->zv_next);
 
        zv->zv_queue = blk_init_queue(zvol_request, &zv->zv_lock);
        if (zv->zv_queue == NULL)
@@ -1250,9 +1251,6 @@ zvol_alloc(dev_t dev, const char *name)
            sizeof (rl_t), offsetof(rl_t, r_node));
        zv->zv_znode.z_is_zvol = TRUE;
 
-       spin_lock_init(&zv->zv_lock);
-       list_link_init(&zv->zv_next);
-
        zv->zv_disk->major = zvol_major;
        zv->zv_disk->first_minor = (dev & MINORMASK);
        zv->zv_disk->fops = &zvol_ops;
@@ -1267,7 +1265,7 @@ out_queue:
        blk_cleanup_queue(zv->zv_queue);
 out_kmem:
        kmem_free(zv, sizeof (zvol_state_t));
-out:
+
        return NULL;
 }
 
@@ -1288,7 +1286,28 @@ zvol_free(zvol_state_t *zv)
 }
 
 static int
-__zvol_create_minor(const char *name)
+__zvol_snapdev_hidden(const char *name)
+{
+        uint64_t snapdev;
+        char *parent;
+        char *atp;
+        int error = 0;
+
+        parent = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+        (void) strlcpy(parent, name, MAXPATHLEN);
+
+        if ((atp = strrchr(parent, '@')) != NULL) {
+                *atp = '\0';
+                error = dsl_prop_get_integer(parent, "snapdev", &snapdev, NULL);
+                if ((error == 0) && (snapdev == ZFS_SNAPDEV_HIDDEN))
+                        error = ENODEV;
+        }
+        kmem_free(parent, MAXPATHLEN);
+        return (error);
+}
+
+static int
+__zvol_create_minor(const char *name, boolean_t ignore_snapdev)
 {
        zvol_state_t *zv;
        objset_t *os;
@@ -1305,6 +1324,12 @@ __zvol_create_minor(const char *name)
                goto out;
        }
 
+       if (ignore_snapdev == B_FALSE) {
+               error = __zvol_snapdev_hidden(name);
+               if (error)
+                       goto out;
+       }
+
        doi = kmem_alloc(sizeof(dmu_object_info_t), KM_SLEEP);
 
        error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, zvol_tag, &os);
@@ -1386,7 +1411,7 @@ zvol_create_minor(const char *name)
        int error;
 
        mutex_enter(&zvol_state_lock);
-       error = __zvol_create_minor(name);
+       error = __zvol_create_minor(name, B_FALSE);
        mutex_exit(&zvol_state_lock);
 
        return (error);
@@ -1434,7 +1459,7 @@ zvol_create_minors_cb(spa_t *spa, uint64_t dsobj,
        if (strchr(dsname, '/') == NULL)
                return 0;
 
-       (void) __zvol_create_minor(dsname);
+       (void) __zvol_create_minor(dsname, B_FALSE);
        return (0);
 }
 
@@ -1502,35 +1527,70 @@ zvol_remove_minors(const char *pool)
        kmem_free(str, MAXNAMELEN);
 }
 
+static int
+snapdev_snapshot_changed_cb(const char *dsname, void *arg) {
+       uint64_t snapdev = *(uint64_t *) arg;
+
+       if (strchr(dsname, '@') == NULL)
+               return 0;
+
+       switch (snapdev) {
+               case ZFS_SNAPDEV_VISIBLE:
+                       mutex_enter(&zvol_state_lock);
+                       (void) __zvol_create_minor(dsname, B_TRUE);
+                       mutex_exit(&zvol_state_lock);
+                       break;
+               case ZFS_SNAPDEV_HIDDEN:
+                       (void) zvol_remove_minor(dsname);
+                       break;
+       }
+       return 0;
+}
+
+int
+zvol_set_snapdev(const char *dsname, uint64_t snapdev) {
+       (void) dmu_objset_find((char *) dsname, snapdev_snapshot_changed_cb,
+               &snapdev, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
+       /* caller should continue to modify snapdev property */
+       return (-1);
+}
+
+
 int
 zvol_init(void)
 {
        int error;
 
+       list_create(&zvol_state_list, sizeof (zvol_state_t),
+                   offsetof(zvol_state_t, zv_next));
+       mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
+
        zvol_taskq = taskq_create(ZVOL_DRIVER, zvol_threads, maxclsyspri,
                                  zvol_threads, INT_MAX, TASKQ_PREPOPULATE);
        if (zvol_taskq == NULL) {
                printk(KERN_INFO "ZFS: taskq_create() failed\n");
-               return (-ENOMEM);
+               error = -ENOMEM;
+               goto out1;
        }
 
        error = register_blkdev(zvol_major, ZVOL_DRIVER);
        if (error) {
                printk(KERN_INFO "ZFS: register_blkdev() failed %d\n", error);
-               taskq_destroy(zvol_taskq);
-               return (error);
+               goto out2;
        }
 
        blk_register_region(MKDEV(zvol_major, 0), 1UL << MINORBITS,
                            THIS_MODULE, zvol_probe, NULL, NULL);
 
-       mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
-       list_create(&zvol_state_list, sizeof (zvol_state_t),
-                   offsetof(zvol_state_t, zv_next));
+       return (0);
 
-       (void) zvol_create_minors(NULL);
+out2:
+       taskq_destroy(zvol_taskq);
+out1:
+       mutex_destroy(&zvol_state_lock);
+       list_destroy(&zvol_state_list);
 
-       return (0);
+       return (error);
 }
 
 void