Linux compat 4.18: check_disk_size_change()
Added support for the bops->check_events() interface which was added in the 2.6.38 kernel to replace bops->media_changed(). Fully implementing this functionality allows the volume resize code to rely on revalidate_disk(), which is the preferred mechanism, and removes the need to use check_disk_size_change(). In order for bops->check_events() to lookup the zvol_state_t stored in the disk->private_data the zvol_state_lock needs to be held. Since the check events interface may poll the mutex has been converted to a rwlock for better concurrently. The rwlock need only be taken as a writer in the zvol_free() path when disk->private_data is set to NULL. The configure checks for the block_device_operations structure were consolidated in a single kernel-block-device-operations.m4 file. The ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS configure checks and assoicated dead code was removed. This interface was added to the 2.6.28 kernel which predates the oldest supported 2.6.32 kernel and will therefore always be available. Updated maximum Linux version in META file. The 4.17 kernel was released on 2018-06-03 and ZoL is compatible with the finalized kernel. Reviewed-by: Boris Protopopov <boris.protopopov@actifio.com> Reviewed-by: Sara Hartse <sara.hartse@delphix.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #7611
This commit is contained in:
parent
f79c0de208
commit
a2f759146d
|
@ -1,34 +0,0 @@
|
||||||
dnl #
|
|
||||||
dnl # 2.6.x API change
|
|
||||||
dnl #
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS], [
|
|
||||||
AC_MSG_CHECKING([block device operation prototypes])
|
|
||||||
tmp_flags="$EXTRA_KCFLAGS"
|
|
||||||
EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
|
|
||||||
ZFS_LINUX_TRY_COMPILE([
|
|
||||||
#include <linux/blkdev.h>
|
|
||||||
|
|
||||||
int blk_open(struct block_device *bdev, fmode_t mode)
|
|
||||||
{ return 0; }
|
|
||||||
int blk_ioctl(struct block_device *bdev, fmode_t mode,
|
|
||||||
unsigned x, unsigned long y) { return 0; }
|
|
||||||
int blk_compat_ioctl(struct block_device * bdev, fmode_t mode,
|
|
||||||
unsigned x, unsigned long y) { return 0; }
|
|
||||||
|
|
||||||
static const struct block_device_operations
|
|
||||||
bops __attribute__ ((unused)) = {
|
|
||||||
.open = blk_open,
|
|
||||||
.release = NULL,
|
|
||||||
.ioctl = blk_ioctl,
|
|
||||||
.compat_ioctl = blk_compat_ioctl,
|
|
||||||
};
|
|
||||||
],[
|
|
||||||
],[
|
|
||||||
AC_MSG_RESULT(struct block_device)
|
|
||||||
AC_DEFINE(HAVE_BDEV_BLOCK_DEVICE_OPERATIONS, 1,
|
|
||||||
[struct block_device_operations use bdevs])
|
|
||||||
],[
|
|
||||||
AC_MSG_RESULT(struct inode)
|
|
||||||
])
|
|
||||||
EXTRA_KCFLAGS="$tmp_flags"
|
|
||||||
])
|
|
|
@ -1,29 +0,0 @@
|
||||||
dnl #
|
|
||||||
dnl # 3.10.x API change
|
|
||||||
dnl #
|
|
||||||
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
|
|
||||||
AC_MSG_CHECKING([whether block_device_operations.release is void])
|
|
||||||
tmp_flags="$EXTRA_KCFLAGS"
|
|
||||||
EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
|
|
||||||
ZFS_LINUX_TRY_COMPILE([
|
|
||||||
#include <linux/blkdev.h>
|
|
||||||
|
|
||||||
void blk_release(struct gendisk *g, fmode_t mode) { return; }
|
|
||||||
|
|
||||||
static const struct block_device_operations
|
|
||||||
bops __attribute__ ((unused)) = {
|
|
||||||
.open = NULL,
|
|
||||||
.release = blk_release,
|
|
||||||
.ioctl = NULL,
|
|
||||||
.compat_ioctl = NULL,
|
|
||||||
};
|
|
||||||
],[
|
|
||||||
],[
|
|
||||||
AC_MSG_RESULT(void)
|
|
||||||
AC_DEFINE(HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID, 1,
|
|
||||||
[struct block_device_operations.release returns void])
|
|
||||||
],[
|
|
||||||
AC_MSG_RESULT(int)
|
|
||||||
])
|
|
||||||
EXTRA_KCFLAGS="$tmp_flags"
|
|
||||||
])
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
dnl #
|
||||||
|
dnl # 2.6.38 API change
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS], [
|
||||||
|
AC_MSG_CHECKING([whether bops->check_events() exists])
|
||||||
|
tmp_flags="$EXTRA_KCFLAGS"
|
||||||
|
EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
|
||||||
|
ZFS_LINUX_TRY_COMPILE([
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
|
||||||
|
unsigned int blk_check_events(struct gendisk *disk,
|
||||||
|
unsigned int clearing) { return (0); }
|
||||||
|
|
||||||
|
static const struct block_device_operations
|
||||||
|
bops __attribute__ ((unused)) = {
|
||||||
|
.check_events = blk_check_events,
|
||||||
|
};
|
||||||
|
],[
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS, 1,
|
||||||
|
[bops->check_events() exists])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
EXTRA_KCFLAGS="$tmp_flags"
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl #
|
||||||
|
dnl # 3.10.x API change
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
|
||||||
|
AC_MSG_CHECKING([whether bops->release() is void])
|
||||||
|
tmp_flags="$EXTRA_KCFLAGS"
|
||||||
|
EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
|
||||||
|
ZFS_LINUX_TRY_COMPILE([
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
|
||||||
|
void blk_release(struct gendisk *g, fmode_t mode) { return; }
|
||||||
|
|
||||||
|
static const struct block_device_operations
|
||||||
|
bops __attribute__ ((unused)) = {
|
||||||
|
.open = NULL,
|
||||||
|
.release = blk_release,
|
||||||
|
.ioctl = NULL,
|
||||||
|
.compat_ioctl = NULL,
|
||||||
|
};
|
||||||
|
],[
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(void)
|
||||||
|
AC_DEFINE(HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID, 1,
|
||||||
|
[bops->release() returns void])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(int)
|
||||||
|
])
|
||||||
|
EXTRA_KCFLAGS="$tmp_flags"
|
||||||
|
])
|
|
@ -12,7 +12,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
|
||||||
ZFS_AC_KERNEL_CURRENT_BIO_TAIL
|
ZFS_AC_KERNEL_CURRENT_BIO_TAIL
|
||||||
ZFS_AC_KERNEL_SUPER_USER_NS
|
ZFS_AC_KERNEL_SUPER_USER_NS
|
||||||
ZFS_AC_KERNEL_SUBMIT_BIO
|
ZFS_AC_KERNEL_SUBMIT_BIO
|
||||||
ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS
|
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
||||||
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
|
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
|
||||||
ZFS_AC_KERNEL_TYPE_FMODE_T
|
ZFS_AC_KERNEL_TYPE_FMODE_T
|
||||||
ZFS_AC_KERNEL_3ARG_BLKDEV_GET
|
ZFS_AC_KERNEL_3ARG_BLKDEV_GET
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/elevator.h>
|
#include <linux/elevator.h>
|
||||||
#include <linux/backing-dev.h>
|
#include <linux/backing-dev.h>
|
||||||
|
#include <linux/msdos_fs.h> /* for SECTOR_* */
|
||||||
|
|
||||||
#ifndef HAVE_FMODE_T
|
#ifndef HAVE_FMODE_T
|
||||||
typedef unsigned __bitwise__ fmode_t;
|
typedef unsigned __bitwise__ fmode_t;
|
||||||
|
|
|
@ -99,7 +99,7 @@ unsigned long zvol_max_discard_blocks = 16384;
|
||||||
unsigned int zvol_volmode = ZFS_VOLMODE_GEOM;
|
unsigned int zvol_volmode = ZFS_VOLMODE_GEOM;
|
||||||
|
|
||||||
static taskq_t *zvol_taskq;
|
static taskq_t *zvol_taskq;
|
||||||
static kmutex_t zvol_state_lock;
|
static krwlock_t zvol_state_lock;
|
||||||
static list_t zvol_state_list;
|
static list_t zvol_state_list;
|
||||||
|
|
||||||
#define ZVOL_HT_SIZE 1024
|
#define ZVOL_HT_SIZE 1024
|
||||||
|
@ -176,17 +176,17 @@ zvol_find_by_dev(dev_t dev)
|
||||||
{
|
{
|
||||||
zvol_state_t *zv;
|
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;
|
for (zv = list_head(&zvol_state_list); zv != NULL;
|
||||||
zv = list_next(&zvol_state_list, zv)) {
|
zv = list_next(&zvol_state_list, zv)) {
|
||||||
mutex_enter(&zv->zv_state_lock);
|
mutex_enter(&zv->zv_state_lock);
|
||||||
if (zv->zv_dev == dev) {
|
if (zv->zv_dev == dev) {
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
return (zv);
|
return (zv);
|
||||||
}
|
}
|
||||||
mutex_exit(&zv->zv_state_lock);
|
mutex_exit(&zv->zv_state_lock);
|
||||||
}
|
}
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ zvol_find_by_name_hash(const char *name, uint64_t hash, int mode)
|
||||||
zvol_state_t *zv;
|
zvol_state_t *zv;
|
||||||
struct hlist_node *p = NULL;
|
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)) {
|
hlist_for_each(p, ZVOL_HT_HEAD(hash)) {
|
||||||
zv = hlist_entry(p, zvol_state_t, zv_hlink);
|
zv = hlist_entry(p, zvol_state_t, zv_hlink);
|
||||||
mutex_enter(&zv->zv_state_lock);
|
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)
|
strncmp(zv->zv_name, name, MAXNAMELEN)
|
||||||
== 0);
|
== 0);
|
||||||
}
|
}
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
return (zv);
|
return (zv);
|
||||||
}
|
}
|
||||||
mutex_exit(&zv->zv_state_lock);
|
mutex_exit(&zv->zv_state_lock);
|
||||||
}
|
}
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
@ -339,24 +339,6 @@ zvol_get_stats(objset_t *os, nvlist_t *nv)
|
||||||
return (SET_ERROR(error));
|
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.
|
* Sanity check volume size.
|
||||||
*/
|
*/
|
||||||
|
@ -409,31 +391,17 @@ zvol_update_volsize(uint64_t volsize, objset_t *os)
|
||||||
return (error);
|
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,
|
* Set ZFS_PROP_VOLSIZE set entry point. Note that modifying the volume
|
||||||
* the zfs_ereport_post() interface doesn't nicely support posting
|
* size will result in a udev "change" event being generated.
|
||||||
* events for zvols, it assumes events relate to vdevs or zios.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set ZFS_PROP_VOLSIZE set entry point.
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zvol_set_volsize(const char *name, uint64_t volsize)
|
zvol_set_volsize(const char *name, uint64_t volsize)
|
||||||
{
|
{
|
||||||
zvol_state_t *zv = NULL;
|
|
||||||
objset_t *os = NULL;
|
objset_t *os = NULL;
|
||||||
int error;
|
struct gendisk *disk = NULL;
|
||||||
dmu_object_info_t *doi;
|
|
||||||
uint64_t readonly;
|
uint64_t readonly;
|
||||||
|
int error;
|
||||||
boolean_t owned = B_FALSE;
|
boolean_t owned = B_FALSE;
|
||||||
|
|
||||||
error = dsl_prop_get_integer(name,
|
error = dsl_prop_get_integer(name,
|
||||||
|
@ -443,7 +411,7 @@ zvol_set_volsize(const char *name, uint64_t volsize)
|
||||||
if (readonly)
|
if (readonly)
|
||||||
return (SET_ERROR(EROFS));
|
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) &&
|
ASSERT(zv == NULL || (MUTEX_HELD(&zv->zv_state_lock) &&
|
||||||
RW_READ_HELD(&zv->zv_suspend_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;
|
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)) ||
|
if ((error = dmu_object_info(os, ZVOL_OBJ, doi)) ||
|
||||||
(error = zvol_check_volsize(volsize, doi->doi_data_block_size)))
|
(error = zvol_check_volsize(volsize, doi->doi_data_block_size)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = zvol_update_volsize(volsize, os);
|
error = zvol_update_volsize(volsize, os);
|
||||||
|
if (error == 0 && zv != NULL) {
|
||||||
if (error == 0 && zv != NULL)
|
zv->zv_volsize = volsize;
|
||||||
error = zvol_update_live_volsize(zv, volsize);
|
zv->zv_changed = 1;
|
||||||
|
disk = zv->zv_disk;
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
kmem_free(doi, sizeof (dmu_object_info_t));
|
kmem_free(doi, sizeof (dmu_object_info_t));
|
||||||
|
|
||||||
|
@ -488,6 +458,9 @@ out:
|
||||||
if (zv != NULL)
|
if (zv != NULL)
|
||||||
mutex_exit(&zv->zv_state_lock);
|
mutex_exit(&zv->zv_state_lock);
|
||||||
|
|
||||||
|
if (disk != NULL)
|
||||||
|
revalidate_disk(disk);
|
||||||
|
|
||||||
return (SET_ERROR(error));
|
return (SET_ERROR(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,8 +516,8 @@ zvol_set_volblocksize(const char *name, uint64_t volblocksize)
|
||||||
if (zv == NULL)
|
if (zv == NULL)
|
||||||
return (SET_ERROR(ENXIO));
|
return (SET_ERROR(ENXIO));
|
||||||
|
|
||||||
ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
||||||
RW_READ_HELD(&zv->zv_suspend_lock));
|
ASSERT(RW_READ_HELD(&zv->zv_suspend_lock));
|
||||||
|
|
||||||
if (zv->zv_flags & ZVOL_RDONLY) {
|
if (zv->zv_flags & ZVOL_RDONLY) {
|
||||||
mutex_exit(&zv->zv_state_lock);
|
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
|
static void
|
||||||
zvol_insert(zvol_state_t *zv)
|
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);
|
ASSERT3U(MINOR(zv->zv_dev) & ZVOL_MINOR_MASK, ==, 0);
|
||||||
list_insert_head(&zvol_state_list, zv);
|
list_insert_head(&zvol_state_list, zv);
|
||||||
hlist_add_head(&zv->zv_hlink, ZVOL_HT_HEAD(zv->zv_hash));
|
hlist_add_head(&zv->zv_hlink, ZVOL_HT_HEAD(zv->zv_hash));
|
||||||
|
@ -1132,7 +1105,7 @@ zvol_insert(zvol_state_t *zv)
|
||||||
static void
|
static void
|
||||||
zvol_remove(zvol_state_t *zv)
|
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);
|
list_remove(&zvol_state_list, zv);
|
||||||
hlist_del(&zv->zv_hlink);
|
hlist_del(&zv->zv_hlink);
|
||||||
}
|
}
|
||||||
|
@ -1148,8 +1121,8 @@ zvol_setup_zv(zvol_state_t *zv)
|
||||||
uint64_t ro;
|
uint64_t ro;
|
||||||
objset_t *os = zv->zv_objset;
|
objset_t *os = zv->zv_objset;
|
||||||
|
|
||||||
ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
||||||
RW_LOCK_HELD(&zv->zv_suspend_lock));
|
ASSERT(RW_LOCK_HELD(&zv->zv_suspend_lock));
|
||||||
|
|
||||||
error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
|
error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -1227,8 +1200,8 @@ zvol_suspend(const char *name)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
/* block all I/O, release in zvol_resume. */
|
/* block all I/O, release in zvol_resume. */
|
||||||
ASSERT(MUTEX_HELD(&zv->zv_state_lock) &&
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
||||||
RW_WRITE_HELD(&zv->zv_suspend_lock));
|
ASSERT(RW_WRITE_HELD(&zv->zv_suspend_lock));
|
||||||
|
|
||||||
atomic_inc(&zv->zv_suspend_ref);
|
atomic_inc(&zv->zv_suspend_ref);
|
||||||
|
|
||||||
|
@ -1349,9 +1322,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
||||||
int error = 0;
|
int error = 0;
|
||||||
boolean_t drop_suspend = B_TRUE;
|
boolean_t drop_suspend = B_TRUE;
|
||||||
|
|
||||||
ASSERT(!MUTEX_HELD(&zvol_state_lock));
|
rw_enter(&zvol_state_lock, RW_READER);
|
||||||
|
|
||||||
mutex_enter(&zvol_state_lock);
|
|
||||||
/*
|
/*
|
||||||
* Obtain a copy of private_data under the zvol_state_lock to make
|
* Obtain a copy of private_data under the zvol_state_lock to make
|
||||||
* sure that either the result of zvol free code path setting
|
* 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;
|
zv = bdev->bd_disk->private_data;
|
||||||
if (zv == NULL) {
|
if (zv == NULL) {
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
return (SET_ERROR(-ENXIO));
|
return (SET_ERROR(-ENXIO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1384,7 +1355,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
||||||
} else {
|
} else {
|
||||||
drop_suspend = B_FALSE;
|
drop_suspend = B_FALSE;
|
||||||
}
|
}
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
|
|
||||||
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
||||||
ASSERT(zv->zv_open_count != 0 || RW_READ_HELD(&zv->zv_suspend_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++;
|
zv->zv_open_count++;
|
||||||
|
|
||||||
|
mutex_exit(&zv->zv_state_lock);
|
||||||
|
if (drop_suspend)
|
||||||
|
rw_exit(&zv->zv_suspend_lock);
|
||||||
|
|
||||||
check_disk_change(bdev);
|
check_disk_change(bdev);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
|
||||||
out_open_count:
|
out_open_count:
|
||||||
if (zv->zv_open_count == 0)
|
if (zv->zv_open_count == 0)
|
||||||
zvol_last_close(zv);
|
zvol_last_close(zv);
|
||||||
|
|
||||||
out_mutex:
|
out_mutex:
|
||||||
mutex_exit(&zv->zv_state_lock);
|
mutex_exit(&zv->zv_state_lock);
|
||||||
if (drop_suspend)
|
if (drop_suspend)
|
||||||
|
@ -1427,9 +1405,7 @@ zvol_release(struct gendisk *disk, fmode_t mode)
|
||||||
zvol_state_t *zv;
|
zvol_state_t *zv;
|
||||||
boolean_t drop_suspend = B_TRUE;
|
boolean_t drop_suspend = B_TRUE;
|
||||||
|
|
||||||
ASSERT(!MUTEX_HELD(&zvol_state_lock));
|
rw_enter(&zvol_state_lock, RW_READER);
|
||||||
|
|
||||||
mutex_enter(&zvol_state_lock);
|
|
||||||
zv = disk->private_data;
|
zv = disk->private_data;
|
||||||
|
|
||||||
mutex_enter(&zv->zv_state_lock);
|
mutex_enter(&zv->zv_state_lock);
|
||||||
|
@ -1453,7 +1429,7 @@ zvol_release(struct gendisk *disk, fmode_t mode)
|
||||||
} else {
|
} else {
|
||||||
drop_suspend = B_FALSE;
|
drop_suspend = B_FALSE;
|
||||||
}
|
}
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
|
|
||||||
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
||||||
ASSERT(zv->zv_open_count != 1 || RW_READ_HELD(&zv->zv_suspend_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;
|
zvol_state_t *zv = bdev->bd_disk->private_data;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
ASSERT(zv && zv->zv_open_count > 0);
|
ASSERT3U(zv->zv_open_count, >, 0);
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case BLKFLSBUF:
|
case BLKFLSBUF:
|
||||||
|
@ -1519,23 +1495,62 @@ zvol_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
#define zvol_compat_ioctl NULL
|
#define zvol_compat_ioctl NULL
|
||||||
#endif
|
#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)
|
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;
|
zvol_state_t *zv = disk->private_data;
|
||||||
|
if (zv != NULL) {
|
||||||
ASSERT(zv && zv->zv_open_count > 0);
|
mutex_enter(&zv->zv_state_lock);
|
||||||
|
changed = zv->zv_changed;
|
||||||
return (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)
|
static int zvol_revalidate_disk(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
|
rw_enter(&zvol_state_lock, RW_READER);
|
||||||
|
|
||||||
zvol_state_t *zv = disk->private_data;
|
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);
|
rw_exit(&zvol_state_lock);
|
||||||
|
|
||||||
zv->zv_changed = 0;
|
|
||||||
set_capacity(zv->zv_disk, zv->zv_volsize >> 9);
|
|
||||||
|
|
||||||
return (0);
|
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;
|
zvol_state_t *zv = bdev->bd_disk->private_data;
|
||||||
sector_t sectors;
|
sector_t sectors;
|
||||||
|
|
||||||
ASSERT(zv && zv->zv_open_count > 0);
|
ASSERT3U(zv->zv_open_count, >, 0);
|
||||||
|
|
||||||
sectors = get_capacity(zv->zv_disk);
|
sectors = get_capacity(zv->zv_disk);
|
||||||
|
|
||||||
|
@ -1585,68 +1600,20 @@ zvol_probe(dev_t dev, int *part, void *arg)
|
||||||
return (kobj);
|
return (kobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_BDEV_BLOCK_DEVICE_OPERATIONS
|
|
||||||
static struct block_device_operations zvol_ops = {
|
static struct block_device_operations zvol_ops = {
|
||||||
.open = zvol_open,
|
.open = zvol_open,
|
||||||
.release = zvol_release,
|
.release = zvol_release,
|
||||||
.ioctl = zvol_ioctl,
|
.ioctl = zvol_ioctl,
|
||||||
.compat_ioctl = zvol_compat_ioctl,
|
.compat_ioctl = zvol_compat_ioctl,
|
||||||
.media_changed = zvol_media_changed,
|
#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
|
||||||
.revalidate_disk = zvol_revalidate_disk,
|
.check_events = zvol_check_events,
|
||||||
.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));
|
|
||||||
}
|
|
||||||
#else
|
#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,
|
.media_changed = zvol_media_changed,
|
||||||
|
#endif
|
||||||
.revalidate_disk = zvol_revalidate_disk,
|
.revalidate_disk = zvol_revalidate_disk,
|
||||||
.getgeo = zvol_getgeo,
|
.getgeo = zvol_getgeo,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
#endif /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate memory for a new zvol_state_t and setup the required
|
* 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);
|
rw_init(&zv->zv_suspend_lock, NULL, RW_DEFAULT, NULL);
|
||||||
|
|
||||||
zv->zv_disk->major = zvol_major;
|
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) {
|
if (volmode == ZFS_VOLMODE_DEV) {
|
||||||
/*
|
/*
|
||||||
* ZFS_VOLMODE_DEV disable partitioning on ZVOL devices: set
|
* ZFS_VOLMODE_DEV disable partitioning on ZVOL devices: set
|
||||||
|
@ -1743,7 +1714,6 @@ zvol_free(void *arg)
|
||||||
{
|
{
|
||||||
zvol_state_t *zv = arg;
|
zvol_state_t *zv = arg;
|
||||||
|
|
||||||
ASSERT(!MUTEX_HELD(&zvol_state_lock));
|
|
||||||
ASSERT(!RW_LOCK_HELD(&zv->zv_suspend_lock));
|
ASSERT(!RW_LOCK_HELD(&zv->zv_suspend_lock));
|
||||||
ASSERT(!MUTEX_HELD(&zv->zv_state_lock));
|
ASSERT(!MUTEX_HELD(&zv->zv_state_lock));
|
||||||
ASSERT(zv->zv_open_count == 0);
|
ASSERT(zv->zv_open_count == 0);
|
||||||
|
@ -1870,9 +1840,9 @@ out_doi:
|
||||||
kmem_free(doi, sizeof (dmu_object_info_t));
|
kmem_free(doi, sizeof (dmu_object_info_t));
|
||||||
|
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
mutex_enter(&zvol_state_lock);
|
rw_enter(&zvol_state_lock, RW_WRITER);
|
||||||
zvol_insert(zv);
|
zvol_insert(zv);
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
add_disk(zv->zv_disk);
|
add_disk(zv->zv_disk);
|
||||||
} else {
|
} else {
|
||||||
ida_simple_remove(&zvol_ida, idx);
|
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);
|
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));
|
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
|
||||||
|
|
||||||
strlcpy(zv->zv_name, newname, sizeof (zv->zv_name));
|
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),
|
list_create(&free_list, sizeof (zvol_state_t),
|
||||||
offsetof(zvol_state_t, zv_next));
|
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) {
|
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
||||||
zv_next = list_next(&zvol_state_list, zv);
|
zv_next = list_next(&zvol_state_list, zv);
|
||||||
|
@ -2154,15 +2124,15 @@ zvol_remove_minors_impl(const char *name)
|
||||||
zvol_remove(zv);
|
zvol_remove(zv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clear this while holding zvol_state_lock so
|
* Cleared while holding zvol_state_lock as a writer
|
||||||
* zvol_open won't open it
|
* which will prevent zvol_open() from opening it.
|
||||||
*/
|
*/
|
||||||
zv->zv_disk->private_data = NULL;
|
zv->zv_disk->private_data = NULL;
|
||||||
|
|
||||||
/* Drop zv_state_lock before zvol_free() */
|
/* Drop zv_state_lock before zvol_free() */
|
||||||
mutex_exit(&zv->zv_state_lock);
|
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,
|
t = taskq_dispatch(system_taskq, zvol_free, zv,
|
||||||
TQ_SLEEP);
|
TQ_SLEEP);
|
||||||
if (t == TASKQID_INVALID)
|
if (t == TASKQID_INVALID)
|
||||||
|
@ -2173,11 +2143,9 @@ zvol_remove_minors_impl(const char *name)
|
||||||
mutex_exit(&zv->zv_state_lock);
|
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) {
|
while ((zv = list_head(&free_list)) != NULL) {
|
||||||
list_remove(&free_list, zv);
|
list_remove(&free_list, zv);
|
||||||
zvol_free(zv);
|
zvol_free(zv);
|
||||||
|
@ -2196,7 +2164,7 @@ zvol_remove_minor_impl(const char *name)
|
||||||
if (zvol_inhibit_dev)
|
if (zvol_inhibit_dev)
|
||||||
return;
|
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) {
|
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
||||||
zv_next = list_next(&zvol_state_list, zv);
|
zv_next = list_next(&zvol_state_list, zv);
|
||||||
|
@ -2216,7 +2184,10 @@ zvol_remove_minor_impl(const char *name)
|
||||||
}
|
}
|
||||||
zvol_remove(zv);
|
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;
|
zv->zv_disk->private_data = NULL;
|
||||||
|
|
||||||
mutex_exit(&zv->zv_state_lock);
|
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() */
|
/* Drop zvol_state_lock before calling zvol_free() */
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
|
|
||||||
if (zv != NULL)
|
if (zv != NULL)
|
||||||
zvol_free(zv);
|
zvol_free(zv);
|
||||||
|
@ -2248,7 +2219,7 @@ zvol_rename_minors_impl(const char *oldname, const char *newname)
|
||||||
oldnamelen = strlen(oldname);
|
oldnamelen = strlen(oldname);
|
||||||
newnamelen = strlen(newname);
|
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) {
|
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
||||||
zv_next = list_next(&zvol_state_list, zv);
|
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(&zv->zv_state_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&zvol_state_lock);
|
rw_exit(&zvol_state_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct zvol_snapdev_cb_arg {
|
typedef struct zvol_snapdev_cb_arg {
|
||||||
|
@ -2653,7 +2624,7 @@ zvol_init(void)
|
||||||
|
|
||||||
list_create(&zvol_state_list, sizeof (zvol_state_t),
|
list_create(&zvol_state_list, sizeof (zvol_state_t),
|
||||||
offsetof(zvol_state_t, zv_next));
|
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);
|
ida_init(&zvol_ida);
|
||||||
|
|
||||||
zvol_taskq = taskq_create(ZVOL_DRIVER, threads, maxclsyspri,
|
zvol_taskq = taskq_create(ZVOL_DRIVER, threads, maxclsyspri,
|
||||||
|
@ -2690,7 +2661,7 @@ out_taskq:
|
||||||
taskq_destroy(zvol_taskq);
|
taskq_destroy(zvol_taskq);
|
||||||
out:
|
out:
|
||||||
ida_destroy(&zvol_ida);
|
ida_destroy(&zvol_ida);
|
||||||
mutex_destroy(&zvol_state_lock);
|
rw_destroy(&zvol_state_lock);
|
||||||
list_destroy(&zvol_state_list);
|
list_destroy(&zvol_state_list);
|
||||||
|
|
||||||
return (SET_ERROR(error));
|
return (SET_ERROR(error));
|
||||||
|
@ -2707,7 +2678,7 @@ zvol_fini(void)
|
||||||
|
|
||||||
taskq_destroy(zvol_taskq);
|
taskq_destroy(zvol_taskq);
|
||||||
list_destroy(&zvol_state_list);
|
list_destroy(&zvol_state_list);
|
||||||
mutex_destroy(&zvol_state_lock);
|
rw_destroy(&zvol_state_lock);
|
||||||
|
|
||||||
ida_destroy(&zvol_ida);
|
ida_destroy(&zvol_ida);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue