aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c')
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c155
1 files changed, 93 insertions, 62 deletions
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c
index 212ef560db07..72a7c4ea082a 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c
@@ -1248,9 +1248,11 @@ zvol_os_is_zvol(const char *device)
return (device && strncmp(device, ZVOL_DIR, strlen(ZVOL_DIR)) == 0);
}
-void
+int
zvol_os_rename_minor(zvol_state_t *zv, const char *newname)
{
+ int error = 0;
+
ASSERT(RW_LOCK_HELD(&zvol_state_lock));
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
@@ -1304,14 +1306,94 @@ zvol_os_rename_minor(zvol_state_t *zv, const char *newname)
args.mda_gid = GID_OPERATOR;
args.mda_mode = 0640;
args.mda_si_drv2 = zv;
- if (make_dev_s(&args, &dev, "%s/%s", ZVOL_DRIVER, newname)
- == 0) {
+ error = make_dev_s(&args, &dev, "%s/%s", ZVOL_DRIVER, newname);
+ if (error == 0) {
dev->si_iosize_max = maxphys;
zsd->zsd_cdev = dev;
}
}
strlcpy(zv->zv_name, newname, sizeof (zv->zv_name));
dataset_kstats_rename(&zv->zv_kstat, newname);
+
+ return (error);
+}
+
+/*
+ * Allocate memory for a new zvol_state_t and setup the required
+ * request queue and generic disk structures for the block device.
+ */
+static int
+zvol_alloc(const char *name, uint64_t volsize, uint64_t volblocksize,
+ zvol_state_t **zvp)
+{
+ zvol_state_t *zv;
+ uint64_t volmode;
+ int error;
+
+ error = dsl_prop_get_integer(name, zfs_prop_to_name(ZFS_PROP_VOLMODE),
+ &volmode, NULL);
+ if (error)
+ return (error);
+
+ if (volmode == ZFS_VOLMODE_DEFAULT)
+ volmode = zvol_volmode;
+
+ if (volmode == ZFS_VOLMODE_NONE)
+ return (0);
+
+ zv = kmem_zalloc(sizeof (*zv), KM_SLEEP);
+ mutex_init(&zv->zv_state_lock, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&zv->zv_removing_cv, NULL, CV_DEFAULT, NULL);
+ zv->zv_zso = kmem_zalloc(sizeof (struct zvol_state_os), KM_SLEEP);
+ zv->zv_volmode = volmode;
+ zv->zv_volsize = volsize;
+ zv->zv_volblocksize = volblocksize;
+ if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
+ struct zvol_state_geom *zsg = &zv->zv_zso->zso_geom;
+ struct g_provider *pp;
+ struct g_geom *gp;
+
+ g_topology_lock();
+ gp = g_new_geomf(&zfs_zvol_class, "zfs::zvol::%s", name);
+ gp->start = zvol_geom_bio_start;
+ gp->access = zvol_geom_access;
+ pp = g_new_providerf(gp, "%s/%s", ZVOL_DRIVER, name);
+ pp->flags |= G_PF_DIRECT_RECEIVE | G_PF_DIRECT_SEND;
+ pp->sectorsize = DEV_BSIZE;
+ pp->mediasize = 0;
+ pp->private = zv;
+
+ zsg->zsg_provider = pp;
+ } else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
+ struct zvol_state_dev *zsd = &zv->zv_zso->zso_dev;
+ struct cdev *dev;
+ struct make_dev_args args;
+
+ make_dev_args_init(&args);
+ args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
+ args.mda_devsw = &zvol_cdevsw;
+ args.mda_cr = NULL;
+ args.mda_uid = UID_ROOT;
+ args.mda_gid = GID_OPERATOR;
+ args.mda_mode = 0640;
+ args.mda_si_drv2 = zv;
+ error = make_dev_s(&args, &dev, "%s/%s", ZVOL_DRIVER, name);
+ if (error) {
+ kmem_free(zv->zv_zso, sizeof (struct zvol_state_os));
+ kmem_free(zv, sizeof (zvol_state_t));
+ return (error);
+ }
+
+ dev->si_iosize_max = maxphys;
+ zsd->zsd_cdev = dev;
+ knlist_init_sx(&zsd->zsd_selinfo.si_note, &zv->zv_state_lock);
+ }
+ (void) strlcpy(zv->zv_name, name, MAXPATHLEN);
+ rw_init(&zv->zv_suspend_lock, NULL, RW_DEFAULT, NULL);
+ zfs_rangelock_init(&zv->zv_rangelock, NULL, NULL);
+
+ *zvp = zv;
+ return (error);
}
/*
@@ -1364,11 +1446,11 @@ zvol_os_free(zvol_state_t *zv)
int
zvol_os_create_minor(const char *name)
{
- zvol_state_t *zv;
+ zvol_state_t *zv = NULL;
objset_t *os;
dmu_object_info_t *doi;
uint64_t volsize;
- uint64_t volmode, hash, len;
+ uint64_t hash, len;
int error;
bool replayed_zil = B_FALSE;
@@ -1400,67 +1482,15 @@ zvol_os_create_minor(const char *name)
if (error)
goto out_dmu_objset_disown;
- error = dsl_prop_get_integer(name,
- zfs_prop_to_name(ZFS_PROP_VOLMODE), &volmode, NULL);
- if (error || volmode == ZFS_VOLMODE_DEFAULT)
- volmode = zvol_volmode;
- error = 0;
+ error = zvol_alloc(name, volsize, doi->doi_data_block_size, &zv);
+ if (error || zv == NULL)
+ goto out_dmu_objset_disown;
- /*
- * zvol_alloc equivalent ...
- */
- zv = kmem_zalloc(sizeof (*zv), KM_SLEEP);
zv->zv_hash = hash;
- mutex_init(&zv->zv_state_lock, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&zv->zv_removing_cv, NULL, CV_DEFAULT, NULL);
- zv->zv_zso = kmem_zalloc(sizeof (struct zvol_state_os), KM_SLEEP);
- zv->zv_volmode = volmode;
- if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
- struct zvol_state_geom *zsg = &zv->zv_zso->zso_geom;
- struct g_provider *pp;
- struct g_geom *gp;
-
- g_topology_lock();
- gp = g_new_geomf(&zfs_zvol_class, "zfs::zvol::%s", name);
- gp->start = zvol_geom_bio_start;
- gp->access = zvol_geom_access;
- pp = g_new_providerf(gp, "%s/%s", ZVOL_DRIVER, name);
- pp->flags |= G_PF_DIRECT_RECEIVE | G_PF_DIRECT_SEND;
- pp->sectorsize = DEV_BSIZE;
- pp->mediasize = 0;
- pp->private = zv;
-
- zsg->zsg_provider = pp;
- } else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
- struct zvol_state_dev *zsd = &zv->zv_zso->zso_dev;
- struct cdev *dev;
- struct make_dev_args args;
-
- make_dev_args_init(&args);
- args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
- args.mda_devsw = &zvol_cdevsw;
- args.mda_cr = NULL;
- args.mda_uid = UID_ROOT;
- args.mda_gid = GID_OPERATOR;
- args.mda_mode = 0640;
- args.mda_si_drv2 = zv;
- if (make_dev_s(&args, &dev, "%s/%s", ZVOL_DRIVER, name)
- == 0) {
- dev->si_iosize_max = maxphys;
- zsd->zsd_cdev = dev;
- knlist_init_sx(&zsd->zsd_selinfo.si_note,
- &zv->zv_state_lock);
- }
- }
- (void) strlcpy(zv->zv_name, name, MAXPATHLEN);
- rw_init(&zv->zv_suspend_lock, NULL, RW_DEFAULT, NULL);
- zfs_rangelock_init(&zv->zv_rangelock, NULL, NULL);
if (dmu_objset_is_snapshot(os) || !spa_writeable(dmu_objset_spa(os)))
zv->zv_flags |= ZVOL_RDONLY;
- zv->zv_volblocksize = doi->doi_data_block_size;
- zv->zv_volsize = volsize;
zv->zv_objset = os;
ASSERT3P(zv->zv_kstat.dk_kstats, ==, NULL);
@@ -1490,13 +1520,14 @@ zvol_os_create_minor(const char *name)
out_dmu_objset_disown:
dmu_objset_disown(os, B_TRUE, FTAG);
- if (error == 0 && volmode == ZFS_VOLMODE_GEOM) {
+ if (error == 0 && zv && zv->zv_volmode == ZFS_VOLMODE_GEOM) {
g_error_provider(zv->zv_zso->zso_geom.zsg_provider, 0);
+ /* geom was locked inside zvol_alloc() function */
g_topology_unlock();
}
out_doi:
kmem_free(doi, sizeof (dmu_object_info_t));
- if (error == 0) {
+ if (error == 0 && zv) {
rw_enter(&zvol_state_lock, RW_WRITER);
zvol_insert(zv);
zvol_minors++;