ZFS panic on zvol resize
Kristof Provost
kristof at sigsegv.be
Sat Jul 19 22:42:26 UTC 2014
On 2014-07-19 18:41:13 (+0200), Kristof Provost <kristof at sigsegv.be> wrote:
> With this patch I no longer see the original panic, but I get a shiny
> new one in its place:
>
> panic: solaris assert: txg_how != TXG_WAIT || !dsl_pool_config_held(tx->tx_pool), file: /usr/src/sys/modules/zfs/../../cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c, line: 1279
Both problems appear to be fixed in Illumos commit
3b2aab18808792cbd248a12f1edf139b89833c13
Essentially they've changed from using dmu_objset_hold() to
dmu_objset_own().
See:
- https://www.illumos.org/issues/3464
- https://github.com/illumos/illumos-gate/commit/3b2aab18808792cbd248a12f1edf139b89833c13
- ZoL: https://github.com/zfsonlinux/zfs/pull/2048
I included the zvol resize bits of the patch in my tree, and can now
resize zvols without panicing the machine.
Index: cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zvol.h
===================================================================
--- cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zvol.h (revision 268881)
+++ cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zvol.h (working copy)
@@ -43,7 +43,7 @@
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);
Index: cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
===================================================================
--- cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c (revision 268881)
+++ cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c (working copy)
@@ -2482,8 +2482,7 @@
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:
{
Index: cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
===================================================================
--- cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c (revision 268881)
+++ cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c (working copy)
@@ -203,11 +203,12 @@
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 sun
dev_t dev = makedevice(maj, min);
+ zv->zv_volsize = volsize;
VERIFY(ddi_prop_update_int64(dev, zfs_dip,
"Size", volsize) == DDI_SUCCESS);
VERIFY(ddi_prop_update_int64(dev, zfs_dip,
@@ -765,9 +766,9 @@
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);
@@ -891,65 +892,42 @@
PICKUP_GIANT();
}
-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(&spa_namespace_lock);
- zv = zvol_minor_lookup(name);
- if ((error = dmu_objset_hold(name, FTAG, &os)) != 0) {
- mutex_exit(&spa_namespace_lock);
- return (error);
- }
+ ASSERT(MUTEX_HELD(&spa_namespace_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);
- }
+ 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 */
- if (error == 0) {
- zv->zv_volsize = volsize;
- zvol_size_changed(zv);
- }
}
+#endif /* ZVOL_DUMP */
#ifdef sun
/*
* 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);
@@ -967,12 +945,57 @@
kmem_free(physpath, MAXPATHLEN);
}
#endif /* sun */
+ 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(&spa_namespace_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(&spa_namespace_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(&spa_namespace_lock);
-
return (error);
}
Regards,
Kristof
More information about the freebsd-fs
mailing list