|
|
|
@ -99,7 +99,7 @@ unsigned long zvol_max_discard_blocks = 16384;
|
|
|
|
|
unsigned int zvol_volmode = ZFS_VOLMODE_GEOM;
|
|
|
|
|
|
|
|
|
|
static taskq_t *zvol_taskq;
|
|
|
|
|
static kmutex_t zvol_state_lock;
|
|
|
|
|
static krwlock_t zvol_state_lock;
|
|
|
|
|
static list_t zvol_state_list;
|
|
|
|
|
|
|
|
|
|
#define ZVOL_HT_SIZE 1024
|
|
|
|
@ -176,17 +176,17 @@ zvol_find_by_dev(dev_t dev)
|
|
|
|
|
{
|
|
|
|
|
zvol_state_t *zv;
|
|
|
|
|
|
|
|
|
|
mutex_enter(&zvol_state_lock);
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_READER);
|
|
|
|
|
for (zv = list_head(&zvol_state_list); zv != NULL;
|
|
|
|
|
zv = list_next(&zvol_state_list, zv)) {
|
|
|
|
|
mutex_enter(&zv->zv_state_lock);
|
|
|
|
|
if (zv->zv_dev == dev) {
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
return (zv);
|
|
|
|
|
}
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
}
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
@ -204,7 +204,7 @@ zvol_find_by_name_hash(const char *name, uint64_t hash, int mode)
|
|
|
|
|
zvol_state_t *zv;
|
|
|
|
|
struct hlist_node *p = NULL;
|
|
|
|
|
|
|
|
|
|
mutex_enter(&zvol_state_lock);
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_READER);
|
|
|
|
|
hlist_for_each(p, ZVOL_HT_HEAD(hash)) {
|
|
|
|
|
zv = hlist_entry(p, zvol_state_t, zv_hlink);
|
|
|
|
|
mutex_enter(&zv->zv_state_lock);
|
|
|
|
@ -227,12 +227,12 @@ zvol_find_by_name_hash(const char *name, uint64_t hash, int mode)
|
|
|
|
|
strncmp(zv->zv_name, name, MAXNAMELEN)
|
|
|
|
|
== 0);
|
|
|
|
|
}
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
return (zv);
|
|
|
|
|
}
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
}
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
@ -339,24 +339,6 @@ zvol_get_stats(objset_t *os, nvlist_t *nv)
|
|
|
|
|
return (SET_ERROR(error));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
zvol_size_changed(zvol_state_t *zv, uint64_t volsize)
|
|
|
|
|
{
|
|
|
|
|
struct block_device *bdev;
|
|
|
|
|
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
|
|
|
|
|
|
|
|
bdev = bdget_disk(zv->zv_disk, 0);
|
|
|
|
|
if (bdev == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
set_capacity(zv->zv_disk, volsize >> 9);
|
|
|
|
|
zv->zv_volsize = volsize;
|
|
|
|
|
check_disk_size_change(zv->zv_disk, bdev);
|
|
|
|
|
|
|
|
|
|
bdput(bdev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Sanity check volume size.
|
|
|
|
|
*/
|
|
|
|
@ -409,31 +391,17 @@ zvol_update_volsize(uint64_t volsize, objset_t *os)
|
|
|
|
|
return (error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
zvol_update_live_volsize(zvol_state_t *zv, uint64_t volsize)
|
|
|
|
|
{
|
|
|
|
|
zvol_size_changed(zv, volsize);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We should post a event here describing the expansion. However,
|
|
|
|
|
* the zfs_ereport_post() interface doesn't nicely support posting
|
|
|
|
|
* events for zvols, it assumes events relate to vdevs or zios.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set ZFS_PROP_VOLSIZE set entry point.
|
|
|
|
|
* Set ZFS_PROP_VOLSIZE set entry point. Note that modifying the volume
|
|
|
|
|
* size will result in a udev "change" event being generated.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
zvol_set_volsize(const char *name, uint64_t volsize)
|
|
|
|
|
{
|
|
|
|
|
zvol_state_t *zv = NULL;
|
|
|
|
|
objset_t *os = NULL;
|
|
|
|
|
int error;
|
|
|
|
|
dmu_object_info_t *doi;
|
|
|
|
|
struct gendisk *disk = NULL;
|
|
|
|
|
uint64_t readonly;
|
|
|
|
|
int error;
|
|
|
|
|
boolean_t owned = B_FALSE;
|
|
|
|
|
|
|
|
|
|
error = dsl_prop_get_integer(name,
|
|
|
|
@ -443,7 +411,7 @@ zvol_set_volsize(const char *name, uint64_t volsize)
|
|
|
|
|
if (readonly)
|
|
|
|
|
return (SET_ERROR(EROFS));
|
|
|
|
|
|
|
|
|
|
zv = zvol_find_by_name(name, RW_READER);
|
|
|
|
|
zvol_state_t *zv = zvol_find_by_name(name, RW_READER);
|
|
|
|
|
|
|
|
|
|
ASSERT(zv == NULL || (MUTEX_HELD(&zv->zv_state_lock) &&
|
|
|
|
|
RW_READ_HELD(&zv->zv_suspend_lock)));
|
|
|
|
@ -464,16 +432,18 @@ zvol_set_volsize(const char *name, uint64_t volsize)
|
|
|
|
|
os = zv->zv_objset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP);
|
|
|
|
|
dmu_object_info_t *doi = kmem_alloc(sizeof (*doi), KM_SLEEP);
|
|
|
|
|
|
|
|
|
|
if ((error = dmu_object_info(os, ZVOL_OBJ, doi)) ||
|
|
|
|
|
(error = zvol_check_volsize(volsize, doi->doi_data_block_size)))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
error = zvol_update_volsize(volsize, os);
|
|
|
|
|
|
|
|
|
|
if (error == 0 && zv != NULL)
|
|
|
|
|
error = zvol_update_live_volsize(zv, volsize);
|
|
|
|
|
if (error == 0 && zv != NULL) {
|
|
|
|
|
zv->zv_volsize = volsize;
|
|
|
|
|
zv->zv_changed = 1;
|
|
|
|
|
disk = zv->zv_disk;
|
|
|
|
|
}
|
|
|
|
|
out:
|
|
|
|
|
kmem_free(doi, sizeof (dmu_object_info_t));
|
|
|
|
|
|
|
|
|
@ -488,6 +458,9 @@ out:
|
|
|
|
|
if (zv != NULL)
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
|
|
|
|
|
if (disk != NULL)
|
|
|
|
|
revalidate_disk(disk);
|
|
|
|
|
|
|
|
|
|
return (SET_ERROR(error));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -543,8 +516,8 @@ zvol_set_volblocksize(const char *name, uint64_t volblocksize)
|
|
|
|
|
if (zv == NULL)
|
|
|
|
|
return (SET_ERROR(ENXIO));
|
|
|
|
|
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
|
|
|
|
RW_READ_HELD(&zv->zv_suspend_lock));
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
|
|
|
ASSERT(RW_READ_HELD(&zv->zv_suspend_lock));
|
|
|
|
|
|
|
|
|
|
if (zv->zv_flags & ZVOL_RDONLY) {
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
@ -1120,7 +1093,7 @@ zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
|
|
|
|
|
static void
|
|
|
|
|
zvol_insert(zvol_state_t *zv)
|
|
|
|
|
{
|
|
|
|
|
ASSERT(MUTEX_HELD(&zvol_state_lock));
|
|
|
|
|
ASSERT(RW_WRITE_HELD(&zvol_state_lock));
|
|
|
|
|
ASSERT3U(MINOR(zv->zv_dev) & ZVOL_MINOR_MASK, ==, 0);
|
|
|
|
|
list_insert_head(&zvol_state_list, zv);
|
|
|
|
|
hlist_add_head(&zv->zv_hlink, ZVOL_HT_HEAD(zv->zv_hash));
|
|
|
|
@ -1132,7 +1105,7 @@ zvol_insert(zvol_state_t *zv)
|
|
|
|
|
static void
|
|
|
|
|
zvol_remove(zvol_state_t *zv)
|
|
|
|
|
{
|
|
|
|
|
ASSERT(MUTEX_HELD(&zvol_state_lock));
|
|
|
|
|
ASSERT(RW_WRITE_HELD(&zvol_state_lock));
|
|
|
|
|
list_remove(&zvol_state_list, zv);
|
|
|
|
|
hlist_del(&zv->zv_hlink);
|
|
|
|
|
}
|
|
|
|
@ -1148,8 +1121,8 @@ zvol_setup_zv(zvol_state_t *zv)
|
|
|
|
|
uint64_t ro;
|
|
|
|
|
objset_t *os = zv->zv_objset;
|
|
|
|
|
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
|
|
|
|
RW_LOCK_HELD(&zv->zv_suspend_lock));
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
|
|
|
ASSERT(RW_LOCK_HELD(&zv->zv_suspend_lock));
|
|
|
|
|
|
|
|
|
|
error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
|
|
|
|
|
if (error)
|
|
|
|
@ -1227,8 +1200,8 @@ zvol_suspend(const char *name)
|
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
|
|
/* block all I/O, release in zvol_resume. */
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
|
|
|
|
RW_WRITE_HELD(&zv->zv_suspend_lock));
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
|
|
|
ASSERT(RW_WRITE_HELD(&zv->zv_suspend_lock));
|
|
|
|
|
|
|
|
|
|
atomic_inc(&zv->zv_suspend_ref);
|
|
|
|
|
|
|
|
|
@ -1349,9 +1322,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|
|
|
|
int error = 0;
|
|
|
|
|
boolean_t drop_suspend = B_TRUE;
|
|
|
|
|
|
|
|
|
|
ASSERT(!MUTEX_HELD(&zvol_state_lock));
|
|
|
|
|
|
|
|
|
|
mutex_enter(&zvol_state_lock);
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_READER);
|
|
|
|
|
/*
|
|
|
|
|
* Obtain a copy of private_data under the zvol_state_lock to make
|
|
|
|
|
* sure that either the result of zvol free code path setting
|
|
|
|
@ -1360,7 +1331,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|
|
|
|
*/
|
|
|
|
|
zv = bdev->bd_disk->private_data;
|
|
|
|
|
if (zv == NULL) {
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
return (SET_ERROR(-ENXIO));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1384,7 +1355,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|
|
|
|
} else {
|
|
|
|
|
drop_suspend = B_FALSE;
|
|
|
|
|
}
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
|
|
|
ASSERT(zv->zv_open_count != 0 || RW_READ_HELD(&zv->zv_suspend_lock));
|
|
|
|
@ -1402,11 +1373,18 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|
|
|
|
|
|
|
|
|
zv->zv_open_count++;
|
|
|
|
|
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
if (drop_suspend)
|
|
|
|
|
rw_exit(&zv->zv_suspend_lock);
|
|
|
|
|
|
|
|
|
|
check_disk_change(bdev);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
out_open_count:
|
|
|
|
|
if (zv->zv_open_count == 0)
|
|
|
|
|
zvol_last_close(zv);
|
|
|
|
|
|
|
|
|
|
out_mutex:
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
if (drop_suspend)
|
|
|
|
@ -1427,9 +1405,7 @@ zvol_release(struct gendisk *disk, fmode_t mode)
|
|
|
|
|
zvol_state_t *zv;
|
|
|
|
|
boolean_t drop_suspend = B_TRUE;
|
|
|
|
|
|
|
|
|
|
ASSERT(!MUTEX_HELD(&zvol_state_lock));
|
|
|
|
|
|
|
|
|
|
mutex_enter(&zvol_state_lock);
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_READER);
|
|
|
|
|
zv = disk->private_data;
|
|
|
|
|
|
|
|
|
|
mutex_enter(&zv->zv_state_lock);
|
|
|
|
@ -1453,7 +1429,7 @@ zvol_release(struct gendisk *disk, fmode_t mode)
|
|
|
|
|
} else {
|
|
|
|
|
drop_suspend = B_FALSE;
|
|
|
|
|
}
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
|
|
|
ASSERT(zv->zv_open_count != 1 || RW_READ_HELD(&zv->zv_suspend_lock));
|
|
|
|
@ -1479,7 +1455,7 @@ zvol_ioctl(struct block_device *bdev, fmode_t mode,
|
|
|
|
|
zvol_state_t *zv = bdev->bd_disk->private_data;
|
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
|
|
ASSERT(zv && zv->zv_open_count > 0);
|
|
|
|
|
ASSERT3U(zv->zv_open_count, >, 0);
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case BLKFLSBUF:
|
|
|
|
@ -1519,23 +1495,62 @@ zvol_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
|
|
|
|
#define zvol_compat_ioctl NULL
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Linux 2.6.38 preferred interface.
|
|
|
|
|
*/
|
|
|
|
|
#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
|
|
|
|
static unsigned int
|
|
|
|
|
zvol_check_events(struct gendisk *disk, unsigned int clearing)
|
|
|
|
|
{
|
|
|
|
|
unsigned int mask = 0;
|
|
|
|
|
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_READER);
|
|
|
|
|
|
|
|
|
|
zvol_state_t *zv = disk->private_data;
|
|
|
|
|
if (zv != NULL) {
|
|
|
|
|
mutex_enter(&zv->zv_state_lock);
|
|
|
|
|
mask = zv->zv_changed ? DISK_EVENT_MEDIA_CHANGE : 0;
|
|
|
|
|
zv->zv_changed = 0;
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
return (mask);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
static int zvol_media_changed(struct gendisk *disk)
|
|
|
|
|
{
|
|
|
|
|
int changed = 0;
|
|
|
|
|
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_READER);
|
|
|
|
|
|
|
|
|
|
zvol_state_t *zv = disk->private_data;
|
|
|
|
|
|
|
|
|
|
ASSERT(zv && zv->zv_open_count > 0);
|
|
|
|
|
|
|
|
|
|
return (zv->zv_changed);
|
|
|
|
|
if (zv != NULL) {
|
|
|
|
|
mutex_enter(&zv->zv_state_lock);
|
|
|
|
|
changed = zv->zv_changed;
|
|
|
|
|
zv->zv_changed = 0;
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
return (changed);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static int zvol_revalidate_disk(struct gendisk *disk)
|
|
|
|
|
{
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_READER);
|
|
|
|
|
|
|
|
|
|
zvol_state_t *zv = disk->private_data;
|
|
|
|
|
if (zv != NULL) {
|
|
|
|
|
mutex_enter(&zv->zv_state_lock);
|
|
|
|
|
set_capacity(zv->zv_disk, zv->zv_volsize >> SECTOR_BITS);
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ASSERT(zv && zv->zv_open_count > 0);
|
|
|
|
|
|
|
|
|
|
zv->zv_changed = 0;
|
|
|
|
|
set_capacity(zv->zv_disk, zv->zv_volsize >> 9);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
@ -1552,7 +1567,7 @@ zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
|
|
|
|
zvol_state_t *zv = bdev->bd_disk->private_data;
|
|
|
|
|
sector_t sectors;
|
|
|
|
|
|
|
|
|
|
ASSERT(zv && zv->zv_open_count > 0);
|
|
|
|
|
ASSERT3U(zv->zv_open_count, >, 0);
|
|
|
|
|
|
|
|
|
|
sectors = get_capacity(zv->zv_disk);
|
|
|
|
|
|
|
|
|
@ -1585,68 +1600,20 @@ zvol_probe(dev_t dev, int *part, void *arg)
|
|
|
|
|
return (kobj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_BDEV_BLOCK_DEVICE_OPERATIONS
|
|
|
|
|
static struct block_device_operations zvol_ops = {
|
|
|
|
|
.open = zvol_open,
|
|
|
|
|
.release = zvol_release,
|
|
|
|
|
.ioctl = zvol_ioctl,
|
|
|
|
|
.compat_ioctl = zvol_compat_ioctl,
|
|
|
|
|
.media_changed = zvol_media_changed,
|
|
|
|
|
.revalidate_disk = zvol_revalidate_disk,
|
|
|
|
|
.getgeo = zvol_getgeo,
|
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#else /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
zvol_open_by_inode(struct inode *inode, struct file *file)
|
|
|
|
|
{
|
|
|
|
|
return (zvol_open(inode->i_bdev, file->f_mode));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
zvol_release_by_inode(struct inode *inode, struct file *file)
|
|
|
|
|
{
|
|
|
|
|
return (zvol_release(inode->i_bdev->bd_disk, file->f_mode));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
zvol_ioctl_by_inode(struct inode *inode, struct file *file,
|
|
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
|
{
|
|
|
|
|
if (file == NULL || inode == NULL)
|
|
|
|
|
return (SET_ERROR(-EINVAL));
|
|
|
|
|
|
|
|
|
|
return (zvol_ioctl(inode->i_bdev, file->f_mode, cmd, arg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
|
static long
|
|
|
|
|
zvol_compat_ioctl_by_inode(struct file *file,
|
|
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
|
{
|
|
|
|
|
if (file == NULL)
|
|
|
|
|
return (SET_ERROR(-EINVAL));
|
|
|
|
|
|
|
|
|
|
return (zvol_compat_ioctl(file->f_dentry->d_inode->i_bdev,
|
|
|
|
|
file->f_mode, cmd, arg));
|
|
|
|
|
}
|
|
|
|
|
#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
|
|
|
|
.check_events = zvol_check_events,
|
|
|
|
|
#else
|
|
|
|
|
#define zvol_compat_ioctl_by_inode NULL
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static struct block_device_operations zvol_ops = {
|
|
|
|
|
.open = zvol_open_by_inode,
|
|
|
|
|
.release = zvol_release_by_inode,
|
|
|
|
|
.ioctl = zvol_ioctl_by_inode,
|
|
|
|
|
.compat_ioctl = zvol_compat_ioctl_by_inode,
|
|
|
|
|
.media_changed = zvol_media_changed,
|
|
|
|
|
#endif
|
|
|
|
|
.revalidate_disk = zvol_revalidate_disk,
|
|
|
|
|
.getgeo = zvol_getgeo,
|
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
|
};
|
|
|
|
|
#endif /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Allocate memory for a new zvol_state_t and setup the required
|
|
|
|
@ -1699,6 +1666,10 @@ zvol_alloc(dev_t dev, const char *name)
|
|
|
|
|
rw_init(&zv->zv_suspend_lock, NULL, RW_DEFAULT, NULL);
|
|
|
|
|
|
|
|
|
|
zv->zv_disk->major = zvol_major;
|
|
|
|
|
#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
|
|
|
|
zv->zv_disk->events = DISK_EVENT_MEDIA_CHANGE;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (volmode == ZFS_VOLMODE_DEV) {
|
|
|
|
|
/*
|
|
|
|
|
* ZFS_VOLMODE_DEV disable partitioning on ZVOL devices: set
|
|
|
|
@ -1743,7 +1714,6 @@ zvol_free(void *arg)
|
|
|
|
|
{
|
|
|
|
|
zvol_state_t *zv = arg;
|
|
|
|
|
|
|
|
|
|
ASSERT(!MUTEX_HELD(&zvol_state_lock));
|
|
|
|
|
ASSERT(!RW_LOCK_HELD(&zv->zv_suspend_lock));
|
|
|
|
|
ASSERT(!MUTEX_HELD(&zv->zv_state_lock));
|
|
|
|
|
ASSERT(zv->zv_open_count == 0);
|
|
|
|
@ -1870,9 +1840,9 @@ out_doi:
|
|
|
|
|
kmem_free(doi, sizeof (dmu_object_info_t));
|
|
|
|
|
|
|
|
|
|
if (error == 0) {
|
|
|
|
|
mutex_enter(&zvol_state_lock);
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_WRITER);
|
|
|
|
|
zvol_insert(zv);
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
add_disk(zv->zv_disk);
|
|
|
|
|
} else {
|
|
|
|
|
ida_simple_remove(&zvol_ida, idx);
|
|
|
|
@ -1889,7 +1859,7 @@ zvol_rename_minor(zvol_state_t *zv, const char *newname)
|
|
|
|
|
{
|
|
|
|
|
int readonly = get_disk_ro(zv->zv_disk);
|
|
|
|
|
|
|
|
|
|
ASSERT(MUTEX_HELD(&zvol_state_lock));
|
|
|
|
|
ASSERT(RW_LOCK_HELD(&zvol_state_lock));
|
|
|
|
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
|
|
|
|
|
|
|
|
|
strlcpy(zv->zv_name, newname, sizeof (zv->zv_name));
|
|
|
|
@ -2129,7 +2099,7 @@ zvol_remove_minors_impl(const char *name)
|
|
|
|
|
list_create(&free_list, sizeof (zvol_state_t),
|
|
|
|
|
offsetof(zvol_state_t, zv_next));
|
|
|
|
|
|
|
|
|
|
mutex_enter(&zvol_state_lock);
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_WRITER);
|
|
|
|
|
|
|
|
|
|
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
|
|
|
|
zv_next = list_next(&zvol_state_list, zv);
|
|
|
|
@ -2154,15 +2124,15 @@ zvol_remove_minors_impl(const char *name)
|
|
|
|
|
zvol_remove(zv);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* clear this while holding zvol_state_lock so
|
|
|
|
|
* zvol_open won't open it
|
|
|
|
|
* Cleared while holding zvol_state_lock as a writer
|
|
|
|
|
* which will prevent zvol_open() from opening it.
|
|
|
|
|
*/
|
|
|
|
|
zv->zv_disk->private_data = NULL;
|
|
|
|
|
|
|
|
|
|
/* Drop zv_state_lock before zvol_free() */
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
|
|
|
|
|
/* try parallel zv_free, if failed do it in place */
|
|
|
|
|
/* Try parallel zv_free, if failed do it in place */
|
|
|
|
|
t = taskq_dispatch(system_taskq, zvol_free, zv,
|
|
|
|
|
TQ_SLEEP);
|
|
|
|
|
if (t == TASKQID_INVALID)
|
|
|
|
@ -2173,11 +2143,9 @@ zvol_remove_minors_impl(const char *name)
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Drop zvol_state_lock before calling zvol_free()
|
|
|
|
|
*/
|
|
|
|
|
/* Drop zvol_state_lock before calling zvol_free() */
|
|
|
|
|
while ((zv = list_head(&free_list)) != NULL) {
|
|
|
|
|
list_remove(&free_list, zv);
|
|
|
|
|
zvol_free(zv);
|
|
|
|
@ -2196,7 +2164,7 @@ zvol_remove_minor_impl(const char *name)
|
|
|
|
|
if (zvol_inhibit_dev)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
mutex_enter(&zvol_state_lock);
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_WRITER);
|
|
|
|
|
|
|
|
|
|
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
|
|
|
|
zv_next = list_next(&zvol_state_list, zv);
|
|
|
|
@ -2216,7 +2184,10 @@ zvol_remove_minor_impl(const char *name)
|
|
|
|
|
}
|
|
|
|
|
zvol_remove(zv);
|
|
|
|
|
|
|
|
|
|
/* clear this so zvol_open won't open it */
|
|
|
|
|
/*
|
|
|
|
|
* Cleared while holding zvol_state_lock as a writer
|
|
|
|
|
* which will prevent zvol_open() from opening it.
|
|
|
|
|
*/
|
|
|
|
|
zv->zv_disk->private_data = NULL;
|
|
|
|
|
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
@ -2227,7 +2198,7 @@ zvol_remove_minor_impl(const char *name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Drop zvol_state_lock before calling zvol_free() */
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
if (zv != NULL)
|
|
|
|
|
zvol_free(zv);
|
|
|
|
@ -2248,7 +2219,7 @@ zvol_rename_minors_impl(const char *oldname, const char *newname)
|
|
|
|
|
oldnamelen = strlen(oldname);
|
|
|
|
|
newnamelen = strlen(newname);
|
|
|
|
|
|
|
|
|
|
mutex_enter(&zvol_state_lock);
|
|
|
|
|
rw_enter(&zvol_state_lock, RW_READER);
|
|
|
|
|
|
|
|
|
|
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
|
|
|
|
zv_next = list_next(&zvol_state_list, zv);
|
|
|
|
@ -2276,7 +2247,7 @@ zvol_rename_minors_impl(const char *oldname, const char *newname)
|
|
|
|
|
mutex_exit(&zv->zv_state_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_exit(&zvol_state_lock);
|
|
|
|
|
rw_exit(&zvol_state_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct zvol_snapdev_cb_arg {
|
|
|
|
@ -2653,7 +2624,7 @@ zvol_init(void)
|
|
|
|
|
|
|
|
|
|
list_create(&zvol_state_list, sizeof (zvol_state_t),
|
|
|
|
|
offsetof(zvol_state_t, zv_next));
|
|
|
|
|
mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
|
|
|
|
|
rw_init(&zvol_state_lock, NULL, RW_DEFAULT, NULL);
|
|
|
|
|
ida_init(&zvol_ida);
|
|
|
|
|
|
|
|
|
|
zvol_taskq = taskq_create(ZVOL_DRIVER, threads, maxclsyspri,
|
|
|
|
@ -2690,7 +2661,7 @@ out_taskq:
|
|
|
|
|
taskq_destroy(zvol_taskq);
|
|
|
|
|
out:
|
|
|
|
|
ida_destroy(&zvol_ida);
|
|
|
|
|
mutex_destroy(&zvol_state_lock);
|
|
|
|
|
rw_destroy(&zvol_state_lock);
|
|
|
|
|
list_destroy(&zvol_state_list);
|
|
|
|
|
|
|
|
|
|
return (SET_ERROR(error));
|
|
|
|
@ -2707,7 +2678,7 @@ zvol_fini(void)
|
|
|
|
|
|
|
|
|
|
taskq_destroy(zvol_taskq);
|
|
|
|
|
list_destroy(&zvol_state_list);
|
|
|
|
|
mutex_destroy(&zvol_state_lock);
|
|
|
|
|
rw_destroy(&zvol_state_lock);
|
|
|
|
|
|
|
|
|
|
ida_destroy(&zvol_ida);
|
|
|
|
|
}
|
|
|
|
|