Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Oct 2014 08:39:44 +0000 (UTC)
From:      Steven Hartland <smh@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-releng@freebsd.org
Subject:   svn commit: r273162 - releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs
Message-ID:  <201410160839.s9G8diBZ089660@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: smh
Date: Thu Oct 16 08:39:44 2014
New Revision: 273162
URL: https://svnweb.freebsd.org/changeset/base/273162

Log:
  MFS10 r272883
  MFC r272474
  Fix ZFS ZVOL deadlock and rename issues
  
  Approved by:	re@ (delphij)
  Sponsored by:	Multiplay

Modified:
  releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
  releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
  releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
Directory Properties:
  releng/10.1/   (props changed)

Modified: releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
==============================================================================
--- releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c	Thu Oct 16 08:33:11 2014	(r273161)
+++ releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c	Thu Oct 16 08:39:44 2014	(r273162)
@@ -2257,6 +2257,9 @@ dsl_dataset_promote_sync(void *arg, dmu_
 	dsl_dir_t *odd = NULL;
 	uint64_t oldnext_obj;
 	int64_t delta;
+#if defined(__FreeBSD__) && defined(_KERNEL)
+	char *oldname, *newname;
+#endif
 
 	VERIFY0(promote_hold(ddpa, dp, FTAG));
 	hds = ddpa->ddpa_clone;
@@ -2322,6 +2325,14 @@ dsl_dataset_promote_sync(void *arg, dmu_
 		    dd->dd_phys->dd_clones, origin_head->ds_object, tx));
 	}
 
+#if defined(__FreeBSD__) && defined(_KERNEL)
+	/* Take the spa_namespace_lock early so zvol renames don't deadlock. */
+	mutex_enter(&spa_namespace_lock);
+
+	oldname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+	newname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+#endif
+
 	/* move snapshots to this dir */
 	for (snap = list_head(&ddpa->shared_snaps); snap;
 	    snap = list_next(&ddpa->shared_snaps, snap)) {
@@ -2356,6 +2367,12 @@ dsl_dataset_promote_sync(void *arg, dmu_
 		VERIFY0(dsl_dir_hold_obj(dp, dd->dd_object,
 		    NULL, ds, &ds->ds_dir));
 
+#if defined(__FreeBSD__) && defined(_KERNEL)
+		dsl_dataset_name(ds, newname);
+		zfsvfs_update_fromname(oldname, newname);
+		zvol_rename_minors(oldname, newname);
+#endif
+
 		/* move any clone references */
 		if (ds->ds_phys->ds_next_clones_obj &&
 		    spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
@@ -2393,6 +2410,12 @@ dsl_dataset_promote_sync(void *arg, dmu_
 		ASSERT(!dsl_prop_hascb(ds));
 	}
 
+#if defined(__FreeBSD__) && defined(_KERNEL)
+	mutex_exit(&spa_namespace_lock);
+
+	kmem_free(newname, MAXPATHLEN);
+	kmem_free(oldname, MAXPATHLEN);
+#endif
 	/*
 	 * Change space accounting.
 	 * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either

Modified: releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
==============================================================================
--- releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c	Thu Oct 16 08:33:11 2014	(r273161)
+++ releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c	Thu Oct 16 08:39:44 2014	(r273162)
@@ -3541,6 +3541,7 @@ zfs_destroy_unmount_origin(const char *f
 static int
 zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
 {
+	int error, poollen;
 	nvlist_t *snaps;
 	nvpair_t *pair;
 	boolean_t defer;
@@ -3549,9 +3550,25 @@ zfs_ioc_destroy_snaps(const char *poolna
 		return (SET_ERROR(EINVAL));
 	defer = nvlist_exists(innvl, "defer");
 
+	poollen = strlen(poolname);
 	for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
 	    pair = nvlist_next_nvpair(snaps, pair)) {
-		(void) zfs_unmount_snap(nvpair_name(pair));
+		const char *name = nvpair_name(pair);
+
+		/*
+		 * The snap must be in the specified pool to prevent the
+		 * invalid removal of zvol minors below.
+		 */
+		if (strncmp(name, poolname, poollen) != 0 ||
+		    (name[poollen] != '/' && name[poollen] != '@'))
+			return (SET_ERROR(EXDEV));
+
+		error = zfs_unmount_snap(name);
+		if (error != 0)
+			return (error);
+#if defined(__FreeBSD__)
+		zvol_remove_minors(name);
+#endif
 	}
 
 	return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
@@ -3676,7 +3693,11 @@ zfs_ioc_destroy(zfs_cmd_t *zc)
 	else
 		err = dsl_destroy_head(zc->zc_name);
 	if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0)
+#ifdef __FreeBSD__
+		zvol_remove_minors(zc->zc_name);
+#else
 		(void) zvol_remove_minor(zc->zc_name);
+#endif
 	return (err);
 }
 

Modified: releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
==============================================================================
--- releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c	Thu Oct 16 08:33:11 2014	(r273161)
+++ releng/10.1/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c	Thu Oct 16 08:39:44 2014	(r273162)
@@ -883,7 +883,8 @@ zvol_remove_minors(const char *name)
 	LIST_FOREACH_SAFE(zv, &all_zvols, zv_links, tzv) {
 		if (strcmp(zv->zv_name, name) == 0 ||
 		    (strncmp(zv->zv_name, name, namelen) == 0 &&
-		     zv->zv_name[namelen] == '/')) {
+		    strlen(zv->zv_name) > namelen && (zv->zv_name[namelen] == '/' ||
+		    zv->zv_name[namelen] == '@'))) {
 			(void) zvol_remove_zv(zv);
 		}
 	}
@@ -2571,9 +2572,10 @@ zvol_create_minors(const char *name)
 	if (dmu_objset_type(os) == DMU_OST_ZVOL) {
 		dsl_dataset_long_hold(os->os_dsl_dataset, FTAG);
 		dsl_pool_rele(dmu_objset_pool(os), FTAG);
-		if ((error = zvol_create_minor(name)) == 0)
+		error = zvol_create_minor(name);
+		if (error == 0 || error == EEXIST) {
 			error = zvol_create_snapshots(os, name);
-		else {
+		} else {
 			printf("ZFS WARNING: Unable to create ZVOL %s (error=%d).\n",
 			    name, error);
 		}
@@ -2674,12 +2676,17 @@ zvol_rename_minors(const char *oldname, 
 	size_t oldnamelen, newnamelen;
 	zvol_state_t *zv;
 	char *namebuf;
+	boolean_t locked = B_FALSE;
 
 	oldnamelen = strlen(oldname);
 	newnamelen = strlen(newname);
 
 	DROP_GIANT();
-	mutex_enter(&spa_namespace_lock);
+	/* See comment in zvol_open(). */
+	if (!MUTEX_HELD(&spa_namespace_lock)) {
+		mutex_enter(&spa_namespace_lock);
+		locked = B_TRUE;
+	}
 
 	LIST_FOREACH(zv, &all_zvols, zv_links) {
 		if (strcmp(zv->zv_name, oldname) == 0) {
@@ -2694,7 +2701,8 @@ zvol_rename_minors(const char *oldname, 
 		}
 	}
 
-	mutex_exit(&spa_namespace_lock);
+	if (locked)
+		mutex_exit(&spa_namespace_lock);
 	PICKUP_GIANT();
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201410160839.s9G8diBZ089660>