X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzvol.c;h=b516156372448a286f8e68c761314048d8334ac4;hb=refs%2Fheads%2Frertzinger%2Ffeature-zpool-get--p;hp=f8e32567609ff3cef794c152120011ef355995e8;hpb=b01615d5ac86913da1e092d0378bfb8f0e72af30;p=zfs.git diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index f8e3256..b516156 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -941,7 +941,8 @@ zvol_first_open(zvol_state_t *zv) zv->zv_zilog = zil_open(os, zvol_get_data); VERIFY(dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL) == 0); - if (ro || dmu_objset_is_snapshot(os)) { + if (ro || dmu_objset_is_snapshot(os) || + !spa_writeable(dmu_objset_spa(os))) { set_disk_ro(zv->zv_disk, 1); zv->zv_flags |= ZVOL_RDONLY; } else { @@ -1023,7 +1024,11 @@ out_mutex: return (error); } +#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID +static void +#else static int +#endif zvol_release(struct gendisk *disk, fmode_t mode) { zvol_state_t *zv = disk->private_data; @@ -1043,7 +1048,9 @@ zvol_release(struct gendisk *disk, fmode_t mode) if (drop_mutex) mutex_exit(&zvol_state_lock); +#ifndef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID return (0); +#endif } static int @@ -1213,8 +1220,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) @@ -1249,9 +1257,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; @@ -1266,7 +1271,7 @@ out_queue: blk_cleanup_queue(zv->zv_queue); out_kmem: kmem_free(zv, sizeof (zvol_state_t)); -out: + return NULL; } @@ -1287,7 +1292,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; @@ -1304,6 +1330,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); @@ -1352,10 +1384,12 @@ __zvol_create_minor(const char *name) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zv->zv_queue); #endif - if (zil_replay_disable) - zil_destroy(dmu_objset_zil(os), B_FALSE); - else - zil_replay(os, zv, zvol_replay_vector); + if (spa_writeable(dmu_objset_spa(os))) { + if (zil_replay_disable) + zil_destroy(dmu_objset_zil(os), B_FALSE); + else + zil_replay(os, zv, zvol_replay_vector); + } zv->zv_objset = NULL; out_dmu_objset_disown: @@ -1383,7 +1417,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); @@ -1431,7 +1465,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); } @@ -1499,35 +1533,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