static int get_hsp( void *d, int mode ) { hot_spare_pool_t *hsp; get_hsp_t *ghsp; size_t size; set_t setno; int err = 0; md_i_get_t *migp = (md_i_get_t *)d; setno = migp->md_driver.md_setno; mdclrerror(&migp->mde); /* Scan the hot spare pool list */ hsp = find_hot_spare_pool(setno, migp->id); if (hsp == NULL) { return (mdhsperror(&migp->mde, MDE_INVAL_HSP, migp->id)); } size = (sizeof (ghsp->ghsp_hs_keys[0]) * (hsp->hsp_nhotspares - 1)) + sizeof (get_hsp_t); if (migp->size == 0) { migp->size = (int)size; return (0); } if (migp->size < size) return (EFAULT); ghsp = kmem_alloc(size, KM_SLEEP); ghsp->ghsp_id = hsp->hsp_self_id; ghsp->ghsp_refcount = hsp->hsp_refcount; ghsp->ghsp_nhotspares = hsp->hsp_nhotspares; build_key_list(setno, hsp, ghsp->ghsp_hs_keys); if (ddi_copyout(ghsp, (caddr_t)(uintptr_t)migp->mdp, size, mode)) err = EFAULT; kmem_free(ghsp, size); return (err); }
static int stripe_change( md_stripe_params_t *msp, IOLOCK *lock ) { ms_params_t *pp = &msp->params; minor_t mnum = msp->mnum; ms_unit_t *un; mdi_unit_t *ui; int r, c, i; struct ms_row *mdr; ms_comp_t *mdcomp, *mdc; mddb_recid_t recids[4]; int irecid; int inc_new_hsp = 0; int err; set_t setno = MD_MIN2SET(mnum); mdclrerror(&msp->mde); if ((setno >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits)) return (mdmderror(&msp->mde, MDE_INVAL_UNIT, mnum)); if (md_get_setstatus(setno) & MD_SET_STALE) return (mdmddberror(&msp->mde, MDE_DB_STALE, mnum, setno)); if ((ui = MDI_UNIT(mnum)) == NULL) { return (mdmderror(&msp->mde, MDE_UNIT_NOT_SETUP, mnum)); } if (!pp->change_hsp_id) return (0); un = (ms_unit_t *)md_ioctl_writerlock(lock, ui); /* verify that no hot spares are in use */ mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]); for (r = 0; r < un->un_nrows; r++) { mdr = &un->un_row[r]; for (c = 0, i = mdr->un_icomp; c < mdr->un_ncomp; c++) { mdc = &mdcomp[i++]; if (mdc->un_mirror.ms_hs_id != 0) { return (mdmderror(&msp->mde, MDE_HS_IN_USE, mnum)); } } } recids[1] = 0; recids[2] = 0; irecid = 1; if (pp->hsp_id != -1) { /* increment the reference count of the new hsp */ err = md_hot_spare_ifc(HSP_INCREF, pp->hsp_id, 0, 0, &recids[1], NULL, NULL, NULL); if (err) { return (mdhsperror(&msp->mde, MDE_INVAL_HSP, pp->hsp_id)); } inc_new_hsp = 1; irecid++; } if (un->un_hsp_id != -1) { /* decrement the reference count of the old hsp */ err = md_hot_spare_ifc(HSP_DECREF, un->un_hsp_id, 0, 0, &recids[irecid], NULL, NULL, NULL); if (err) { err = mdhsperror(&msp->mde, MDE_INVAL_HSP, pp->hsp_id); if (inc_new_hsp) { (void) md_hot_spare_ifc(HSP_DECREF, pp->hsp_id, 0, 0, &recids[1], NULL, NULL, NULL); /* * Don't need to commit the record, * cause it never got commit before */ } return (err); } } un->un_hsp_id = pp->hsp_id; recids[0] = un->c.un_record_id; recids[3] = 0; mddb_commitrecs_wrapper(recids); SE_NOTIFY(EC_SVM_STATE, ESC_SVM_CHANGE, SVM_TAG_METADEVICE, MD_UN2SET(un), MD_SID(un)); return (0); }
static int stripe_set(void *d, int mode) { minor_t mnum; ms_unit_t *un; void *p; mddb_recid_t ms_recid; mddb_recid_t *recids; mddb_type_t typ1; int err; set_t setno; md_error_t *mdep; struct ms_comp *mdcomp; int row; int rid; int num_recs; int i, c; md_set_params_t *msp = d; mnum = msp->mnum; setno = MD_MIN2SET(mnum); mdep = &msp->mde; mdclrerror(mdep); if ((setno >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits)) { return (mdmderror(mdep, MDE_INVAL_UNIT, mnum)); } if (md_get_setstatus(setno) & MD_SET_STALE) return (mdmddberror(mdep, MDE_DB_STALE, mnum, setno)); un = MD_UNIT(mnum); if (un != NULL) { return (mdmderror(mdep, MDE_UNIT_ALREADY_SETUP, mnum)); } typ1 = (mddb_type_t)md_getshared_key(setno, stripe_md_ops.md_driver.md_drivername); /* create the db record for this mdstruct */ if (msp->options & MD_CRO_64BIT) { #if defined(_ILP32) return (mdmderror(mdep, MDE_UNIT_TOO_LARGE, mnum)); #else ms_recid = mddb_createrec((size_t)msp->size, typ1, 0, MD_CRO_64BIT | MD_CRO_STRIPE | MD_CRO_FN, setno); #endif } else { ms_recid = mddb_createrec((size_t)msp->size, typ1, 0, MD_CRO_32BIT | MD_CRO_STRIPE | MD_CRO_FN, setno); } if (ms_recid < 0) return (mddbstatus2error(mdep, ms_recid, mnum, setno)); /* get the address of the mdstruct */ p = (void *) mddb_getrecaddr(ms_recid); /* * It is okay that we muck with the mdstruct here, * since no one else will know about the mdstruct * until we commit it. If we crash, the record will * be automatically purged, since we haven't * committed it yet. */ /* copy in the user's mdstruct */ if (err = ddi_copyin((caddr_t)(uintptr_t)msp->mdp, (caddr_t)p, (size_t)msp->size, mode)) { mddb_deleterec_wrapper(ms_recid); return (EFAULT); } un = (ms_unit_t *)p; /* All 64 bit metadevices only support EFI labels. */ if (msp->options & MD_CRO_64BIT) { un->c.un_flag |= MD_EFILABEL; } /* * allocate the real recids array. since we may have to commit * underlying metadevice records, we need an array * of size: total number of components in stripe + 3 * (1 for the stripe itself, one for the hotspare, one * for the end marker). */ num_recs = 3; rid = 0; for (row = 0; row < un->un_nrows; row++) { struct ms_row *mdr = &un->un_row[row]; num_recs += mdr->un_ncomp; } recids = kmem_alloc(num_recs * sizeof (mddb_recid_t), KM_SLEEP); recids[rid++] = ms_recid; MD_SID(un) = mnum; MD_RECID(un) = recids[0]; MD_CAPAB(un) = MD_CAN_PARENT | MD_CAN_SUB_MIRROR | MD_CAN_SP; MD_PARENT(un) = MD_NO_PARENT; un->c.un_revision |= MD_FN_META_DEV; if (err = stripe_build_incore(p, 0)) { md_nblocks_set(mnum, -1ULL); MD_UNIT(mnum) = NULL; mddb_deleterec_wrapper(recids[0]); kmem_free(recids, num_recs * sizeof (mddb_recid_t)); return (err); } /* * Update unit availability */ md_set[setno].s_un_avail--; recids[rid] = 0; if (un->un_hsp_id != -1) err = md_hot_spare_ifc(HSP_INCREF, un->un_hsp_id, 0, 0, &recids[rid++], NULL, NULL, NULL); if (err) { md_nblocks_set(mnum, -1ULL); MD_UNIT(mnum) = NULL; mddb_deleterec_wrapper(recids[0]); kmem_free(recids, num_recs * sizeof (mddb_recid_t)); return (mdhsperror(mdep, MDE_INVAL_HSP, un->un_hsp_id)); } /* * set the parent on any metadevice components. * NOTE: currently soft partitions are the only metadevices * which can appear within a stripe. */ mdcomp = (ms_comp_t *)((void *)&((char *)un)[un->un_ocomp]); for (row = 0; row < un->un_nrows; row++) { struct ms_row *mdr = &un->un_row[row]; for (i = 0, c = mdr->un_icomp; i < mdr->un_ncomp; i++) { ms_comp_t *mdc = &mdcomp[c++]; md_dev64_t comp_dev; md_unit_t *comp_un; comp_dev = mdc->un_dev; if (md_getmajor(comp_dev) == md_major) { /* set parent and disallow soft partitioning */ comp_un = MD_UNIT(md_getminor(comp_dev)); recids[rid++] = MD_RECID(comp_un); md_set_parent(mdc->un_dev, MD_SID(un)); } } } /* set end marker */ recids[rid] = 0; mddb_commitrecs_wrapper(recids); md_create_unit_incore(mnum, &stripe_md_ops, 0); kmem_free(recids, (num_recs * sizeof (mddb_recid_t))); SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_METADEVICE, MD_UN2SET(un), MD_SID(un)); return (0); }
static int seths_create_hsp(set_hs_params_t *shs) { hot_spare_pool_t *hsp; mddb_recid_t recid; set_t setno; mddb_type_t typ1; setno = HSP_SET(shs->shs_hot_spare_pool); /* 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 (0); typ1 = (mddb_type_t)md_getshared_key(setno, hotspares_md_ops.md_driver.md_drivername); /* create a hot spare pool record */ if (shs->shs_options & MD_CRO_64BIT) { #if defined(_ILP32) return (mdhsperror(&shs->mde, MDE_HSP_UNIT_TOO_LARGE, shs->shs_hot_spare_pool)); #else recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1, HSP_REC, MD_CRO_64BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN, setno); #endif } else { recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1, HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN, setno); } if (recid < 0) { return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, shs->shs_hot_spare_pool)); } /* get the record addr */ hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, sizeof (*hsp), HSP_ONDSK_STR_OFF); hsp->hsp_self_id = shs->shs_hot_spare_pool; hsp->hsp_record_id = recid; hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; hsp->hsp_refcount = 0; hsp->hsp_nhotspares = 0; hsp->hsp_revision |= MD_FN_META_DEV; md_set[setno].s_hsp = (void *) hsp; mddb_commitrec_wrapper(recid); SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno, md_expldev(hsp->hsp_self_id)); rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); hsp->hsp_link.ln_next = hotspares_md_ops.md_head; hsp->hsp_link.ln_setno = setno; hsp->hsp_link.ln_id = hsp->hsp_self_id; hotspares_md_ops.md_head = &hsp->hsp_link; rw_exit(&hotspares_md_ops.md_link_rw.lock); 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); }
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_delete_hsp(set_hs_params_t *shs) { hot_spare_pool_t *prev_hsp; hot_spare_pool_t *hsp; set_t setno; hsp_t hspid; setno = HSP_SET(shs->shs_hot_spare_pool); /* Scan the hot spare pool list */ prev_hsp = (hot_spare_pool_t *)0; hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; while (hsp) { if (hsp->hsp_self_id == shs->shs_hot_spare_pool) { break; } prev_hsp = hsp; hsp = hsp->hsp_next; } if (hsp == NULL) { return (mdhsperror(&shs->mde, MDE_INVAL_HSP, shs->shs_hot_spare_pool)); } if (hsp->hsp_nhotspares != 0) { return (mdhsperror(&shs->mde, MDE_HSP_BUSY, shs->shs_hot_spare_pool)); } if (hsp->hsp_refcount != 0) { return (mdhsperror(&shs->mde, MDE_HSP_REF, shs->shs_hot_spare_pool)); } /* In case of a dryrun, we're done here */ if (shs->shs_options & HS_OPT_DRYRUN) { return (0); } /* * NOTE: We do not commit the previous hot spare pool record. * There is no need, the link gets rebuilt at boot time. */ if (prev_hsp) prev_hsp->hsp_next = hsp->hsp_next; else md_set[setno].s_hsp = (void *) hsp->hsp_next; hspid = hsp->hsp_self_id; md_rem_link(setno, hsp->hsp_self_id, &hotspares_md_ops.md_link_rw.lock, &hotspares_md_ops.md_head); mddb_deleterec_wrapper(hsp->hsp_record_id); SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_DELETE, SVM_TAG_HSP, setno, md_expldev(hspid)); return (0); }
static int seths_add(set_hs_params_t *shs) { hot_spare_t *hs; hot_spare_pool_t *hsp; hot_spare_pool_t *prev_hsp; hot_spare_pool_t *new_hsp; hot_spare_pool_t *old_hsp; md_create_rec_option_t options; mddb_recid_t recid; mddb_recid_t recids[5]; size_t new_size; int i; int delete_hsp = 0; int irecid; set_t setno; mddb_type_t typ1; int hsp_created = 0; mdkey_t key_old; int num_keys_old = 0; /* Not much to do here in case of a dryrun */ if (shs->shs_options & HS_OPT_DRYRUN) { return (0); } /* create an empty hot spare pool */ if (shs->shs_options & HS_OPT_POOL) { return (seths_create_hsp(shs)); } 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; while (hs) { if (hs->hs_devnum == shs->shs_component_old) { break; } hs = hs->hs_next; } if (hs == NULL) { /* * Did not find match for device using devnum so use * key associated with shs_component_old just * in case there is a match but the match's dev is NODEV. * If unable to find a unique key for shs_component_old * then fail since namespace has multiple entries * for this old component and we shouldn't allow * an addition of a hotspare in this case. */ 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; while (hs) { /* * Only need to compare keys when hs_devnum is NODEV. */ if ((hs->hs_devnum == NODEV64) && (hs->hs_key == key_old)) { break; } hs = hs->hs_next; } } if (hs == NULL) { /* 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_old)); #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_old)); } /* get the addr */ hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, sizeof (*hs), 0); hs->hs_record_id = recid; hs->hs_devnum = shs->shs_component_old; hs->hs_key = shs->shs_key_old; hs->hs_start_blk = shs->shs_start_blk; hs->hs_has_label = shs->shs_has_label; hs->hs_number_blks = shs->shs_number_blks; set_hot_spare_state(hs, HSS_AVAILABLE); hs->hs_refcount = 0; hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; md_set[setno].s_hs = (void *) hs; } /* Scan the hot spare pool list */ hsp = (hot_spare_pool_t *)md_set[setno].s_hsp; prev_hsp = (hot_spare_pool_t *)0; while (hsp) { if (hsp->hsp_self_id == shs->shs_hot_spare_pool) { break; } prev_hsp = hsp; hsp = hsp->hsp_next; } if (hsp == NULL) { /* create a hot spare pool record */ recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1, HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN, setno); if (recid < 0) { return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, shs->shs_hot_spare_pool)); } /* get the record addr */ hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, sizeof (*hsp), HSP_ONDSK_STR_OFF); hsp->hsp_self_id = shs->shs_hot_spare_pool; hsp->hsp_record_id = recid; hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; hsp->hsp_refcount = 0; hsp->hsp_nhotspares = 0; hsp->hsp_revision |= MD_FN_META_DEV; /* force prev_hsp to NULL, this will cause hsp to be linked */ prev_hsp = (hot_spare_pool_t *)0; rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); hsp->hsp_link.ln_next = hotspares_md_ops.md_head; hsp->hsp_link.ln_setno = setno; hsp->hsp_link.ln_id = hsp->hsp_self_id; hotspares_md_ops.md_head = &hsp->hsp_link; rw_exit(&hotspares_md_ops.md_link_rw.lock); hsp_created = 1; } else { /* * Make sure the hot spare is not already in the pool. */ for (i = 0; i < hsp->hsp_nhotspares; i++) if (hsp->hsp_hotspares[i] == hs->hs_record_id) { return (mdhserror(&shs->mde, MDE_HS_INUSE, shs->shs_hot_spare_pool, hs->hs_devnum)); } /* * Create a new hot spare pool record * This gives us the one extra hs slot, * because there is one slot in the * hot_spare_pool struct */ new_size = sizeof (hot_spare_pool_ond_t) + (sizeof (mddb_recid_t) * hsp->hsp_nhotspares); /* * The Friendly Name status of the new HSP should duplicate * the status of the existing one. */ if (hsp->hsp_revision & MD_FN_META_DEV) { options = MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN; } else { options = MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL; } recid = mddb_createrec(new_size, typ1, HSP_REC, options, setno); if (recid < 0) { return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE, hsp->hsp_self_id)); } new_size = sizeof (hot_spare_pool_t) + (sizeof (mddb_recid_t) * hsp->hsp_nhotspares); /* get the record addr */ new_hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, new_size, HSP_ONDSK_STR_OFF); /* copy the old record into the new one */ bcopy((caddr_t)hsp, (caddr_t)new_hsp, (size_t)((sizeof (hot_spare_pool_t) + (sizeof (mddb_recid_t) * hsp->hsp_nhotspares) - sizeof (mddb_recid_t)))); new_hsp->hsp_record_id = recid; md_rem_link(setno, hsp->hsp_self_id, &hotspares_md_ops.md_link_rw.lock, &hotspares_md_ops.md_head); rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER); new_hsp->hsp_link.ln_next = hotspares_md_ops.md_head; new_hsp->hsp_link.ln_setno = setno; new_hsp->hsp_link.ln_id = new_hsp->hsp_self_id; hotspares_md_ops.md_head = &new_hsp->hsp_link; rw_exit(&hotspares_md_ops.md_link_rw.lock); /* mark the old hsp to be deleted */ delete_hsp = 1; old_hsp = hsp; hsp = new_hsp; } if (shs->shs_size_option & MD_CRO_64BIT) { hs->hs_revision |= MD_64BIT_META_DEV; } else { hs->hs_revision &= ~MD_64BIT_META_DEV; } /* lock the db records */ recids[0] = hs->hs_record_id; recids[1] = hsp->hsp_record_id; irecid = 2; if (delete_hsp) recids[irecid++] = old_hsp->hsp_record_id; recids[irecid] = 0; /* increment the reference count */ hs->hs_refcount++; /* add the hs at the end of the hot spare pool */ hsp->hsp_hotspares[hsp->hsp_nhotspares] = hs->hs_record_id; hsp->hsp_nhotspares++; /* * NOTE: We do not commit the previous hot spare pool record. * There is no need, the link gets rebuilt at boot time. */ if (prev_hsp) prev_hsp->hsp_next = hsp; else md_set[setno].s_hsp = (void *) hsp; if (delete_hsp) old_hsp->hsp_self_id = MD_HSP_NONE; /* commit the db records */ mddb_commitrecs_wrapper(recids); if (delete_hsp) { /* delete the old hot spare pool record */ mddb_deleterec_wrapper(old_hsp->hsp_record_id); } if (hsp_created) { SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno, md_expldev(hsp->hsp_self_id)); } SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_ADD, SVM_TAG_HSP, setno, md_expldev(hsp->hsp_self_id)); return (0); }