--- a/usr/src/uts/common/fs/zfs/zvol.c Tue Jun 01 17:33:59 2010 -0400
+++ b/usr/src/uts/common/fs/zfs/zvol.c Tue Jun 01 17:04:42 2010 -0600
@@ -80,18 +80,18 @@
#include "zfs_namecheck.h"
-static void *zvol_state;
+void *zfsdev_state;
static char *zvol_tag = "zvol_tag";
#define ZVOL_DUMPSIZE "dumpsize"
/*
- * This lock protects the zvol_state structure from being modified
+ * This lock protects the zfsdev_state structure from being modified
* while it's being used, e.g. an open that comes in before a create
* finishes. It also protects temporary opens of the dataset so that,
* e.g., an open doesn't get a spurious EBUSY.
*/
-static kmutex_t zvol_state_lock;
+kmutex_t zfsdev_state_lock;
static uint32_t zvol_minors;
typedef struct zvol_extent {
@@ -205,33 +205,16 @@
return (error);
}
-/*
- * Find a free minor number.
- */
-static minor_t
-zvol_minor_alloc(void)
-{
- minor_t minor;
-
- ASSERT(MUTEX_HELD(&zvol_state_lock));
-
- for (minor = 1; minor <= ZVOL_MAX_MINOR; minor++)
- if (ddi_get_soft_state(zvol_state, minor) == NULL)
- return (minor);
-
- return (0);
-}
-
static zvol_state_t *
zvol_minor_lookup(const char *name)
{
minor_t minor;
zvol_state_t *zv;
- ASSERT(MUTEX_HELD(&zvol_state_lock));
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
- for (minor = 1; minor <= ZVOL_MAX_MINOR; minor++) {
- zv = ddi_get_soft_state(zvol_state, minor);
+ for (minor = 1; minor <= ZFSDEV_MAX_MINOR; minor++) {
+ zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
continue;
if (strcmp(zv->zv_name, name) == 0)
@@ -438,11 +421,11 @@
{
zvol_state_t *zv;
- mutex_enter(&zvol_state_lock);
+ mutex_enter(&zfsdev_state_lock);
zv = zvol_minor_lookup(name);
if (minor && zv)
*minor = zv->zv_minor;
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (zv ? 0 : -1);
}
@@ -452,6 +435,7 @@
int
zvol_create_minor(const char *name)
{
+ zfs_soft_state_t *zs;
zvol_state_t *zv;
objset_t *os;
dmu_object_info_t doi;
@@ -459,10 +443,10 @@
char chrbuf[30], blkbuf[30];
int error;
- mutex_enter(&zvol_state_lock);
+ mutex_enter(&zfsdev_state_lock);
if (zvol_minor_lookup(name) != NULL) {
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (EEXIST);
}
@@ -470,19 +454,19 @@
error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, zvol_tag, &os);
if (error) {
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (error);
}
- if ((minor = zvol_minor_alloc()) == 0) {
+ if ((minor = zfsdev_minor_alloc()) == 0) {
dmu_objset_disown(os, zvol_tag);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (ENXIO);
}
- if (ddi_soft_state_zalloc(zvol_state, minor) != DDI_SUCCESS) {
+ if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) {
dmu_objset_disown(os, zvol_tag);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (EAGAIN);
}
(void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME,
@@ -492,9 +476,9 @@
if (ddi_create_minor_node(zfs_dip, chrbuf, S_IFCHR,
minor, DDI_PSEUDO, 0) == DDI_FAILURE) {
- ddi_soft_state_free(zvol_state, minor);
+ ddi_soft_state_free(zfsdev_state, minor);
dmu_objset_disown(os, zvol_tag);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (EAGAIN);
}
@@ -503,14 +487,15 @@
if (ddi_create_minor_node(zfs_dip, blkbuf, S_IFBLK,
minor, DDI_PSEUDO, 0) == DDI_FAILURE) {
ddi_remove_minor_node(zfs_dip, chrbuf);
- ddi_soft_state_free(zvol_state, minor);
+ ddi_soft_state_free(zfsdev_state, minor);
dmu_objset_disown(os, zvol_tag);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (EAGAIN);
}
- zv = ddi_get_soft_state(zvol_state, minor);
-
+ zs = ddi_get_soft_state(zfsdev_state, minor);
+ zs->zss_type = ZSST_ZVOL;
+ zv = zs->zss_data = kmem_zalloc(sizeof (zvol_state_t), KM_SLEEP);
(void) strlcpy(zv->zv_name, name, MAXPATHLEN);
zv->zv_min_bs = DEV_BSHIFT;
zv->zv_minor = minor;
@@ -536,7 +521,7 @@
zvol_minors++;
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (0);
}
@@ -548,21 +533,24 @@
zvol_remove_zv(zvol_state_t *zv)
{
char nmbuf[20];
+ minor_t minor = zv->zv_minor;
- ASSERT(MUTEX_HELD(&zvol_state_lock));
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
if (zv->zv_total_opens != 0)
return (EBUSY);
- (void) snprintf(nmbuf, sizeof (nmbuf), "%u,raw", zv->zv_minor);
+ (void) snprintf(nmbuf, sizeof (nmbuf), "%u,raw", minor);
ddi_remove_minor_node(zfs_dip, nmbuf);
- (void) snprintf(nmbuf, sizeof (nmbuf), "%u", zv->zv_minor);
+ (void) snprintf(nmbuf, sizeof (nmbuf), "%u", minor);
ddi_remove_minor_node(zfs_dip, nmbuf);
avl_destroy(&zv->zv_znode.z_range_avl);
mutex_destroy(&zv->zv_znode.z_range_lock);
- ddi_soft_state_free(zvol_state, zv->zv_minor);
+ kmem_free(zv, sizeof (zvol_state_t));
+
+ ddi_soft_state_free(zfsdev_state, minor);
zvol_minors--;
return (0);
@@ -574,13 +562,13 @@
zvol_state_t *zv;
int rc;
- mutex_enter(&zvol_state_lock);
+ mutex_enter(&zfsdev_state_lock);
if ((zv = zvol_minor_lookup(name)) == NULL) {
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (ENXIO);
}
rc = zvol_remove_zv(zv);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (rc);
}
@@ -680,7 +668,7 @@
dmu_tx_t *tx;
int error;
- ASSERT(MUTEX_HELD(&zvol_state_lock));
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
tx = dmu_tx_create(os);
dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
@@ -710,10 +698,10 @@
namebuf = kmem_zalloc(strlen(name) + 2, KM_SLEEP);
(void) strncpy(namebuf, name, strlen(name));
(void) strcat(namebuf, "/");
- mutex_enter(&zvol_state_lock);
- for (minor = 1; minor <= ZVOL_MAX_MINOR; minor++) {
+ mutex_enter(&zfsdev_state_lock);
+ for (minor = 1; minor <= ZFSDEV_MAX_MINOR; minor++) {
- zv = ddi_get_soft_state(zvol_state, minor);
+ zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
continue;
if (strncmp(namebuf, zv->zv_name, strlen(namebuf)) == 0)
@@ -721,7 +709,7 @@
}
kmem_free(namebuf, strlen(name) + 2);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
}
int
@@ -734,10 +722,10 @@
uint64_t old_volsize = 0ULL;
uint64_t readonly;
- mutex_enter(&zvol_state_lock);
+ mutex_enter(&zfsdev_state_lock);
zv = zvol_minor_lookup(name);
if ((error = dmu_objset_hold(name, FTAG, &os)) != 0) {
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (error);
}
@@ -800,7 +788,7 @@
out:
dmu_objset_rele(os, FTAG);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (error);
}
@@ -809,25 +797,21 @@
int
zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr)
{
- minor_t minor = getminor(*devp);
zvol_state_t *zv;
int err = 0;
- if (minor == 0) /* This is the control device */
- return (0);
+ mutex_enter(&zfsdev_state_lock);
- mutex_enter(&zvol_state_lock);
-
- zv = ddi_get_soft_state(zvol_state, minor);
+ zv = zfsdev_get_soft_state(getminor(*devp), ZSST_ZVOL);
if (zv == NULL) {
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (ENXIO);
}
if (zv->zv_total_opens == 0)
err = zvol_first_open(zv);
if (err) {
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (err);
}
if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
@@ -850,13 +834,13 @@
zv->zv_open_count[otyp]++;
zv->zv_total_opens++;
}
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (err);
out:
if (zv->zv_total_opens == 0)
zvol_last_close(zv);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (err);
}
@@ -868,14 +852,11 @@
zvol_state_t *zv;
int error = 0;
- if (minor == 0) /* This is the control device */
- return (0);
+ mutex_enter(&zfsdev_state_lock);
- mutex_enter(&zvol_state_lock);
-
- zv = ddi_get_soft_state(zvol_state, minor);
+ zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL) {
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (ENXIO);
}
@@ -900,7 +881,7 @@
if (zv->zv_total_opens == 0)
zvol_last_close(zv);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (error);
}
@@ -1138,7 +1119,8 @@
int
zvol_strategy(buf_t *bp)
{
- zvol_state_t *zv = ddi_get_soft_state(zvol_state, getminor(bp->b_edev));
+ zfs_soft_state_t *zs = NULL;
+ zvol_state_t *zv;
uint64_t off, volsize;
size_t resid;
char *addr;
@@ -1149,17 +1131,23 @@
boolean_t is_dump;
boolean_t sync;
- if (zv == NULL) {
- bioerror(bp, ENXIO);
+ if (getminor(bp->b_edev) == 0) {
+ error = EINVAL;
+ } else {
+ zs = ddi_get_soft_state(zfsdev_state, getminor(bp->b_edev));
+ if (zs == NULL)
+ error = ENXIO;
+ else if (zs->zss_type != ZSST_ZVOL)
+ error = EINVAL;
+ }
+
+ if (error) {
+ bioerror(bp, error);
biodone(bp);
return (0);
}
- if (getminor(bp->b_edev) == 0) {
- bioerror(bp, EINVAL);
- biodone(bp);
- return (0);
- }
+ zv = zs->zss_data;
if (!(bp->b_flags & B_READ) && (zv->zv_flags & ZVOL_RDONLY)) {
bioerror(bp, EROFS);
@@ -1264,10 +1252,7 @@
uint64_t boff;
uint64_t resid;
- if (minor == 0) /* This is the control device */
- return (ENXIO);
-
- zv = ddi_get_soft_state(zvol_state, minor);
+ zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
return (ENXIO);
@@ -1299,10 +1284,7 @@
rl_t *rl;
int error = 0;
- if (minor == 0) /* This is the control device */
- return (ENXIO);
-
- zv = ddi_get_soft_state(zvol_state, minor);
+ zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
return (ENXIO);
@@ -1349,10 +1331,7 @@
int error = 0;
boolean_t sync;
- if (minor == 0) /* This is the control device */
- return (ENXIO);
-
- zv = ddi_get_soft_state(zvol_state, minor);
+ zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
return (ENXIO);
@@ -1471,9 +1450,8 @@
{
zvol_state_t *zv;
- if (minor == 0)
- return (ENXIO);
- if ((zv = ddi_get_soft_state(zvol_state, minor)) == NULL)
+ zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
+ if (zv == NULL)
return (ENXIO);
if (zv->zv_flags & ZVOL_DUMPIFIED)
return (ENXIO);
@@ -1544,12 +1522,12 @@
int error = 0;
rl_t *rl;
- mutex_enter(&zvol_state_lock);
+ mutex_enter(&zfsdev_state_lock);
- zv = ddi_get_soft_state(zvol_state, getminor(dev));
+ zv = zfsdev_get_soft_state(getminor(dev), ZSST_ZVOL);
if (zv == NULL) {
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (ENXIO);
}
ASSERT(zv->zv_total_opens > 0);
@@ -1563,7 +1541,7 @@
dki.dki_ctype = DKC_UNKNOWN;
dki.dki_unit = getminor(dev);
dki.dki_maxtransfer = 1 << (SPA_MAXBLOCKSHIFT - zv->zv_min_bs);
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
if (ddi_copyout(&dki, (void *)arg, sizeof (dki), flag))
error = EFAULT;
return (error);
@@ -1573,7 +1551,7 @@
dkm.dki_lbsize = 1U << zv->zv_min_bs;
dkm.dki_capacity = zv->zv_volsize >> zv->zv_min_bs;
dkm.dki_media_type = DK_UNKNOWN;
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
if (ddi_copyout(&dkm, (void *)arg, sizeof (dkm), flag))
error = EFAULT;
return (error);
@@ -1583,14 +1561,14 @@
uint64_t vs = zv->zv_volsize;
uint8_t bs = zv->zv_min_bs;
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
error = zvol_getefi((void *)arg, flag, vs, bs);
return (error);
}
case DKIOCFLUSHWRITECACHE:
dkc = (struct dk_callback *)arg;
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
zil_commit(zv->zv_zilog, UINT64_MAX, ZVOL_OBJ);
if ((flag & FKIOCTL) && dkc != NULL && dkc->dkc_callback) {
(*dkc->dkc_callback)(dkc->dkc_cookie, error);
@@ -1616,10 +1594,10 @@
}
if (wce) {
zv->zv_flags |= ZVOL_WCE;
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
} else {
zv->zv_flags &= ~ZVOL_WCE;
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
zil_commit(zv->zv_zilog, UINT64_MAX, ZVOL_OBJ);
}
return (0);
@@ -1655,7 +1633,7 @@
break;
}
- mutex_exit(&zvol_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (error);
}
@@ -1668,15 +1646,16 @@
void
zvol_init(void)
{
- VERIFY(ddi_soft_state_init(&zvol_state, sizeof (zvol_state_t), 1) == 0);
- mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
+ VERIFY(ddi_soft_state_init(&zfsdev_state, sizeof (zfs_soft_state_t),
+ 1) == 0);
+ mutex_init(&zfsdev_state_lock, NULL, MUTEX_DEFAULT, NULL);
}
void
zvol_fini(void)
{
- mutex_destroy(&zvol_state_lock);
- ddi_soft_state_fini(&zvol_state);
+ mutex_destroy(&zfsdev_state_lock);
+ ddi_soft_state_fini(&zfsdev_state);
}
static int
@@ -1688,7 +1667,7 @@
nvlist_t *nv = NULL;
uint64_t version = spa_version(dmu_objset_spa(zv->zv_objset));
- ASSERT(MUTEX_HELD(&zvol_state_lock));
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, 0,
DMU_OBJECT_END);
/* wait for dmu_free_long_range to actually free the blocks */