changeset 10948:c686aa11575c

6812139 SVM dereferences NULL from sm_get_component_count and panics
author James Hall <James.Hall@Sun.COM>
date Wed, 04 Nov 2009 13:16:00 +0000
parents 2ecbb0a4d189
children 515fcb538da8
files usr/src/uts/common/io/lvm/mirror/mirror.c usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c
diffstat 2 files changed, 103 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/lvm/mirror/mirror.c	Wed Nov 04 01:45:19 2009 -0800
+++ b/usr/src/uts/common/io/lvm/mirror/mirror.c	Wed Nov 04 13:16:00 2009 +0000
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1813,6 +1813,91 @@
 	return (0);
 }
 
+/*
+ * Collapse any sparse submirror entries snarfed from the on-disk replica.
+ * Only the in-core entries are updated. The replica will be updated on-disk
+ * when the in-core replica is committed on shutdown of the SVM subsystem.
+ */
+static void
+collapse_submirrors(mm_unit_t *un)
+{
+	int			smi, nremovals, smiremove;
+	mm_submirror_t		*sm, *new_sm, *old_sm;
+	mm_submirror_ic_t	*smic;
+	int			nsmidx = un->un_nsm - 1;
+
+rescan:
+	nremovals = 0;
+	smiremove = -1;
+
+	for (smi = 0; smi <= nsmidx; smi++) {
+		sm = &un->un_sm[smi];
+
+		/*
+		 * Check to see if this submirror is marked as in-use.
+		 * If it isn't then it is a potential sparse entry and
+		 * may need to be cleared from the configuration.
+		 * The records should _already_ have been cleared by the
+		 * original mirror_detach() code, but we need to shuffle
+		 * any NULL entries in un_sm[] to the end of the array.
+		 * Any NULL un_smic[] entries need to be reset to the underlying
+		 * submirror/slice accessor functions.
+		 */
+		if (!SMS_BY_INDEX_IS(un, smi, SMS_INUSE)) {
+			nremovals++;
+			smiremove = smi;
+			break;
+		}
+	}
+
+	if (nremovals == 0) {
+		/*
+		 * Ensure that we have a matching contiguous set of un_smic[]
+		 * entries for the corresponding un_sm[] entries
+		 */
+		for (smi = 0; smi <= nsmidx; smi++) {
+			smic = &un->un_smic[smi];
+			sm = &un->un_sm[smi];
+
+			smic->sm_shared_by_blk =
+			    md_get_named_service(sm->sm_dev, 0,
+			    "shared by_blk", 0);
+			smic->sm_shared_by_indx =
+			    md_get_named_service(sm->sm_dev, 0,
+			    "shared by indx", 0);
+			smic->sm_get_component_count =
+			    (int (*)())md_get_named_service(sm->sm_dev, 0,
+			    "get component count", 0);
+			smic->sm_get_bcss =
+			    (int (*)())md_get_named_service(sm->sm_dev, 0,
+			    "get block count skip size", 0);
+		}
+		return;
+	}
+
+	/*
+	 * Reshuffle the submirror devices so that we do not have a dead record
+	 * in the middle of the array. Once we've done this we need to rescan
+	 * the mirror to check for any other holes.
+	 */
+	for (smi = 0; smi < NMIRROR; smi++) {
+		if (smi < smiremove)
+			continue;
+		if (smi > smiremove) {
+			old_sm = &un->un_sm[smi];
+			new_sm = &un->un_sm[smi - 1];
+			bcopy(old_sm, new_sm, sizeof (mm_submirror_t));
+			bzero(old_sm, sizeof (mm_submirror_t));
+		}
+	}
+
+	/*
+	 * Now we need to rescan the array to find the next potential dead
+	 * entry.
+	 */
+	goto rescan;
+}
+
 /* Return a -1 if optimized record unavailable and set should be released */
 int
 mirror_build_incore(mm_unit_t *un, int snarfing)
@@ -1839,6 +1924,17 @@
 	avl_create(&un->un_overlap_root, mirror_overlap_compare,
 	    sizeof (md_mps_t), offsetof(md_mps_t, ps_overlap_node));
 
+	/*
+	 * We need to collapse any sparse submirror entries into a non-sparse
+	 * array. This is to cover the case where we have an old replica image
+	 * which has not been updated (i.e. snarfed) since being modified.
+	 * The new code expects all submirror access to be sequential (i.e.
+	 * both the un_sm[] and un_smic[] entries correspond to non-empty
+	 * submirrors.
+	 */
+
+	collapse_submirrors(un);
+
 	for (i = 0; i < NMIRROR; i++)
 		build_submirror(un, i, snarfing);
 
--- a/usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c	Wed Nov 04 01:45:19 2009 -0800
+++ b/usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c	Wed Nov 04 13:16:00 2009 +0000
@@ -1019,6 +1019,8 @@
 	mddb_recid_t		recids[2];
 	int			nsv = 0;
 	int			smi_remove;
+	mm_submirror_ic_t	*old_smic;
+	mm_submirror_ic_t	*new_smic;
 
 	mdclrerror(&det->mde);
 
@@ -1135,6 +1137,10 @@
 			new_sm->sm_hsp_id = old_sm->sm_hsp_id;
 			new_sm->sm_timestamp = old_sm->sm_timestamp;
 			bzero(old_sm, sizeof (mm_submirror_t));
+			old_smic = &un->un_smic[smi];
+			new_smic = &un->un_smic[smi - 1];
+			bcopy(old_smic, new_smic, sizeof (mm_submirror_ic_t));
+			bzero(old_smic, sizeof (mm_submirror_ic_t));
 		}
 	}
 	mirror_commit(un, 0, NULL);