static int seths_delete(set_hs_params_t *shs) { hot_spare_t *hs; hot_spare_t *prev_hs; hot_spare_pool_t *hsp; mddb_recid_t recids[4]; int i; set_t setno; sv_dev_t sv; int delete_hs = 0; mdkey_t key_old; int num_keys_old = 0; /* delete the hot spare pool */ if (shs->shs_options & HS_OPT_POOL) { return (seths_delete_hsp(shs)); } setno = HSP_SET(shs->shs_hot_spare_pool); /* Scan the hot spare list */ hs = (hot_spare_t *)md_set[setno].s_hs; prev_hs = (hot_spare_t *)0; while (hs) { if (hs->hs_devnum == shs->shs_component_old) { break; } prev_hs = hs; hs = hs->hs_next; } if (hs == NULL) { /* * Unable to find device using devnum so use * key associated with shs_component_old instead. * If unable to find a unique key for shs_component_old * then fail since namespace has multiple entries * for this old component and we're unable to determine * which key is the valid match for shs_component_old. * * Only need to compare keys when hs_devnum is NODEV. */ if (md_getkeyfromdev(setno, mddb_getsidenum(setno), shs->shs_component_old, &key_old, &num_keys_old) != 0) { return (mddeverror(&shs->mde, MDE_NAME_SPACE, shs->shs_component_old)); } /* * If more than one key matches given old_dev - fail command * since shouldn't add new hotspare if namespace has * multiple entries. */ if (num_keys_old > 1) { return (mddeverror(&shs->mde, MDE_MULTNM, shs->shs_component_old)); } /* * If there is no key for this entry then fail since * a key for this entry should exist. */ if (num_keys_old == 0) { return (mddeverror(&shs->mde, MDE_INVAL_HS, shs->shs_component_old)); } /* Scan the hot spare list again */ hs = (hot_spare_t *)md_set[setno].s_hs; prev_hs = (hot_spare_t *)0; while (hs) { /* * Only need to compare keys when hs_devnum is NODEV. */ if ((hs->hs_devnum == NODEV64) && (hs->hs_key == key_old)) { break; } prev_hs = hs; hs = hs->hs_next; } } if (hs == NULL) { return (mddeverror(&shs->mde, MDE_INVAL_HS, shs->shs_component_old)); } /* Scan the hot spare pool list */ hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool); if (hsp == (hot_spare_pool_t *)0) { return (mdhsperror(&shs->mde, MDE_INVAL_HSP, shs->shs_hot_spare_pool)); } /* check for force flag and state of hot spare */ if (((shs->shs_options & HS_OPT_FORCE) == 0) && (hs->hs_state == HSS_RESERVED)) { return (mdhserror(&shs->mde, MDE_HS_RESVD, shs->shs_hot_spare_pool, shs->shs_component_old)); } if (hsp->hsp_refcount && (hs->hs_state == HSS_RESERVED)) { return (mdhserror(&shs->mde, MDE_HS_RESVD, shs->shs_hot_spare_pool, shs->shs_component_old)); } /* * Make sure the device is in the pool. */ for (i = 0; i < hsp->hsp_nhotspares; i++) { if (hsp->hsp_hotspares[i] == hs->hs_record_id) { break; } } if (i >= hsp->hsp_nhotspares) { return (mddeverror(&shs->mde, MDE_INVAL_HS, hs->hs_devnum)); } /* In case of a dryrun, we're done here */ if (shs->shs_options & HS_OPT_DRYRUN) { return (0); } /* lock the db records */ recids[0] = hs->hs_record_id; recids[1] = hsp->hsp_record_id; recids[2] = 0; sv.setno = setno; sv.key = hs->hs_key; hs->hs_refcount--; if (hs->hs_refcount == 0) { /* * NOTE: We do not commit the previous hot spare record. * There is no need, the link we get rebuilt at boot time. */ if (prev_hs) { prev_hs->hs_next = hs->hs_next; } else md_set[setno].s_hs = (void *) hs->hs_next; /* mark the hot spare to be deleted */ delete_hs = 1; recids[0] = hsp->hsp_record_id; recids[1] = 0; } /* find the location of the hs in the hsp */ for (i = 0; i < hsp->hsp_nhotspares; i++) { if (hsp->hsp_hotspares[i] == hs->hs_record_id) break; } /* remove the hs from the hsp */ for (i++; i < hsp->hsp_nhotspares; i++) hsp->hsp_hotspares[i - 1] = hsp->hsp_hotspares[i]; hsp->hsp_nhotspares--; /* commit the db records */ mddb_commitrecs_wrapper(recids); if (delete_hs) mddb_deleterec_wrapper(hs->hs_record_id); md_rem_names(&sv, 1); SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REMOVE, SVM_TAG_HSP, setno, md_expldev(hsp->hsp_self_id)); return (0); }
static int seths_replace(set_hs_params_t *shs) { hot_spare_t *hs; hot_spare_t *prev_hs; hot_spare_t *new_hs; hot_spare_pool_t *hsp; int new_found = 0; mddb_recid_t recid; mddb_recid_t recids[5]; int i; sv_dev_t sv; int delete_hs = 0; set_t setno; mddb_type_t typ1; mdkey_t key_old; int num_keys_old = 0; setno = HSP_SET(shs->shs_hot_spare_pool); typ1 = (mddb_type_t)md_getshared_key(setno, hotspares_md_ops.md_driver.md_drivername); /* Scan the hot spare list */ hs = (hot_spare_t *)md_set[setno].s_hs; prev_hs = (hot_spare_t *)0; while (hs) { if (hs->hs_devnum == shs->shs_component_old) { break; } prev_hs = hs; hs = hs->hs_next; } if (hs == NULL) { /* * Unable to find device using devnum so use * key associated with shs_component_old instead. * If unable to find a unique key for shs_component_old * then fail since namespace has multiple entries * for this old component and we're unable to determine * which key is the valid match for shs_component_old. * * Only need to compare keys when hs_devnum is NODEV. */ if (md_getkeyfromdev(setno, mddb_getsidenum(setno), shs->shs_component_old, &key_old, &num_keys_old) != 0) { return (mddeverror(&shs->mde, MDE_NAME_SPACE, shs->shs_component_old)); } /* * If more than one key matches given old_dev - fail command * since unable to determine which key is correct. */ if (num_keys_old > 1) { return (mddeverror(&shs->mde, MDE_MULTNM, shs->shs_component_old)); } /* * If there is no key for this entry then fail since * a key for this entry should exist. */ if (num_keys_old == 0) { return (mddeverror(&shs->mde, MDE_INVAL_HS, shs->shs_component_old)); } /* Scan the hot spare list again */ hs = (hot_spare_t *)md_set[setno].s_hs; prev_hs = (hot_spare_t *)0; while (hs) { /* * Only need to compare keys when hs_devnum is NODEV. */ if ((hs->hs_devnum == NODEV64) && (hs->hs_key == key_old)) { break; } prev_hs = hs; hs = hs->hs_next; } } if (hs == NULL) { return (mddeverror(&shs->mde, MDE_INVAL_HS, shs->shs_component_old)); } /* check the force flag and the state of the hot spare */ if (((shs->shs_options & HS_OPT_FORCE) == 0) && (hs->hs_state == HSS_RESERVED)) { return (mdhserror(&shs->mde, MDE_HS_RESVD, shs->shs_hot_spare_pool, hs->hs_devnum)); } /* Scan the hot spare pool list */ hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool); if (hsp == (hot_spare_pool_t *)0) { return (mdhsperror(&shs->mde, MDE_INVAL_HSP, shs->shs_hot_spare_pool)); } /* * Make sure the old device is in the pool. */ for (i = 0; i < hsp->hsp_nhotspares; i++) { if (hsp->hsp_hotspares[i] == hs->hs_record_id) { break; } } if (i >= hsp->hsp_nhotspares) { return (mddeverror(&shs->mde, MDE_INVAL_HS, hs->hs_devnum)); } /* Scan the hot spare list for the new hs */ new_hs = (hot_spare_t *)md_set[setno].s_hs; new_found = 0; while (new_hs) { if (new_hs->hs_devnum == shs->shs_component_new) { new_found = 1; break; } new_hs = new_hs->hs_next; } /* * Make sure the new device is not already in the pool. * We don't have to search the hs in this hsp, if the * new hs was just created. Only if the hot spare was found. */ if (new_found) { for (i = 0; i < hsp->hsp_nhotspares; i++) if (hsp->hsp_hotspares[i] == new_hs->hs_record_id) { return (mdhserror(&shs->mde, MDE_HS_INUSE, shs->shs_hot_spare_pool, new_hs->hs_devnum)); } } /* In case of a dryrun, we're done here */ if (shs->shs_options & HS_OPT_DRYRUN) { return (0); } /* * Create the new hotspare */ if (!new_found) { /* create a hot spare record */ if (shs->shs_size_option & MD_CRO_64BIT) { #if defined(_ILP32) return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE, shs->shs_hot_spare_pool, shs->shs_component_new)); #else recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, MD_CRO_64BIT | MD_CRO_HOTSPARE, setno); #endif } else { recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE, setno); } if (recid < 0) { return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE, shs->shs_hot_spare_pool, shs->shs_component_new)); } /* get the addr */ new_hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, sizeof (*new_hs), 0); new_hs->hs_record_id = recid; new_hs->hs_devnum = shs->shs_component_new; new_hs->hs_key = shs->shs_key_new; new_hs->hs_start_blk = shs->shs_start_blk; new_hs->hs_has_label = shs->shs_has_label; new_hs->hs_number_blks = shs->shs_number_blks; set_hot_spare_state(new_hs, HSS_AVAILABLE); new_hs->hs_refcount = 0; new_hs->hs_isopen = 1; } /* lock the db records */ recids[0] = hs->hs_record_id; recids[1] = new_hs->hs_record_id; recids[2] = hsp->hsp_record_id; recids[3] = 0; sv.setno = setno; sv.key = hs->hs_key; hs->hs_refcount--; if (hs->hs_refcount == 0) { /* * NOTE: We do not commit the previous hot spare record. * There is no need, the link we get rebuilt at boot time. */ if (prev_hs) { prev_hs->hs_next = hs->hs_next; } else md_set[setno].s_hs = (void *) hs->hs_next; /* mark hs to be deleted in the correct order */ delete_hs = 1; recids[0] = new_hs->hs_record_id; recids[1] = hsp->hsp_record_id; recids[2] = 0; } /* link into the hs list */ new_hs->hs_refcount++; if (!new_found) { /* do this AFTER the old dev is possibly removed */ new_hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; md_set[setno].s_hs = (void *) new_hs; } /* find the location of the old hs in the hsp */ for (i = 0; i < hsp->hsp_nhotspares; i++) { if (hsp->hsp_hotspares[i] == hs->hs_record_id) { hsp->hsp_hotspares[i] = new_hs->hs_record_id; break; } } if (shs->shs_size_option & MD_CRO_64BIT) { new_hs->hs_revision |= MD_64BIT_META_DEV; } else { new_hs->hs_revision &= ~MD_64BIT_META_DEV; } /* commit the db records */ mddb_commitrecs_wrapper(recids); if (delete_hs) mddb_deleterec_wrapper(hs->hs_record_id); md_rem_names(&sv, 1); SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REPLACE, SVM_TAG_HSP, setno, md_expldev(hsp->hsp_self_id)); return (0); }
void reset_stripe(ms_unit_t *un, minor_t mnum, int removing) { ms_comp_t *mdcomp; struct ms_row *mdr; int i, c; int row; int nsv; int isv; sv_dev_t *sv; mddb_recid_t *recids; mddb_recid_t vtoc_id; int rid = 0; md_destroy_unit_incore(mnum, &stripe_md_ops); md_nblocks_set(mnum, -1ULL); MD_UNIT(mnum) = NULL; /* * Attempt release of its minor node */ md_remove_minor_node(mnum); if (!removing) return; nsv = 0; /* Count the number of devices */ for (row = 0; row < un->un_nrows; row++) { mdr = &un->un_row[row]; nsv += mdr->un_ncomp; } sv = (sv_dev_t *)kmem_alloc(sizeof (sv_dev_t) * nsv, KM_SLEEP); /* * allocate recids array. since we may have to commit * underlying soft partition records, we need an array * of size: total number of components in stripe + 3 * (one for the stripe itself, one for the hotspare, one * for the end marker). */ recids = kmem_alloc(sizeof (mddb_recid_t) * (nsv + 3), KM_SLEEP); /* * Save the md_dev64_t's and driver nm indexes. * Because after the mddb_deleterec() we will * not be able to access the unit structure. * * NOTE: Deleting the names before deleting the * unit structure would cause problems if * the machine crashed in between the two. */ isv = 0; mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]); for (row = 0; row < un->un_nrows; row++) { mdr = &un->un_row[row]; for (i = 0, c = mdr->un_icomp; i < mdr->un_ncomp; i++) { struct ms_comp *mdc; md_dev64_t child_dev; md_unit_t *child_un; mdc = &mdcomp[c++]; if (mdc->un_mirror.ms_hs_id != 0) { mdkey_t hs_key; hs_key = mdc->un_mirror.ms_hs_key; mdc->un_dev = mdc->un_mirror.ms_orig_dev; mdc->un_start_block = mdc->un_mirror.ms_orig_blk; mdc->un_mirror.ms_hs_id = 0; mdc->un_mirror.ms_hs_key = 0; mdc->un_mirror.ms_orig_dev = 0; recids[0] = 0; recids[1] = 0; /* recids[1] filled in below */ recids[2] = 0; (void) md_hot_spare_ifc(HS_FREE, un->un_hsp_id, 0, 0, &recids[0], &hs_key, NULL, NULL); mddb_commitrecs_wrapper(recids); } /* * check if we've got metadevice below us and * deparent it if we do. * NOTE: currently soft partitions are the * the only metadevices stripes can be * built on top of. */ child_dev = mdc->un_dev; if (md_getmajor(child_dev) == md_major) { child_un = MD_UNIT(md_getminor(child_dev)); md_reset_parent(child_dev); recids[rid++] = MD_RECID(child_un); } sv[isv].setno = MD_MIN2SET(mnum); sv[isv++].key = mdc->un_key; } } recids[rid++] = un->c.un_record_id; recids[rid] = 0; /* filled in below */ /* * Decrement the HSP reference count and * remove the knowledge of the HSP from the unit struct. * This is done atomically to remove a window. */ if (un->un_hsp_id != -1) { (void) md_hot_spare_ifc(HSP_DECREF, un->un_hsp_id, 0, 0, &recids[rid++], NULL, NULL, NULL); un->un_hsp_id = -1; } /* set end marker and commit records */ recids[rid] = 0; mddb_commitrecs_wrapper(recids); vtoc_id = un->c.un_vtoc_id; /* * Remove self from the namespace */ if (un->c.un_revision & MD_FN_META_DEV) { (void) md_rem_selfname(un->c.un_self_id); } /* Remove the unit structure */ mddb_deleterec_wrapper(un->c.un_record_id); /* Remove the vtoc, if present */ if (vtoc_id) mddb_deleterec_wrapper(vtoc_id); SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_DELETE, SVM_TAG_METADEVICE, MD_MIN2SET(mnum), MD_MIN2UNIT(mnum)); md_rem_names(sv, nsv); kmem_free(sv, sizeof (sv_dev_t) * nsv); kmem_free(recids, sizeof (mddb_recid_t) * (nsv + 3)); }