6940770 panic in sa_find_idx_tab() after receiving into pool when version shouldn't have allowed it
authorMark Shellenbaum <Mark.Shellenbaum@Sun.COM>
Sun, 04 Apr 2010 17:04:46 -0600
changeset 12070 01261b276236
parent 12069 c8ca11049d6c
child 12071 1af7bbe2d937
6940770 panic in sa_find_idx_tab() after receiving into pool when version shouldn't have allowed it
usr/src/lib/libzfs/common/libzfs_mount.c
usr/src/lib/libzfs/common/libzfs_sendrecv.c
usr/src/uts/common/fs/zfs/dmu_send.c
usr/src/uts/common/fs/zfs/zfs_vfsops.c
--- a/usr/src/lib/libzfs/common/libzfs_mount.c	Sat Apr 03 14:24:23 2010 -0400
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c	Sun Apr 04 17:04:46 2010 -0600
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -316,13 +315,15 @@
 			    "Insufficient privileges"));
 		} else if (errno == ENOTSUP) {
 			char buf[256];
+			int spa_version;
 
+			VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
 			(void) snprintf(buf, sizeof (buf),
-			    dgettext(TEXT_DOMAIN, "Mismatched versions:  File "
-			    "system is version %llu on-disk format, which is "
-			    "incompatible with this software version %lld!"),
+			    dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
+			    "file system on a version %d pool. Pool must be"
+			    " upgraded to mount this file system."),
 			    (u_longlong_t)zfs_prop_get_int(zhp,
-			    ZFS_PROP_VERSION), ZPL_VERSION);
+			    ZFS_PROP_VERSION), spa_version);
 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
 		} else {
 			zfs_error_aux(hdl, strerror(errno));
--- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c	Sat Apr 03 14:24:23 2010 -0400
+++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c	Sun Apr 04 17:04:46 2010 -0600
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <assert.h>
@@ -2683,6 +2682,11 @@
 			    "invalid stream (checksum mismatch)"));
 			(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
 			break;
+		case ENOTSUP:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "pool must be upgraded to receive this stream."));
+			(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+			break;
 		default:
 			(void) zfs_standard_error(hdl, ioctl_errno, errbuf);
 		}
--- a/usr/src/uts/common/fs/zfs/dmu_send.c	Sat Apr 03 14:24:23 2010 -0400
+++ b/usr/src/uts/common/fs/zfs/dmu_send.c	Sun Apr 04 17:04:46 2010 -0600
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/dmu.h>
@@ -39,6 +38,7 @@
 #include <sys/zfs_ioctl.h>
 #include <sys/zap.h>
 #include <sys/zio_checksum.h>
+#include <sys/zfs_znode.h>
 #include <sys/avl.h>
 #include <sys/ddt.h>
 
@@ -419,6 +419,20 @@
 	drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
 	DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo,
 	    DMU_SUBSTREAM);
+
+#ifdef _KERNEL
+	if (dmu_objset_type(tosnap) == DMU_OST_ZFS) {
+		uint64_t version;
+		if (zfs_get_zplprop(tosnap, ZFS_PROP_VERSION, &version) != 0)
+			return (EINVAL);
+		if (version == ZPL_VERSION_SA) {
+			DMU_SET_FEATUREFLAGS(
+			    drr->drr_u.drr_begin.drr_versioninfo,
+			    DMU_BACKUP_FEATURE_SA_SPILL);
+		}
+	}
+#endif
+
 	drr->drr_u.drr_begin.drr_creation_time =
 	    ds->ds_phys->ds_creation_time;
 	drr->drr_u.drr_begin.drr_type = tosnap->os_phys->os_type;
@@ -645,6 +659,19 @@
 	    dp->dp_spa, tx, cr, "dataset = %lld", dsobj);
 }
 
+
+static boolean_t
+dmu_recv_verify_features(dsl_dataset_t *ds, struct drr_begin *drrb)
+{
+	int featureflags;
+
+	featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+
+	/* Verify pool version supports SA if SA_SPILL feature set */
+	return ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) &&
+	    (spa_version(dsl_dataset_get_spa(ds)) < SPA_VERSION_SA));
+}
+
 /*
  * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
  * succeeds; otherwise we will leak the holds on the datasets.
@@ -705,6 +732,10 @@
 	/* open the dataset we are logically receiving into */
 	err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds);
 	if (err == 0) {
+		if (dmu_recv_verify_features(ds, drrb)) {
+			dsl_dataset_rele(ds, dmu_recv_tag);
+			return (ENOTSUP);
+		}
 		/* target fs already exists; recv into temp clone */
 
 		/* Can't recv a clone into an existing fs */
@@ -751,6 +782,11 @@
 		if (err)
 			return (err);
 
+		if (dmu_recv_verify_features(ds, drrb)) {
+			dsl_dataset_rele(ds, dmu_recv_tag);
+			return (ENOTSUP);
+		}
+
 		err = dsl_sync_task_do(ds->ds_dir->dd_pool,
 		    recv_new_check, recv_new_sync, ds->ds_dir, &rbsa, 5);
 		dsl_dataset_rele(ds, FTAG);
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Sat Apr 03 14:24:23 2010 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Sun Apr 04 17:04:46 2010 -0600
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -862,7 +861,6 @@
 	return (zfs_fuid_overquota(zfsvfs, isgroup, fuid));
 }
 
-
 int
 zfsvfs_create(const char *osname, zfsvfs_t **zfvp)
 {
@@ -898,15 +896,15 @@
 	error = zfs_get_zplprop(os, ZFS_PROP_VERSION, &zfsvfs->z_version);
 	if (error) {
 		goto out;
-	} else if (zfsvfs->z_version > ZPL_VERSION) {
-		(void) printf("Mismatched versions:  File system "
-		    "is version %llu on-disk format, which is "
-		    "incompatible with this software version %lld!",
-		    (u_longlong_t)zfsvfs->z_version, ZPL_VERSION);
+	} else if (zfsvfs->z_version >
+	    zfs_zpl_version_map(spa_version(dmu_objset_spa(os)))) {
+		(void) printf("Can't mount a version %lld file system "
+		    "on a version %lld pool\n. Pool must be upgraded to mount "
+		    "this file system.", (u_longlong_t)zfsvfs->z_version,
+		    (u_longlong_t)spa_version(dmu_objset_spa(os)));
 		error = ENOTSUP;
 		goto out;
 	}
-
 	if ((error = zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &zval)) != 0)
 		goto out;
 	zfsvfs->z_norm = (int)zval;