diff options
author | James Hall <James.Hall@Sun.COM> | 2009-11-04 13:16:00 +0000 |
---|---|---|
committer | James Hall <James.Hall@Sun.COM> | 2009-11-04 13:16:00 +0000 |
commit | 6be62bb1cb31cf9b2bf19971174c02023f2ead77 (patch) | |
tree | ebf5d09e5818e21259580a68059e4e634bde5a61 /usr/src | |
parent | 8031591d3cc3c82e97f4b60ea22d671525077b15 (diff) | |
download | illumos-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.c | 98 | ||||
-rw-r--r-- | usr/src/uts/common/io/lvm/mirror/mirror_ioctl.c | 6 |
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); |