Fix panic when resizing ZFS zvol's
Resizing a ZFS ZVOL with debug enabled would result in a panic due to recursion on dp_config_rwlock. The upstream change "3464 zfs synctask code needs restructuring" changed zvol_set_volsize to avoid the recursion on dp_config_rwlock, but this was missed when originally merged in by r248571 due to significant differences in our codebases in this area. These changes also relied on bring in changes from upstream: 3557 dumpvp_size is not updated correctly when a dump zvol's size is changed, which where also not present. In order to help prevent future issues in this area a direct comparison and diff minimisation from current upstream version (b515258) of zvol.c. Differential Revision: https://reviews.freebsd.org/D1302 MFC after: 1 month X-MFC-With: r276063 & r276066 Sponsored by: Multiplay
This commit is contained in:
parent
08c0f91ecc
commit
6831cf6aa6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=276069
@ -43,7 +43,7 @@ extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
|
||||
extern int zvol_create_minor(const char *);
|
||||
extern int zvol_remove_minor(const char *);
|
||||
extern void zvol_remove_minors(const char *);
|
||||
extern int zvol_set_volsize(const char *, major_t, uint64_t);
|
||||
extern int zvol_set_volsize(const char *, uint64_t);
|
||||
|
||||
#ifdef sun
|
||||
extern int zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr);
|
||||
|
@ -2482,8 +2482,7 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
|
||||
err = dsl_dataset_set_refreservation(dsname, source, intval);
|
||||
break;
|
||||
case ZFS_PROP_VOLSIZE:
|
||||
err = zvol_set_volsize(dsname, ddi_driver_major(zfs_dip),
|
||||
intval);
|
||||
err = zvol_set_volsize(dsname, intval);
|
||||
break;
|
||||
case ZFS_PROP_VERSION:
|
||||
{
|
||||
|
@ -97,6 +97,7 @@
|
||||
|
||||
#include "zfs_namecheck.h"
|
||||
|
||||
#ifndef illumos
|
||||
struct g_class zfs_zvol_class = {
|
||||
.name = "ZFS::ZVOL",
|
||||
.version = G_VERSION,
|
||||
@ -104,6 +105,7 @@ struct g_class zfs_zvol_class = {
|
||||
|
||||
DECLARE_GEOM_CLASS(zfs_zvol_class, zfs_zvol);
|
||||
|
||||
#endif
|
||||
void *zfsdev_state;
|
||||
static char *zvol_tag = "zvol_tag";
|
||||
|
||||
@ -126,12 +128,14 @@ kmutex_t zfsdev_state_lock;
|
||||
#endif
|
||||
static uint32_t zvol_minors;
|
||||
|
||||
#ifndef illumos
|
||||
SYSCTL_DECL(_vfs_zfs);
|
||||
SYSCTL_NODE(_vfs_zfs, OID_AUTO, vol, CTLFLAG_RW, 0, "ZFS VOLUME");
|
||||
static int volmode = ZFS_VOLMODE_GEOM;
|
||||
SYSCTL_INT(_vfs_zfs_vol, OID_AUTO, mode, CTLFLAG_RWTUN, &volmode, 0,
|
||||
"Expose as GEOM providers (1), device files (2) or neither");
|
||||
|
||||
#endif
|
||||
typedef struct zvol_extent {
|
||||
list_node_t ze_node;
|
||||
dva_t ze_dva; /* dva associated with this extent */
|
||||
@ -142,28 +146,40 @@ typedef struct zvol_extent {
|
||||
* The in-core state of each volume.
|
||||
*/
|
||||
typedef struct zvol_state {
|
||||
#ifndef illumos
|
||||
LIST_ENTRY(zvol_state) zv_links;
|
||||
#endif
|
||||
char zv_name[MAXPATHLEN]; /* pool/dd name */
|
||||
uint64_t zv_volsize; /* amount of space we advertise */
|
||||
uint64_t zv_volblocksize; /* volume block size */
|
||||
#ifdef illumos
|
||||
minor_t zv_minor; /* minor number */
|
||||
#else
|
||||
struct cdev *zv_dev; /* non-GEOM device */
|
||||
struct g_provider *zv_provider; /* GEOM provider */
|
||||
#endif
|
||||
uint8_t zv_min_bs; /* minimum addressable block shift */
|
||||
uint8_t zv_flags; /* readonly, dumpified, etc. */
|
||||
objset_t *zv_objset; /* objset handle */
|
||||
#ifdef illumos
|
||||
uint32_t zv_open_count[OTYPCNT]; /* open counts */
|
||||
#endif
|
||||
uint32_t zv_total_opens; /* total open count */
|
||||
zilog_t *zv_zilog; /* ZIL handle */
|
||||
list_t zv_extents; /* List of extents for dump */
|
||||
znode_t zv_znode; /* for range locking */
|
||||
dmu_buf_t *zv_dbuf; /* bonus handle */
|
||||
#ifndef illumos
|
||||
int zv_state;
|
||||
int zv_volmode; /* Provide GEOM or cdev */
|
||||
struct bio_queue_head zv_queue;
|
||||
struct mtx zv_queue_mtx; /* zv_queue mutex */
|
||||
#endif
|
||||
} zvol_state_t;
|
||||
|
||||
#ifndef illumos
|
||||
static LIST_HEAD(, zvol_state) all_zvols;
|
||||
|
||||
#endif
|
||||
/*
|
||||
* zvol specific flags
|
||||
*/
|
||||
@ -181,6 +197,7 @@ int zvol_maxphys = DMU_MAX_ACCESS/2;
|
||||
* Toggle unmap functionality.
|
||||
*/
|
||||
boolean_t zvol_unmap_enabled = B_TRUE;
|
||||
#ifndef illumos
|
||||
SYSCTL_INT(_vfs_zfs_vol, OID_AUTO, unmap_enabled, CTLFLAG_RWTUN,
|
||||
&zvol_unmap_enabled, 0,
|
||||
"Enable UNMAP functionality");
|
||||
@ -204,28 +221,30 @@ static struct cdevsw zvol_cdevsw = {
|
||||
.d_flags = D_DISK | D_TRACKCLOSE,
|
||||
};
|
||||
|
||||
extern int zfs_set_prop_nvlist(const char *, zprop_source_t,
|
||||
nvlist_t *, nvlist_t *);
|
||||
static void zvol_geom_run(zvol_state_t *zv);
|
||||
static void zvol_geom_destroy(zvol_state_t *zv);
|
||||
static int zvol_geom_access(struct g_provider *pp, int acr, int acw, int ace);
|
||||
static void zvol_geom_start(struct bio *bp);
|
||||
static void zvol_geom_worker(void *arg);
|
||||
static void zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off,
|
||||
uint64_t len, boolean_t sync);
|
||||
#endif /* !illumos */
|
||||
|
||||
extern int zfs_set_prop_nvlist(const char *, zprop_source_t,
|
||||
nvlist_t *, nvlist_t *);
|
||||
static int zvol_remove_zv(zvol_state_t *);
|
||||
static int zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio);
|
||||
static int zvol_dumpify(zvol_state_t *zv);
|
||||
static int zvol_dump_fini(zvol_state_t *zv);
|
||||
static int zvol_dump_init(zvol_state_t *zv, boolean_t resize);
|
||||
|
||||
static void zvol_geom_run(zvol_state_t *zv);
|
||||
static void zvol_geom_destroy(zvol_state_t *zv);
|
||||
static int zvol_geom_access(struct g_provider *pp, int acr, int acw, int ace);
|
||||
static void zvol_geom_start(struct bio *bp);
|
||||
static void zvol_geom_worker(void *arg);
|
||||
|
||||
static void
|
||||
zvol_size_changed(zvol_state_t *zv)
|
||||
zvol_size_changed(zvol_state_t *zv, uint64_t volsize)
|
||||
{
|
||||
#ifdef illumos
|
||||
dev_t dev = makedevice(maj, min);
|
||||
dev_t dev = makedevice(ddi_driver_major(zfs_dip), zv->zv_minor);
|
||||
|
||||
zv->zv_volsize = volsize;
|
||||
VERIFY(ddi_prop_update_int64(dev, zfs_dip,
|
||||
"Size", volsize) == DDI_SUCCESS);
|
||||
VERIFY(ddi_prop_update_int64(dev, zfs_dip,
|
||||
@ -235,6 +254,7 @@ zvol_size_changed(zvol_state_t *zv)
|
||||
spec_size_invalidate(dev, VBLK);
|
||||
spec_size_invalidate(dev, VCHR);
|
||||
#else /* !illumos */
|
||||
zv->zv_volsize = volsize;
|
||||
if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
|
||||
struct g_provider *pp;
|
||||
|
||||
@ -301,16 +321,26 @@ zvol_get_stats(objset_t *os, nvlist_t *nv)
|
||||
static zvol_state_t *
|
||||
zvol_minor_lookup(const char *name)
|
||||
{
|
||||
#ifdef illumos
|
||||
minor_t minor;
|
||||
#endif
|
||||
zvol_state_t *zv;
|
||||
|
||||
ASSERT(MUTEX_HELD(&zfsdev_state_lock));
|
||||
|
||||
#ifdef illumos
|
||||
for (minor = 1; minor <= ZFSDEV_MAX_MINOR; minor++) {
|
||||
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
|
||||
if (zv == NULL)
|
||||
continue;
|
||||
#else
|
||||
LIST_FOREACH(zv, &all_zvols, zv_links) {
|
||||
#endif
|
||||
if (strcmp(zv->zv_name, name) == 0)
|
||||
break;
|
||||
return (zv);
|
||||
}
|
||||
|
||||
return (zv);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* extent mapping arg */
|
||||
@ -550,14 +580,21 @@ zvol_create_minor(const char *name)
|
||||
zfs_soft_state_t *zs;
|
||||
zvol_state_t *zv;
|
||||
objset_t *os;
|
||||
dmu_object_info_t doi;
|
||||
#ifdef illumos
|
||||
minor_t minor = 0;
|
||||
char chrbuf[30], blkbuf[30];
|
||||
#else
|
||||
struct cdev *dev;
|
||||
struct g_provider *pp;
|
||||
struct g_geom *gp;
|
||||
dmu_object_info_t doi;
|
||||
uint64_t volsize, mode;
|
||||
#endif
|
||||
int error;
|
||||
|
||||
#ifndef illumos
|
||||
ZFS_LOG(1, "Creating ZVOL %s...", name);
|
||||
#endif
|
||||
|
||||
mutex_enter(&zfsdev_state_lock);
|
||||
|
||||
@ -664,6 +701,9 @@ zvol_create_minor(const char *name)
|
||||
|
||||
(void) strlcpy(zv->zv_name, name, MAXPATHLEN);
|
||||
zv->zv_min_bs = DEV_BSHIFT;
|
||||
#ifdef illumos
|
||||
zv->zv_minor = minor;
|
||||
#endif
|
||||
zv->zv_objset = os;
|
||||
if (dmu_objset_is_snapshot(os) || !spa_writeable(dmu_objset_spa(os)))
|
||||
zv->zv_flags |= ZVOL_RDONLY;
|
||||
@ -689,16 +729,15 @@ zvol_create_minor(const char *name)
|
||||
zvol_minors++;
|
||||
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
|
||||
#ifndef illumos
|
||||
if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
|
||||
zvol_geom_run(zv);
|
||||
g_topology_unlock();
|
||||
}
|
||||
PICKUP_GIANT();
|
||||
#endif
|
||||
|
||||
ZFS_LOG(1, "ZVOL %s created.", name);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -710,6 +749,7 @@ static int
|
||||
zvol_remove_zv(zvol_state_t *zv)
|
||||
{
|
||||
#ifdef illumos
|
||||
char nmbuf[20];
|
||||
minor_t minor = zv->zv_minor;
|
||||
#endif
|
||||
|
||||
@ -717,12 +757,15 @@ zvol_remove_zv(zvol_state_t *zv)
|
||||
if (zv->zv_total_opens != 0)
|
||||
return (SET_ERROR(EBUSY));
|
||||
|
||||
ZFS_LOG(1, "ZVOL %s destroyed.", zv->zv_name);
|
||||
|
||||
#ifdef illumos
|
||||
(void) snprintf(nmbuf, sizeof (nmbuf), "%u,raw", minor);
|
||||
ddi_remove_minor_node(zfs_dip, nmbuf);
|
||||
|
||||
(void) snprintf(nmbuf, sizeof (nmbuf), "%u", minor);
|
||||
ddi_remove_minor_node(zfs_dip, nmbuf);
|
||||
#else
|
||||
ZFS_LOG(1, "ZVOL %s destroyed.", zv->zv_name);
|
||||
|
||||
LIST_REMOVE(zv, zv_links);
|
||||
if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
|
||||
g_topology_lock();
|
||||
@ -735,8 +778,10 @@ zvol_remove_zv(zvol_state_t *zv)
|
||||
avl_destroy(&zv->zv_znode.z_range_avl);
|
||||
mutex_destroy(&zv->zv_znode.z_range_lock);
|
||||
|
||||
kmem_free(zv, sizeof(*zv));
|
||||
|
||||
kmem_free(zv, sizeof (zvol_state_t));
|
||||
#ifdef illumos
|
||||
ddi_soft_state_free(zfsdev_state, minor);
|
||||
#endif
|
||||
zvol_minors--;
|
||||
return (0);
|
||||
}
|
||||
@ -771,21 +816,22 @@ zvol_first_open(zvol_state_t *zv)
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
zv->zv_objset = os;
|
||||
error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
|
||||
if (error) {
|
||||
ASSERT(error == 0);
|
||||
dmu_objset_disown(os, zvol_tag);
|
||||
return (error);
|
||||
}
|
||||
zv->zv_objset = os;
|
||||
|
||||
error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf);
|
||||
if (error) {
|
||||
dmu_objset_disown(os, zvol_tag);
|
||||
return (error);
|
||||
}
|
||||
zv->zv_volsize = volsize;
|
||||
|
||||
zvol_size_changed(zv, volsize);
|
||||
zv->zv_zilog = zil_open(os, zvol_get_data);
|
||||
zvol_size_changed(zv);
|
||||
|
||||
VERIFY(dsl_prop_get_integer(zv->zv_name, "readonly", &readonly,
|
||||
NULL) == 0);
|
||||
@ -889,6 +935,27 @@ zvol_update_volsize(objset_t *os, uint64_t volsize)
|
||||
void
|
||||
zvol_remove_minors(const char *name)
|
||||
{
|
||||
#ifdef illumos
|
||||
zvol_state_t *zv;
|
||||
char *namebuf;
|
||||
minor_t minor;
|
||||
|
||||
namebuf = kmem_zalloc(strlen(name) + 2, KM_SLEEP);
|
||||
(void) strncpy(namebuf, name, strlen(name));
|
||||
(void) strcat(namebuf, "/");
|
||||
mutex_enter(&zfsdev_state_lock);
|
||||
for (minor = 1; minor <= ZFSDEV_MAX_MINOR; minor++) {
|
||||
|
||||
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
|
||||
if (zv == NULL)
|
||||
continue;
|
||||
if (strncmp(namebuf, zv->zv_name, strlen(namebuf)) == 0)
|
||||
(void) zvol_remove_zv(zv);
|
||||
}
|
||||
kmem_free(namebuf, strlen(name) + 2);
|
||||
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#else /* !illumos */
|
||||
zvol_state_t *zv, *tzv;
|
||||
size_t namelen;
|
||||
|
||||
@ -908,67 +975,46 @@ zvol_remove_minors(const char *name)
|
||||
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
PICKUP_GIANT();
|
||||
#endif /* illumos */
|
||||
}
|
||||
|
||||
int
|
||||
zvol_set_volsize(const char *name, major_t maj, uint64_t volsize)
|
||||
static int
|
||||
zvol_update_live_volsize(zvol_state_t *zv, uint64_t volsize)
|
||||
{
|
||||
zvol_state_t *zv = NULL;
|
||||
objset_t *os;
|
||||
int error;
|
||||
dmu_object_info_t doi;
|
||||
uint64_t old_volsize = 0ULL;
|
||||
uint64_t readonly;
|
||||
int error = 0;
|
||||
|
||||
mutex_enter(&zfsdev_state_lock);
|
||||
zv = zvol_minor_lookup(name);
|
||||
if ((error = dmu_objset_hold(name, FTAG, &os)) != 0) {
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
return (error);
|
||||
}
|
||||
ASSERT(MUTEX_HELD(&zfsdev_state_lock));
|
||||
|
||||
if ((error = dmu_object_info(os, ZVOL_OBJ, &doi)) != 0 ||
|
||||
(error = zvol_check_volsize(volsize,
|
||||
doi.doi_data_block_size)) != 0)
|
||||
goto out;
|
||||
|
||||
VERIFY(dsl_prop_get_integer(name, "readonly", &readonly,
|
||||
NULL) == 0);
|
||||
if (readonly) {
|
||||
error = EROFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = zvol_update_volsize(os, volsize);
|
||||
/*
|
||||
* Reinitialize the dump area to the new size. If we
|
||||
* failed to resize the dump area then restore it back to
|
||||
* its original size.
|
||||
* its original size. We must set the new volsize prior
|
||||
* to calling dumpvp_resize() to ensure that the devices'
|
||||
* size(9P) is not visible by the dump subsystem.
|
||||
*/
|
||||
if (zv && error == 0) {
|
||||
old_volsize = zv->zv_volsize;
|
||||
zvol_size_changed(zv, volsize);
|
||||
|
||||
#ifdef ZVOL_DUMP
|
||||
if (zv->zv_flags & ZVOL_DUMPIFIED) {
|
||||
old_volsize = zv->zv_volsize;
|
||||
zv->zv_volsize = volsize;
|
||||
if ((error = zvol_dumpify(zv)) != 0 ||
|
||||
(error = dumpvp_resize()) != 0) {
|
||||
(void) zvol_update_volsize(os, old_volsize);
|
||||
zv->zv_volsize = old_volsize;
|
||||
error = zvol_dumpify(zv);
|
||||
}
|
||||
}
|
||||
#endif /* ZVOL_DUMP */
|
||||
if (error == 0) {
|
||||
zv->zv_volsize = volsize;
|
||||
zvol_size_changed(zv);
|
||||
if (zv->zv_flags & ZVOL_DUMPIFIED) {
|
||||
if ((error = zvol_dumpify(zv)) != 0 ||
|
||||
(error = dumpvp_resize()) != 0) {
|
||||
int dumpify_error;
|
||||
|
||||
(void) zvol_update_volsize(zv->zv_objset, old_volsize);
|
||||
zvol_size_changed(zv, old_volsize);
|
||||
dumpify_error = zvol_dumpify(zv);
|
||||
error = dumpify_error ? dumpify_error : error;
|
||||
}
|
||||
}
|
||||
#endif /* ZVOL_DUMP */
|
||||
|
||||
#ifdef illumos
|
||||
/*
|
||||
* Generate a LUN expansion event.
|
||||
*/
|
||||
if (zv && error == 0) {
|
||||
if (error == 0) {
|
||||
sysevent_id_t eid;
|
||||
nvlist_t *attr;
|
||||
char *physpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
|
||||
@ -986,21 +1032,88 @@ zvol_set_volsize(const char *name, major_t maj, uint64_t volsize)
|
||||
kmem_free(physpath, MAXPATHLEN);
|
||||
}
|
||||
#endif /* illumos */
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zvol_set_volsize(const char *name, uint64_t volsize)
|
||||
{
|
||||
zvol_state_t *zv = NULL;
|
||||
objset_t *os;
|
||||
int error;
|
||||
dmu_object_info_t doi;
|
||||
uint64_t readonly;
|
||||
boolean_t owned = B_FALSE;
|
||||
|
||||
error = dsl_prop_get_integer(name,
|
||||
zfs_prop_to_name(ZFS_PROP_READONLY), &readonly, NULL);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (readonly)
|
||||
return (SET_ERROR(EROFS));
|
||||
|
||||
mutex_enter(&zfsdev_state_lock);
|
||||
zv = zvol_minor_lookup(name);
|
||||
|
||||
if (zv == NULL || zv->zv_objset == NULL) {
|
||||
if ((error = dmu_objset_own(name, DMU_OST_ZVOL, B_FALSE,
|
||||
FTAG, &os)) != 0) {
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
return (error);
|
||||
}
|
||||
owned = B_TRUE;
|
||||
if (zv != NULL)
|
||||
zv->zv_objset = os;
|
||||
} else {
|
||||
os = zv->zv_objset;
|
||||
}
|
||||
|
||||
if ((error = dmu_object_info(os, ZVOL_OBJ, &doi)) != 0 ||
|
||||
(error = zvol_check_volsize(volsize, doi.doi_data_block_size)) != 0)
|
||||
goto out;
|
||||
|
||||
error = zvol_update_volsize(os, volsize);
|
||||
|
||||
if (error == 0 && zv != NULL)
|
||||
error = zvol_update_live_volsize(zv, volsize);
|
||||
out:
|
||||
dmu_objset_rele(os, FTAG);
|
||||
|
||||
if (owned) {
|
||||
dmu_objset_disown(os, FTAG);
|
||||
if (zv != NULL)
|
||||
zv->zv_objset = NULL;
|
||||
}
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
#ifdef illumos
|
||||
int
|
||||
zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr)
|
||||
#else
|
||||
static int
|
||||
zvol_open(struct g_provider *pp, int flag, int count)
|
||||
#endif
|
||||
{
|
||||
zvol_state_t *zv;
|
||||
int err = 0;
|
||||
#ifdef illumos
|
||||
|
||||
mutex_enter(&zfsdev_state_lock);
|
||||
|
||||
zv = zfsdev_get_soft_state(getminor(*devp), ZSST_ZVOL);
|
||||
if (zv == NULL) {
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
return (SET_ERROR(ENXIO));
|
||||
}
|
||||
|
||||
if (zv->zv_total_opens == 0)
|
||||
err = zvol_first_open(zv);
|
||||
if (err) {
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
return (err);
|
||||
}
|
||||
#else /* !illumos */
|
||||
boolean_t locked = B_FALSE;
|
||||
|
||||
/*
|
||||
@ -1037,6 +1150,7 @@ zvol_open(struct g_provider *pp, int flag, int count)
|
||||
pp->stripeoffset = 0;
|
||||
pp->stripesize = zv->zv_volblocksize;
|
||||
}
|
||||
#endif /* illumos */
|
||||
if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
|
||||
err = SET_ERROR(EROFS);
|
||||
goto out;
|
||||
@ -1055,20 +1169,46 @@ zvol_open(struct g_provider *pp, int flag, int count)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef illumos
|
||||
if (zv->zv_open_count[otyp] == 0 || otyp == OTYP_LYR) {
|
||||
zv->zv_open_count[otyp]++;
|
||||
zv->zv_total_opens++;
|
||||
}
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#else
|
||||
zv->zv_total_opens += count;
|
||||
if (locked)
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#endif
|
||||
|
||||
return (err);
|
||||
out:
|
||||
if (zv->zv_total_opens == 0)
|
||||
zvol_last_close(zv);
|
||||
#ifdef illumos
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#else
|
||||
if (locked)
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#endif
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
#ifdef illumos
|
||||
int
|
||||
zvol_close(dev_t dev, int flag, int otyp, cred_t *cr)
|
||||
{
|
||||
minor_t minor = getminor(dev);
|
||||
zvol_state_t *zv;
|
||||
int error = 0;
|
||||
|
||||
mutex_enter(&zfsdev_state_lock);
|
||||
|
||||
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
|
||||
if (zv == NULL) {
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#else /* !illumos */
|
||||
static int
|
||||
zvol_close(struct g_provider *pp, int flag, int count)
|
||||
{
|
||||
@ -1086,6 +1226,7 @@ zvol_close(struct g_provider *pp, int flag, int count)
|
||||
if (zv == NULL) {
|
||||
if (locked)
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#endif /* illumos */
|
||||
return (SET_ERROR(ENXIO));
|
||||
}
|
||||
|
||||
@ -1098,18 +1239,30 @@ zvol_close(struct g_provider *pp, int flag, int count)
|
||||
* If the open count is zero, this is a spurious close.
|
||||
* That indicates a bug in the kernel / DDI framework.
|
||||
*/
|
||||
#ifdef illumos
|
||||
ASSERT(zv->zv_open_count[otyp] != 0);
|
||||
#endif
|
||||
ASSERT(zv->zv_total_opens != 0);
|
||||
|
||||
/*
|
||||
* You may get multiple opens, but only one close.
|
||||
*/
|
||||
#ifdef illumos
|
||||
zv->zv_open_count[otyp]--;
|
||||
zv->zv_total_opens--;
|
||||
#else
|
||||
zv->zv_total_opens -= count;
|
||||
#endif
|
||||
|
||||
if (zv->zv_total_opens == 0)
|
||||
zvol_last_close(zv);
|
||||
|
||||
#ifdef illumos
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#else
|
||||
if (locked)
|
||||
mutex_exit(&zfsdev_state_lock);
|
||||
#endif
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1362,11 +1515,16 @@ zvol_dumpio(zvol_state_t *zv, void *addr, uint64_t offset, uint64_t size,
|
||||
|
||||
return (error);
|
||||
}
|
||||
#endif /* illumos */
|
||||
|
||||
int
|
||||
zvol_strategy(buf_t *bp)
|
||||
{
|
||||
zfs_soft_state_t *zs = NULL;
|
||||
#else /* !illumos */
|
||||
void
|
||||
zvol_strategy(struct bio *bp)
|
||||
{
|
||||
#endif /* illumos */
|
||||
zvol_state_t *zv;
|
||||
uint64_t off, volsize;
|
||||
size_t resid;
|
||||
@ -1374,22 +1532,53 @@ zvol_strategy(struct bio *bp)
|
||||
objset_t *os;
|
||||
rl_t *rl;
|
||||
int error = 0;
|
||||
#ifdef illumos
|
||||
boolean_t doread = bp->b_flags & B_READ;
|
||||
#else
|
||||
boolean_t doread = 0;
|
||||
#endif
|
||||
boolean_t is_dumpified;
|
||||
boolean_t sync;
|
||||
|
||||
#ifdef illumos
|
||||
if (getminor(bp->b_edev) == 0) {
|
||||
error = SET_ERROR(EINVAL);
|
||||
} else {
|
||||
zs = ddi_get_soft_state(zfsdev_state, getminor(bp->b_edev));
|
||||
if (zs == NULL)
|
||||
error = SET_ERROR(ENXIO);
|
||||
else if (zs->zss_type != ZSST_ZVOL)
|
||||
error = SET_ERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
bioerror(bp, error);
|
||||
biodone(bp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
zv = zs->zss_data;
|
||||
|
||||
if (!(bp->b_flags & B_READ) && (zv->zv_flags & ZVOL_RDONLY)) {
|
||||
bioerror(bp, EROFS);
|
||||
biodone(bp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
off = ldbtob(bp->b_blkno);
|
||||
#else /* !illumos */
|
||||
if (bp->bio_to)
|
||||
zv = bp->bio_to->private;
|
||||
else
|
||||
zv = bp->bio_dev->si_drv2;
|
||||
|
||||
if (zv == NULL) {
|
||||
error = ENXIO;
|
||||
error = SET_ERROR(ENXIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bp->bio_cmd != BIO_READ && (zv->zv_flags & ZVOL_RDONLY)) {
|
||||
error = EROFS;
|
||||
error = SET_ERROR(EROFS);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1407,26 +1596,41 @@ zvol_strategy(struct bio *bp)
|
||||
}
|
||||
|
||||
off = bp->bio_offset;
|
||||
#endif /* illumos */
|
||||
volsize = zv->zv_volsize;
|
||||
|
||||
os = zv->zv_objset;
|
||||
ASSERT(os != NULL);
|
||||
|
||||
#ifdef illumos
|
||||
bp_mapin(bp);
|
||||
addr = bp->b_un.b_addr;
|
||||
resid = bp->b_bcount;
|
||||
|
||||
if (resid > 0 && (off < 0 || off >= volsize)) {
|
||||
bioerror(bp, EIO);
|
||||
biodone(bp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
is_dumpified = zv->zv_flags & ZVOL_DUMPIFIED;
|
||||
sync = ((!(bp->b_flags & B_ASYNC) &&
|
||||
!(zv->zv_flags & ZVOL_WCE)) ||
|
||||
(zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS)) &&
|
||||
!doread && !is_dumpified;
|
||||
#else /* !illumos */
|
||||
addr = bp->bio_data;
|
||||
resid = bp->bio_length;
|
||||
|
||||
if (resid > 0 && (off < 0 || off >= volsize)) {
|
||||
error = EIO;
|
||||
error = SET_ERROR(EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef illumos
|
||||
is_dumpified = zv->zv_flags & ZVOL_DUMPIFIED;
|
||||
#else
|
||||
is_dumpified = B_FALSE;
|
||||
#endif
|
||||
sync = !doread && !is_dumpified &&
|
||||
sync = !doread && !is_dumpified &&
|
||||
zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS;
|
||||
#endif /* illumos */
|
||||
|
||||
/*
|
||||
* There must be no buffer changes when doing a dmu_sync() because
|
||||
@ -1435,6 +1639,7 @@ zvol_strategy(struct bio *bp)
|
||||
rl = zfs_range_lock(&zv->zv_znode, off, resid,
|
||||
doread ? RL_READER : RL_WRITER);
|
||||
|
||||
#ifndef illumos
|
||||
if (bp->bio_cmd == BIO_DELETE) {
|
||||
dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
|
||||
error = dmu_tx_assign(tx, TXG_WAIT);
|
||||
@ -1449,7 +1654,7 @@ zvol_strategy(struct bio *bp)
|
||||
}
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
#endif
|
||||
while (resid != 0 && off < volsize) {
|
||||
size_t size = MIN(resid, zvol_maxphys);
|
||||
#ifdef illumos
|
||||
@ -1485,9 +1690,21 @@ zvol_strategy(struct bio *bp)
|
||||
addr += size;
|
||||
resid -= size;
|
||||
}
|
||||
#ifndef illumos
|
||||
unlock:
|
||||
#endif
|
||||
zfs_range_unlock(rl);
|
||||
|
||||
#ifdef illumos
|
||||
if ((bp->b_resid = resid) == bp->b_bcount)
|
||||
bioerror(bp, off > volsize ? EINVAL : error);
|
||||
|
||||
if (sync)
|
||||
zil_commit(zv->zv_zilog, ZVOL_OBJ);
|
||||
biodone(bp);
|
||||
|
||||
return (0);
|
||||
#else /* !illumos */
|
||||
bp->bio_completed = bp->bio_length - resid;
|
||||
if (bp->bio_completed < bp->bio_length && off > volsize)
|
||||
error = EINVAL;
|
||||
@ -1501,6 +1718,7 @@ zvol_strategy(struct bio *bp)
|
||||
g_io_deliver(bp, error);
|
||||
else
|
||||
biofinish(bp, NULL, error);
|
||||
#endif /* illumos */
|
||||
}
|
||||
|
||||
#ifdef illumos
|
||||
@ -1578,6 +1796,7 @@ zvol_read(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
#endif
|
||||
|
||||
volsize = zv->zv_volsize;
|
||||
/* uio_loffset == volsize isn't an error as its required for EOF processing. */
|
||||
if (uio->uio_resid > 0 &&
|
||||
(uio->uio_loffset < 0 || uio->uio_loffset > volsize))
|
||||
return (SET_ERROR(EIO));
|
||||
@ -1637,6 +1856,7 @@ zvol_write(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
#endif
|
||||
|
||||
volsize = zv->zv_volsize;
|
||||
/* uio_loffset == volsize isn't an error as its required for EOF processing. */
|
||||
if (uio->uio_resid > 0 &&
|
||||
(uio->uio_loffset < 0 || uio->uio_loffset > volsize))
|
||||
return (SET_ERROR(EIO));
|
||||
@ -2369,7 +2589,7 @@ zvol_dump_fini(zvol_state_t *zv)
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif /* illumos */
|
||||
#else /* !illumos */
|
||||
|
||||
static void
|
||||
zvol_geom_run(zvol_state_t *zv)
|
||||
@ -2947,3 +3167,4 @@ zvol_d_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct threa
|
||||
|
||||
return (error);
|
||||
}
|
||||
#endif /* illumos */
|
||||
|
Loading…
Reference in New Issue
Block a user