summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJames Hall <James.Hall@Sun.COM>2009-11-04 13:16:00 +0000
committerJames Hall <James.Hall@Sun.COM>2009-11-04 13:16:00 +0000
commit6be62bb1cb31cf9b2bf19971174c02023f2ead77 (patch)
treeebf5d09e5818e21259580a68059e4e634bde5a61 /usr/src
parent8031591d3cc3c82e97f4b60ea22d671525077b15 (diff)
downloadillumos-joyent-6be62bb1cb31cf9b2bf19971174c02023f2ead77.tar.gz
6812139 SVM dereferences NULL from sm_get_component_count and panics
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/lvm/mirror/mirror.c98
-rw-r--r--usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c6
2 files changed, 103 insertions, 1 deletions
diff --git a/usr/src/uts/common/io/lvm/mirror/mirror.c b/usr/src/uts/common/io/lvm/mirror/mirror.c
index 0097a0be57..b3e563b6d2 100644
--- a/usr/src/uts/common/io/lvm/mirror/mirror.c
+++ b/usr/src/uts/common/io/lvm/mirror/mirror.c
@@ -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 @@ mirror_overlap_compare(const void *p1, const void *p2)
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 @@ mirror_build_incore(mm_unit_t *un, int snarfing)
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);
diff --git a/usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c b/usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c
index d2c12f6f9c..1e9a3a494b 100644
--- a/usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c
+++ b/usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c
@@ -1019,6 +1019,8 @@ mirror_detach(
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 @@ mirror_detach(
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);