6655963 Panic: 0 == zap_add(mos, pds->dd_phys->dd_child_dir_zapobj, name, sizeof (uint64_t), 1, &ddobj, tx)
authorek110237
Tue, 26 Feb 2008 11:31:49 -0800
changeset 6083 23e77aa611b1
parent 6082 30337f24796b
child 6084 d5f45b4dae7e
6655963 Panic: 0 == zap_add(mos, pds->dd_phys->dd_child_dir_zapobj, name, sizeof (uint64_t), 1, &ddobj, tx) 6661137 simultaneous rollbacks can panic the system 6662714 panic: rrw_held(&zfsvfs->z_teardown_lock, RW_WRITER), file: ../../common/fs/zfs/zfs_vfsops.c
usr/src/uts/common/fs/zfs/dmu_send.c
usr/src/uts/common/fs/zfs/sys/dmu.h
usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
usr/src/uts/common/fs/zfs/zfs_ioctl.c
usr/src/uts/common/fs/zfs/zfs_vfsops.c
--- a/usr/src/uts/common/fs/zfs/dmu_send.c	Tue Feb 26 07:21:54 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/dmu_send.c	Tue Feb 26 11:31:49 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -467,6 +467,15 @@
 	if (ds->ds_prev->ds_phys->ds_guid != rbsa->fromguid)
 		return (ENODEV);
 
+	/* temporary clone name must not exist */
+	err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
+	    ds->ds_dir->dd_phys->dd_child_dir_zapobj,
+	    rbsa->clonelastname, 8, 1, &val);
+	if (err == 0)
+		return (EEXIST);
+	if (err != ENOENT)
+		return (err);
+
 	/* new snapshot name must not exist */
 	err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
 	    ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val);
@@ -963,8 +972,8 @@
 	return (err);
 }
 
-static void
-recv_abort_cleanup(dmu_recv_cookie_t *drc)
+void
+dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc)
 {
 	if (drc->drc_newfs || drc->drc_real_ds != drc->drc_logical_ds) {
 		/*
@@ -1124,7 +1133,7 @@
 		 * leave it in the restoring state.
 		 */
 		txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0);
-		recv_abort_cleanup(drc);
+		dmu_recv_abort_cleanup(drc);
 	}
 
 	kmem_free(ra.buf, ra.bufsize);
@@ -1182,7 +1191,7 @@
 	    DS_MODE_PRIMARY, DS_MODE_EXCLUSIVE)) {
 		lmode = DS_MODE_EXCLUSIVE;
 	} else {
-		recv_abort_cleanup(drc);
+		dmu_recv_abort_cleanup(drc);
 		return (EBUSY);
 	}
 
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h	Tue Feb 26 07:21:54 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h	Tue Feb 26 11:31:49 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -605,6 +605,7 @@
     boolean_t force, objset_t *origin, boolean_t online, dmu_recv_cookie_t *);
 int dmu_recv_stream(dmu_recv_cookie_t *drc, struct vnode *vp, offset_t *voffp);
 int dmu_recv_end(dmu_recv_cookie_t *drc);
+void dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc);
 
 /* CRC64 table */
 #define	ZFS_CRC64_POLY	0xC96C5795D7870F42ULL	/* ECMA-182, reflected form */
--- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h	Tue Feb 26 07:21:54 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h	Tue Feb 26 11:31:49 2008 -0800
@@ -74,7 +74,8 @@
 	boolean_t	z_issnap;	/* true if this is a snapshot */
 	boolean_t	z_vscan;	/* virus scan on/off */
 	boolean_t	z_use_fuids;	/* version allows fuids */
-	uint64_t	z_version;
+	kmutex_t	z_online_recv_lock; /* recv in prog grabs as WRITER */
+	uint64_t	z_version;	/* ZPL version */
 #define	ZFS_OBJ_MTX_SZ	64
 	kmutex_t	z_hold_mtx[ZFS_OBJ_MTX_SZ];	/* znode hold locks */
 };
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Tue Feb 26 07:21:54 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Tue Feb 26 11:31:49 2008 -0800
@@ -2186,11 +2186,17 @@
 		char osname[MAXNAMELEN];
 		int mode;
 
-		VERIFY3U(0, ==, zfs_suspend_fs(zfsvfs, osname, &mode));
-		ASSERT(strcmp(osname, zc->zc_name) == 0);
-		error = dmu_objset_rollback(os);
-		VERIFY3U(0, ==, zfs_resume_fs(zfsvfs, osname, mode));
-
+		error = zfs_suspend_fs(zfsvfs, osname, &mode);
+		if (error == 0) {
+			int resume_err;
+
+			ASSERT(strcmp(osname, zc->zc_name) == 0);
+			error = dmu_objset_rollback(os);
+			resume_err = zfs_resume_fs(zfsvfs, osname, mode);
+			error = error ? error : resume_err;
+		} else {
+			dmu_objset_close(os);
+		}
 		VFS_RELE(zfsvfs->z_vfs);
 	} else {
 		error = dmu_objset_rollback(os);
@@ -2294,9 +2300,19 @@
 	if (!error) {
 		mutex_enter(&os->os->os_user_ptr_lock);
 		zfsvfs = dmu_objset_get_user(os);
-		if (zfsvfs != NULL)
+		if (zfsvfs != NULL) {
 			VFS_HOLD(zfsvfs->z_vfs);
-		mutex_exit(&os->os->os_user_ptr_lock);
+			mutex_exit(&os->os->os_user_ptr_lock);
+			if (!mutex_tryenter(&zfsvfs->z_online_recv_lock)) {
+				VFS_RELE(zfsvfs->z_vfs);
+				dmu_objset_close(os);
+				nvlist_free(props);
+				releasef(fd);
+				return (EBUSY);
+			}
+		} else {
+			mutex_exit(&os->os->os_user_ptr_lock);
+		}
 		dmu_objset_close(os);
 	}
 
@@ -2304,8 +2320,10 @@
 		error = dmu_objset_open(zc->zc_string, DMU_OST_ANY,
 		    DS_MODE_STANDARD | DS_MODE_READONLY, &origin);
 		if (error) {
-			if (zfsvfs != NULL)
+			if (zfsvfs != NULL) {
+				mutex_exit(&zfsvfs->z_online_recv_lock);
 				VFS_RELE(zfsvfs->z_vfs);
+			}
 			nvlist_free(props);
 			releasef(fd);
 			return (error);
@@ -2317,8 +2335,10 @@
 	if (origin)
 		dmu_objset_close(origin);
 	if (error) {
-		if (zfsvfs != NULL)
+		if (zfsvfs != NULL) {
+			mutex_exit(&zfsvfs->z_online_recv_lock);
 			VFS_RELE(zfsvfs->z_vfs);
+		}
 		nvlist_free(props);
 		releasef(fd);
 		return (error);
@@ -2372,15 +2392,25 @@
 			char osname[MAXNAMELEN];
 			int mode;
 
-			(void) zfs_suspend_fs(zfsvfs, osname, &mode);
-			error = dmu_recv_end(&drc);
-			error |= zfs_resume_fs(zfsvfs, osname, mode);
+			error = zfs_suspend_fs(zfsvfs, osname, &mode);
+			if (error == 0) {
+				int resume_err;
+
+				error = dmu_recv_end(&drc);
+				resume_err = zfs_resume_fs(zfsvfs,
+				    osname, mode);
+				error = error ? error : resume_err;
+			} else {
+				dmu_recv_abort_cleanup(&drc);
+			}
 		} else {
 			error = dmu_recv_end(&drc);
 		}
 	}
-	if (zfsvfs != NULL)
+	if (zfsvfs != NULL) {
+		mutex_exit(&zfsvfs->z_online_recv_lock);
 		VFS_RELE(zfsvfs->z_vfs);
+	}
 
 	zc->zc_cookie = off - fp->f_offset;
 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Tue Feb 26 07:21:54 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Tue Feb 26 11:31:49 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -624,6 +624,18 @@
 	return (0);
 }
 
+static void
+zfs_freezfsvfs(zfsvfs_t *zfsvfs)
+{
+	mutex_destroy(&zfsvfs->z_znodes_lock);
+	mutex_destroy(&zfsvfs->z_online_recv_lock);
+	list_destroy(&zfsvfs->z_all_znodes);
+	rrw_destroy(&zfsvfs->z_teardown_lock);
+	rw_destroy(&zfsvfs->z_teardown_inactive_lock);
+	rw_destroy(&zfsvfs->z_fuid_lock);
+	kmem_free(zfsvfs, sizeof (zfsvfs_t));
+}
+
 static int
 zfs_domount(vfs_t *vfsp, char *osname, cred_t *cr)
 {
@@ -650,6 +662,7 @@
 	zfsvfs->z_show_ctldir = ZFS_SNAPDIR_VISIBLE;
 
 	mutex_init(&zfsvfs->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
+	mutex_init(&zfsvfs->z_online_recv_lock, NULL, MUTEX_DEFAULT, NULL);
 	list_create(&zfsvfs->z_all_znodes, sizeof (znode_t),
 	    offsetof(znode_t, z_link_node));
 	rrw_init(&zfsvfs->z_teardown_lock);
@@ -738,12 +751,7 @@
 	if (error) {
 		if (zfsvfs->z_os)
 			dmu_objset_close(zfsvfs->z_os);
-		mutex_destroy(&zfsvfs->z_znodes_lock);
-		list_destroy(&zfsvfs->z_all_znodes);
-		rrw_destroy(&zfsvfs->z_teardown_lock);
-		rw_destroy(&zfsvfs->z_teardown_inactive_lock);
-		rw_destroy(&zfsvfs->z_fuid_lock);
-		kmem_free(zfsvfs, sizeof (zfsvfs_t));
+		zfs_freezfsvfs(zfsvfs);
 	} else {
 		atomic_add_32(&zfs_active_fs_count, 1);
 	}
@@ -1145,7 +1153,6 @@
 static int
 zfsvfs_teardown(zfsvfs_t *zfsvfs, boolean_t unmounting)
 {
-	objset_t *os = zfsvfs->z_os;
 	znode_t	*zp;
 
 	rrw_enter(&zfsvfs->z_teardown_lock, RW_WRITER, FTAG);
@@ -1225,9 +1232,9 @@
 	/*
 	 * Evict cached data
 	 */
-	if (dmu_objset_evict_dbufs(os)) {
+	if (dmu_objset_evict_dbufs(zfsvfs->z_os)) {
 		txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0);
-		(void) dmu_objset_evict_dbufs(os);
+		(void) dmu_objset_evict_dbufs(zfsvfs->z_os);
 	}
 
 	return (0);
@@ -1482,13 +1489,8 @@
 	for (i = 0; i != ZFS_OBJ_MTX_SZ; i++)
 		mutex_destroy(&zfsvfs->z_hold_mtx[i]);
 
-	mutex_destroy(&zfsvfs->z_znodes_lock);
-	list_destroy(&zfsvfs->z_all_znodes);
-	rrw_destroy(&zfsvfs->z_teardown_lock);
-	rw_destroy(&zfsvfs->z_teardown_inactive_lock);
 	zfs_fuid_destroy(zfsvfs);
-	rw_destroy(&zfsvfs->z_fuid_lock);
-	kmem_free(zfsvfs, sizeof (zfsvfs_t));
+	zfs_freezfsvfs(zfsvfs);
 
 	atomic_add_32(&zfs_active_fs_count, -1);
 }