Mercurial > illumos > illumos-gate
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);