static void imp_hotsparepool( set_t setno, mddb_recid_t recid ) { hot_spare_pool_ond_t *hsp_ond; mddb_recid_t *hsp_recid, *hs_recid; int i; uint_t *hsp_selfid; mddb_setrecprivate(recid, MD_PRV_GOTIT); hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid); hsp_recid = &(hsp_ond->hsp_record_id); hsp_selfid = &(hsp_ond->hsp_self_id); /* * Fixup the pool and hotspares */ *hsp_recid = MAKERECID(setno, DBID(*hsp_recid)); *hsp_selfid = MAKERECID(setno, DBID(*hsp_selfid)); for (i = 0; i < hsp_ond->hsp_nhotspares; i++) { hs_recid = &(hsp_ond->hsp_hotspares[i]); *hs_recid = MAKERECID(setno, DBID(*hs_recid)); } }
static void load_hotsparepool(set_t setno, mddb_recid_t recid) { hot_spare_pool_t *hsp; hot_spare_pool_ond_t *hsp_ond; size_t hsp_icsize; mddb_setrecprivate(recid, MD_PRV_GOTIT); hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid); ASSERT(hsp_ond != NULL); if (hsp_ond->hsp_self_id == MD_HSP_NONE) { mddb_setrecprivate(recid, MD_PRV_PENDDEL); return; } hsp_icsize = HSP_ONDSK_STR_OFF + mddb_getrecsize(recid); hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, hsp_icsize, HSP_ONDSK_STR_OFF); hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp; md_set[setno].s_hsp = (void *) hsp; 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); }
static void imp_hotspare( set_t setno, mddb_recid_t recid ) { mddb_de_ic_t *dep; mddb_rb32_t *rbp; hot_spare_t *hs64; hot_spare32_od_t *hs32; mddb_recid_t *hs_recid; mddb_setrecprivate(recid, MD_PRV_GOTIT); dep = mddb_getrecdep(recid); rbp = dep->de_rb; switch (rbp->rb_revision) { case MDDB_REV_RB: case MDDB_REV_RBFN: /* * 32 bit hotspare */ hs32 = (hot_spare32_od_t *)mddb_getrecaddr(recid); hs_recid = &(hs32->hs_record_id); break; case MDDB_REV_RB64: case MDDB_REV_RB64FN: hs64 = (hot_spare_t *)mddb_getrecaddr(recid); hs_recid = &(hs64->hs_record_id); break; } /* * Fixup the setno */ *hs_recid = MAKERECID(setno, DBID(*hs_recid)); }
static int stripe_grow(void *d, int mode, IOLOCK *lockp) { minor_t mnum; ms_unit_t *un, *new_un; mdi_unit_t *ui; minor_t *par = NULL; IOLOCK *plock = NULL; ms_comp_t *mdcomp, *new_comp; int row, i, c; mddb_recid_t ms_recid; mddb_recid_t old_vtoc = 0; mddb_recid_t *recids; md_create_rec_option_t options; mddb_type_t typ1; int err; int64_t tb, atb; uint_t nr, oc; int opened; int rval = 0; set_t setno; md_error_t *mdep; int npar; int rid; int num_recs; u_longlong_t rev; md_grow_params_t *mgp = d; mnum = mgp->mnum; mdep = &mgp->mde; setno = MD_MIN2SET(mnum); npar = mgp->npar; 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)); ui = MDI_UNIT(mnum); if (ui == NULL) { return (mdmderror(mdep, MDE_UNIT_NOT_SETUP, mnum)); } if (npar >= 1) { ASSERT((minor_t *)(uintptr_t)mgp->par != NULL); par = kmem_alloc(npar * sizeof (*par), KM_SLEEP); plock = kmem_alloc(npar * sizeof (*plock), KM_SLEEP); if (ddi_copyin((caddr_t)(uintptr_t)mgp->par, (caddr_t)par, (npar * sizeof (*par)), mode) != 0) { kmem_free(par, npar * sizeof (*par)); kmem_free(plock, npar * sizeof (*plock)); return (EFAULT); } } /* * we grab unit reader/writer first, then parent locks, * then our own. * we expect parent units to be sorted to avoid deadlock */ rw_enter(&md_unit_array_rw.lock, RW_WRITER); for (i = 0; i < npar; ++i) { (void) md_ioctl_writerlock(&plock[i], MDI_UNIT(par[i])); } un = (ms_unit_t *)md_ioctl_writerlock(lockp, ui); if (un->un_nrows != mgp->nrows) { rval = EINVAL; goto out; } typ1 = (mddb_type_t)md_getshared_key(setno, stripe_md_ops.md_driver.md_drivername); /* * Preserve the friendly name nature of growing device. */ options = MD_CRO_STRIPE; if (un->c.un_revision & MD_FN_META_DEV) options |= MD_CRO_FN; if (mgp->options & MD_CRO_64BIT) { #if defined(_ILP32) rval = mdmderror(mdep, MDE_UNIT_TOO_LARGE, mnum); goto out; #else ms_recid = mddb_createrec((size_t)mgp->size, typ1, 0, MD_CRO_64BIT | options, setno); #endif } else { ms_recid = mddb_createrec((size_t)mgp->size, typ1, 0, MD_CRO_32BIT | options, setno); } if (ms_recid < 0) { rval = mddbstatus2error(mdep, (int)ms_recid, mnum, setno); goto out; } /* get the address of the new unit */ new_un = (ms_unit_t *)mddb_getrecaddr(ms_recid); /* * It is okay that we muck with the new unit here, * since no one else will know about the unit struct * until we commit it. If we crash, the record will * be automatically purged, since we haven't * committed it yet and the old unit struct will be found. */ /* copy in the user's unit struct */ err = ddi_copyin((caddr_t)(uintptr_t)mgp->mdp, (caddr_t)new_un, (size_t)mgp->size, mode); if (err) { mddb_deleterec_wrapper(ms_recid); rval = EFAULT; goto out; } if (options & MD_CRO_FN) new_un->c.un_revision |= MD_FN_META_DEV; /* * allocate the real recids array. since we may have to * commit underlying metadevice records, we need an * array of size: total number of new components being * attached + 2 (one for the stripe itself, one for the * end marker). */ num_recs = 2; rid = 0; for (row = 0; row < new_un->un_nrows; row++) { struct ms_row *mdr = &new_un->un_row[row]; num_recs += mdr->un_ncomp; } recids = kmem_alloc(num_recs * sizeof (mddb_recid_t), KM_SLEEP); recids[rid++] = ms_recid; /* * Save a few of the new unit structs fields. * Before they get clobbered. */ tb = new_un->c.un_total_blocks; atb = new_un->c.un_actual_tb; nr = new_un->un_nrows; oc = new_un->un_ocomp; rev = new_un->c.un_revision; /* * Copy the old unit struct (static stuff) * into new unit struct */ bcopy((caddr_t)un, (caddr_t)new_un, sizeof (ms_unit_t) + ((nr - 2) * (sizeof (struct ms_row)))); /* * Restore the saved stuff. */ new_un->c.un_total_blocks = tb; md_nblocks_set(mnum, new_un->c.un_total_blocks); new_un->c.un_actual_tb = atb; new_un->un_nrows = nr; new_un->un_ocomp = oc; new_un->c.un_revision = rev; new_un->c.un_record_id = ms_recid; new_un->c.un_size = mgp->size; /* All 64 bit metadevices only support EFI labels. */ if (mgp->options & MD_CRO_64BIT) { new_un->c.un_flag |= MD_EFILABEL; /* * If the device was previously smaller than a terabyte, * and had a vtoc record attached to it, we remove the * vtoc record, because the layout has changed completely. */ if (((un->c.un_revision & MD_64BIT_META_DEV) == 0) && (un->c.un_vtoc_id != 0)) { old_vtoc = un->c.un_vtoc_id; new_un->c.un_vtoc_id = md_vtoc_to_efi_record(old_vtoc, setno); } } /* * Copy the old component structs into the new unit struct. */ mdcomp = (ms_comp_t *)((void *)&((char *)un)[un->un_ocomp]); new_comp = (ms_comp_t *)((void *)&((char *)new_un)[new_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++, c++) { bcopy((caddr_t)&mdcomp[c], (caddr_t)&new_comp[c], sizeof (ms_comp_t)); } } opened = md_unit_isopen(ui); /* * Set parent on metadevices being added. * Open the new devices being added. * NOTE: currently soft partitions are the only metadevices * which can appear within a stripe. */ for (row = un->un_nrows; row < new_un->un_nrows; row++) { struct ms_row *mdr = &new_un->un_row[row]; for (i = 0, c = mdr->un_icomp; i < mdr->un_ncomp; i++) { struct ms_comp *mdc = &new_comp[c++]; md_dev64_t comp_dev; md_unit_t *comp_un; comp_dev = mdc->un_dev; /* set parent on any metadevices */ if (md_getmajor(comp_dev) == md_major) { comp_un = MD_UNIT(md_getminor(comp_dev)); recids[rid++] = MD_RECID(comp_un); md_set_parent(comp_dev, MD_SID(new_un)); } if (opened) { md_dev64_t tmpdev = mdc->un_dev; /* * Open by device id * Check if this comp is hotspared and * if it is then use the key for hotspare */ tmpdev = md_resolve_bydevid(mnum, tmpdev, mdc->un_mirror.ms_hs_id ? mdc->un_mirror.ms_hs_key : mdc->un_key); (void) md_layered_open(mnum, &tmpdev, MD_OFLG_NULL); mdc->un_dev = tmpdev; mdc->un_mirror.ms_flags |= MDM_S_ISOPEN; } } } /* set end marker */ recids[rid] = 0; /* commit new unit struct */ mddb_commitrecs_wrapper(recids); /* delete old unit struct */ mddb_deleterec_wrapper(un->c.un_record_id); /* place new unit in in-core array */ md_nblocks_set(mnum, new_un->c.un_total_blocks); MD_UNIT(mnum) = new_un; /* * If old_vtoc has a non zero value, we know: * - This unit crossed the border from smaller to larger one TB * - There was a vtoc record for the unit, * - This vtoc record is no longer needed, because * a new efi record has been created for this un. */ if (old_vtoc != 0) { mddb_deleterec_wrapper(old_vtoc); } /* free recids array */ kmem_free(recids, num_recs * sizeof (mddb_recid_t)); SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_GROW, SVM_TAG_METADEVICE, MD_UN2SET(new_un), MD_SID(new_un)); /* release locks, return success */ out: for (i = npar - 1; (i >= 0); --i) md_ioctl_writerexit(&plock[i]); rw_exit(&md_unit_array_rw.lock); if (plock != NULL) kmem_free(plock, npar * sizeof (*plock)); if (par != NULL) kmem_free(par, npar * sizeof (*par)); return (rval); }
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 void load_hotspare(set_t setno, mddb_recid_t recid) { hot_spare_t *hs; mddb_de_ic_t *dep; mddb_rb32_t *rbp; size_t newreqsize; hot_spare_t *b_hs; hot_spare32_od_t *s_hs; mddb_setrecprivate(recid, MD_PRV_GOTIT); dep = mddb_getrecdep(recid); dep->de_flags = MDDB_F_HOTSPARE; rbp = dep->de_rb; switch (rbp->rb_revision) { case MDDB_REV_RB: case MDDB_REV_RBFN: /* * Needs to convert to internal 64 bit */ s_hs = (hot_spare32_od_t *)mddb_getrecaddr(recid); newreqsize = sizeof (hot_spare_t); b_hs = (hot_spare_t *)kmem_zalloc(newreqsize, KM_SLEEP); hs_convert((caddr_t)s_hs, (caddr_t)b_hs, SMALL_2_BIG); kmem_free(s_hs, dep->de_reqsize); dep->de_rb_userdata = b_hs; dep->de_reqsize = newreqsize; hs = b_hs; break; case MDDB_REV_RB64: case MDDB_REV_RB64FN: hs = (hot_spare_t *)mddb_getrecaddr_resize (recid, sizeof (*hs), 0); break; } MDDB_NOTE_FN(rbp->rb_revision, hs->hs_revision); #if defined(_ILP32) if (hs->hs_revision & MD_64BIT_META_DEV) { char devname[MD_MAX_CTDLEN]; set_hot_spare_state(hs, HSS_BROKEN); (void) md_devname(setno, hs->hs_devnum, devname, sizeof (devname)); cmn_err(CE_NOTE, "%s is unavailable because 64 bit hotspares " "are not accessible on a 32 bit kernel\n", devname); } #endif ASSERT(hs != NULL); if (hs->hs_refcount == 0) { mddb_setrecprivate(recid, MD_PRV_PENDDEL); return; } hs->hs_next = (hot_spare_t *)md_set[setno].s_hs; md_set[setno].s_hs = (void *)hs; hs->hs_isopen = 0; hs->hs_devnum = md_getdevnum(setno, mddb_getsidenum(setno), hs->hs_key, MD_NOTRUST_DEVT); }