static int mdopen(dev_t dev, int flag, int fmt, struct lwp *l) { int unit; struct md_softc *sc; unit = MD_UNIT(dev); sc = device_lookup_private(&md_cd, unit); if (sc == NULL) return ENXIO; /* * The raw partition is used for ioctl to configure. */ if (DISKPART(dev) == RAW_PART) return 0; #ifdef MEMORY_DISK_HOOKS /* Call the open hook to allow loading the device. */ md_open_hook(unit, &sc->sc_md); #endif /* * This is a normal, "slave" device, so * enforce initialized. */ if (sc->sc_type == MD_UNCONFIGURED) return ENXIO; return 0; }
/* ARGSUSED */ int resync_request( minor_t mnum, int column_index, size_t copysize, md_error_t *mde ) { mr_unit_t *un; un = MD_UNIT(mnum); ASSERT(un != NULL); /* if resync or grow not already active, set resync active for unit */ if (! (un->un_column[column_index].un_devflags & MD_RAID_RESYNC) && ((un->c.un_status & MD_UN_RESYNC_ACTIVE) || (un->c.un_status & MD_UN_GROW_PENDING) || (un->un_column[column_index].un_devstate & RCS_RESYNC))) { if (mde) return (mdmderror(mde, MDE_GROW_DELAYED, mnum)); return (1); } if (un->un_column[column_index].un_devstate & (RCS_ERRED | RCS_LAST_ERRED)) un->un_column[column_index].un_devflags |= MD_RAID_DEV_ERRED; else un->un_column[column_index].un_devflags &= ~MD_RAID_DEV_ERRED; un->c.un_status |= MD_UN_RESYNC_ACTIVE; un->un_resync_index = column_index; un->un_resync_line_index = 0; raid_set_state(un, column_index, RCS_RESYNC, 0); return (0); }
static int stripe_reset(md_i_reset_t *mirp) { minor_t mnum = mirp->mnum; ms_unit_t *un; mdi_unit_t *ui; set_t setno = MD_MIN2SET(mnum); mdclrerror(&mirp->mde); if ((setno >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits)) return (mdmderror(&mirp->mde, MDE_INVAL_UNIT, mnum)); if (md_get_setstatus(setno) & MD_SET_STALE) return (mdmddberror(&mirp->mde, MDE_DB_STALE, mnum, setno)); un = MD_UNIT(mnum); if (un == NULL) { return (mdmderror(&mirp->mde, MDE_UNIT_NOT_SETUP, mnum)); } /* This prevents new opens */ rw_enter(&md_unit_array_rw.lock, RW_WRITER); if (MD_HAS_PARENT(un->c.un_parent)) { rw_exit(&md_unit_array_rw.lock); return (mdmderror(&mirp->mde, MDE_IN_USE, mnum)); } /* single thread */ ui = MDI_UNIT(mnum); un = md_unit_openclose_enter(ui); if (md_unit_isopen(ui)) { md_unit_openclose_exit(ui); rw_exit(&md_unit_array_rw.lock); return (mdmderror(&mirp->mde, MDE_IS_OPEN, mnum)); } md_unit_openclose_exit(ui); reset_stripe(un, mnum, 1); /* * Update unit availability */ md_set[setno].s_un_avail++; /* * If MN set, reset s_un_next so all nodes can have * the same view of the next available slot when * nodes are -w and -j */ if (MD_MNSET_SETNO(setno)) { (void) md_upd_set_unnext(setno, MD_MIN2UNIT(mnum)); } rw_exit(&md_unit_array_rw.lock); return (0); }
/* * Handle I/O requests, either directly, or * by passing them to the server process. */ static void mdstrategy(struct buf *bp) { struct md_softc *sc; void * addr; size_t off, xfer; sc = device_lookup_private(&md_cd, MD_UNIT(bp->b_dev)); if (sc->sc_type == MD_UNCONFIGURED) { bp->b_error = ENXIO; goto done; } switch (sc->sc_type) { #if MEMORY_DISK_SERVER case MD_UMEM_SERVER: /* Just add this job to the server's queue. */ BUFQ_PUT(sc->sc_buflist, bp); wakeup((void *)sc); /* see md_server_loop() */ /* no biodone in this case */ return; #endif /* MEMORY_DISK_SERVER */ case MD_KMEM_FIXED: case MD_KMEM_ALLOCATED: /* These are in kernel space. Access directly. */ bp->b_resid = bp->b_bcount; off = (bp->b_blkno << DEV_BSHIFT); if (off >= sc->sc_size) { if (bp->b_flags & B_READ) break; /* EOF */ goto set_eio; } xfer = bp->b_resid; if (xfer > (sc->sc_size - off)) xfer = (sc->sc_size - off); addr = (char *)sc->sc_addr + off; if (bp->b_flags & B_READ) memcpy(bp->b_data, addr, xfer); else memcpy(addr, bp->b_data, xfer); bp->b_resid -= xfer; break; default: bp->b_resid = bp->b_bcount; set_eio: bp->b_error = EIO; break; } done: biodone(bp); }
static int mdwrite(dev_t dev, struct uio *uio, int flags) { struct md_softc *sc; sc = device_lookup_private(&md_cd, MD_UNIT(dev)); if (sc->sc_type == MD_UNCONFIGURED) return ENXIO; return (physio(mdstrategy, NULL, dev, B_WRITE, minphys, uio)); }
static int mdsize(dev_t dev) { struct md_softc *sc; sc = device_lookup_private(&md_cd, MD_UNIT(dev)); if (sc == NULL) return 0; if (sc->sc_type == MD_UNCONFIGURED) return 0; return (sc->sc_size >> DEV_BSHIFT); }
/* * NAME: release_resync_request * * DESCRIPTION: Release resync active flag and reset unit values accordingly. * * PARAMETERS: minor_t mnum - minor number identity of metadevice * * LOCKS: Expects Unit Writer Lock to be held across call. */ void release_resync_request( minor_t mnum ) { mr_unit_t *un; un = MD_UNIT(mnum); ASSERT(un != NULL); un->c.un_status &= ~MD_UN_RESYNC_ACTIVE; un->un_column[un->un_resync_index].un_devflags &= ~MD_RAID_RESYNC; un->un_column[un->un_resync_index].un_devflags &= ~MD_RAID_RESYNC_ERRED; un->un_column[un->un_resync_index].un_devflags &= ~(MD_RAID_COPY_RESYNC | MD_RAID_REGEN_RESYNC); un->un_resync_line_index = 0; un->un_resync_index = NOCOLUMN; }
/* * NAME: raid_resync_unit * * DESCRIPTION: RAID metadevice specific resync routine. * Open the unit and start resync_unit as a separate thread. * * PARAMETERS: minor_t mnum - minor number identity of metadevice * md_error_t *ep - output error parameter * * RETURN: On error return 1 or set ep to nonzero, otherwise return 0. * * LOCKS: Acquires and releases Unit Writer Lock. */ int raid_resync_unit( minor_t mnum, md_error_t *ep ) { mdi_unit_t *ui; set_t setno = MD_MIN2SET(mnum); mr_unit_t *un; ui = MDI_UNIT(mnum); un = MD_UNIT(mnum); if (md_get_setstatus(setno) & MD_SET_STALE) return (mdmddberror(ep, MDE_DB_STALE, mnum, setno)); ASSERT(un->un_column[un->un_resync_index].un_devflags & (MD_RAID_COPY_RESYNC | MD_RAID_REGEN_RESYNC)); /* Don't start a resync if the device is not available */ if ((ui == NULL) || (ui->ui_tstate & MD_DEV_ERRORED)) { return (mdmderror(ep, MDE_RAID_OPEN_FAILURE, mnum)); } if (raid_internal_open(mnum, FREAD | FWRITE, OTYP_LYR, 0)) { (void) md_unit_writerlock(ui); release_resync_request(mnum); md_unit_writerexit(ui); SE_NOTIFY(EC_SVM_STATE, ESC_SVM_OPEN_FAIL, SVM_TAG_METADEVICE, setno, MD_SID(un)); return (mdmderror(ep, MDE_RAID_OPEN_FAILURE, mnum)); } /* start resync_unit thread */ (void) thread_create(NULL, 0, resync_unit, (void *)(uintptr_t)mnum, 0, &p0, TS_RUN, minclsyspri); return (0); }
static int mdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct md_softc *sc; struct md_conf *umd; sc = device_lookup_private(&md_cd, MD_UNIT(dev)); /* If this is not the raw partition, punt! */ if (DISKPART(dev) != RAW_PART) return ENOTTY; umd = (struct md_conf *)data; switch (cmd) { case MD_GETCONF: *umd = sc->sc_md; return 0; case MD_SETCONF: /* Can only set it once. */ if (sc->sc_type != MD_UNCONFIGURED) break; switch (umd->md_type) { case MD_KMEM_ALLOCATED: return md_ioctl_kalloc(sc, umd, l); #if MEMORY_DISK_SERVER case MD_UMEM_SERVER: return md_ioctl_server(sc, umd, l); #endif /* MEMORY_DISK_SERVER */ default: break; } break; } return EINVAL; }
static int stripe_replace(replace_params_t *params) { minor_t mnum = params->mnum; ms_unit_t *un; mddb_recid_t recids[6]; ms_new_dev_t nd; ms_cd_info_t cd; int ci; int cmpcnt; void *repl_data; md_dev64_t fake_devt; void (*repl_done)(); mdclrerror(¶ms->mde); un = (ms_unit_t *)MD_UNIT(mnum); if (MD_STATUS(un) & MD_UN_RESYNC_ACTIVE) { return (mdmderror(¶ms->mde, MDE_RESYNC_ACTIVE, mnum)); } nd.nd_dev = params->new_dev; nd.nd_key = params->new_key; nd.nd_nblks = params->number_blks; nd.nd_start_blk = params->start_blk; nd.nd_labeled = params->has_label; nd.nd_hs_id = 0; /* * stripe_component_count and stripe_get_dev only care about the * minor number associated with the first argument which is a * md_dev64_t * * The comments section for these two routines have been updated * to indicate that this routine calls with fake major numbers. */ fake_devt = md_makedevice(0, mnum); cmpcnt = stripe_component_count(fake_devt, NULL); for (ci = 0; ci < cmpcnt; ci++) { (void) stripe_get_dev(fake_devt, NULL, ci, &cd); if ((cd.cd_dev == params->old_dev) || (cd.cd_orig_dev == params->old_dev)) break; } if (ci == cmpcnt) { return (EINVAL); } /* In case of a dryrun we're done here */ if (params->options & MDIOCTL_DRYRUN) { return (0); } (void) stripe_replace_dev(fake_devt, 0, ci, &nd, recids, 6, &repl_done, &repl_data); mddb_commitrecs_wrapper(recids); (*repl_done)(fake_devt, repl_data); SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REPLACE, SVM_TAG_METADEVICE, MD_UN2SET(un), MD_SID(un)); return (0); }
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); }
/* * The parameters of md_stripe_ioctl are defined by the ddi and so * dev is of type dev_t and not md_dev64_t */ int md_stripe_ioctl(dev_t dev, int cmd, void *data, int mode, IOLOCK *lockp) { minor_t mnum = getminor(dev); ms_unit_t *un; int err = 0; /* handle admin ioctls */ if (mnum == MD_ADM_MINOR) return (stripe_admin_ioctl(cmd, data, mode, lockp)); /* check unit */ if ((MD_MIN2SET(mnum) >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits) || ((un = MD_UNIT(mnum)) == NULL)) return (ENXIO); /* is this a supported ioctl? */ err = md_check_ioctl_against_unit(cmd, un->c); if (err != 0) { return (err); } /* handle ioctl */ switch (cmd) { case DKIOCINFO: { struct dk_cinfo *p; if (! (mode & FREAD)) return (EACCES); p = kmem_alloc(sizeof (*p), KM_SLEEP); get_info(p, mnum); if (ddi_copyout((caddr_t)p, data, sizeof (*p), mode) != 0) err = EFAULT; kmem_free(p, sizeof (*p)); return (err); } case DKIOCGMEDIAINFO: { struct dk_minfo p; if (! (mode & FREAD)) return (EACCES); get_minfo(&p, mnum); if (ddi_copyout(&p, data, sizeof (struct dk_minfo), mode) != 0) err = EFAULT; return (err); } case DKIOCGGEOM: { struct dk_geom *p; if (! (mode & FREAD)) return (EACCES); p = kmem_alloc(sizeof (*p), KM_SLEEP); if ((err = stripe_get_geom(un, p)) == 0) { if (ddi_copyout((caddr_t)p, data, sizeof (*p), mode) != 0) err = EFAULT; } kmem_free(p, sizeof (*p)); return (err); } case DKIOCGVTOC: { struct vtoc *vtoc; if (! (mode & FREAD)) return (EACCES); vtoc = kmem_zalloc(sizeof (*vtoc), KM_SLEEP); if ((err = stripe_get_vtoc(un, vtoc)) != 0) { kmem_free(vtoc, sizeof (*vtoc)); return (err); } if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) { if (ddi_copyout(vtoc, data, sizeof (*vtoc), mode)) err = EFAULT; } #ifdef _SYSCALL32 else { struct vtoc32 *vtoc32; vtoc32 = kmem_zalloc(sizeof (*vtoc32), KM_SLEEP); vtoctovtoc32((*vtoc), (*vtoc32)); if (ddi_copyout(vtoc32, data, sizeof (*vtoc32), mode)) err = EFAULT; kmem_free(vtoc32, sizeof (*vtoc32)); } #endif /* _SYSCALL32 */ kmem_free(vtoc, sizeof (*vtoc)); return (err); } case DKIOCSVTOC: { struct vtoc *vtoc; if (! (mode & FWRITE)) return (EACCES); vtoc = kmem_zalloc(sizeof (*vtoc), KM_SLEEP); if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) { if (ddi_copyin(data, vtoc, sizeof (*vtoc), mode)) { err = EFAULT; } } #ifdef _SYSCALL32 else { struct vtoc32 *vtoc32; vtoc32 = kmem_zalloc(sizeof (*vtoc32), KM_SLEEP); if (ddi_copyin(data, vtoc32, sizeof (*vtoc32), mode)) { err = EFAULT; } else { vtoc32tovtoc((*vtoc32), (*vtoc)); } kmem_free(vtoc32, sizeof (*vtoc32)); } #endif /* _SYSCALL32 */ if (err == 0) { err = stripe_set_vtoc(un, vtoc); } kmem_free(vtoc, sizeof (*vtoc)); return (err); } case DKIOCGEXTVTOC: { struct extvtoc *extvtoc; if (! (mode & FREAD)) return (EACCES); extvtoc = kmem_zalloc(sizeof (*extvtoc), KM_SLEEP); if ((err = stripe_get_extvtoc(un, extvtoc)) != 0) { kmem_free(extvtoc, sizeof (*extvtoc)); return (err); } if (ddi_copyout(extvtoc, data, sizeof (*extvtoc), mode)) err = EFAULT; kmem_free(extvtoc, sizeof (*extvtoc)); return (err); } case DKIOCSEXTVTOC: { struct extvtoc *extvtoc; if (! (mode & FWRITE)) return (EACCES); extvtoc = kmem_zalloc(sizeof (*extvtoc), KM_SLEEP); if (ddi_copyin(data, extvtoc, sizeof (*extvtoc), mode)) { err = EFAULT; } if (err == 0) { err = stripe_set_extvtoc(un, extvtoc); } kmem_free(extvtoc, sizeof (*extvtoc)); return (err); } case DKIOCGAPART: { struct dk_map dmp; if ((err = stripe_get_cgapart(un, &dmp)) != 0) { return (err); } if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) { if (ddi_copyout((caddr_t)&dmp, data, sizeof (dmp), mode) != 0) err = EFAULT; } #ifdef _SYSCALL32 else { struct dk_map32 dmp32; dmp32.dkl_cylno = dmp.dkl_cylno; dmp32.dkl_nblk = dmp.dkl_nblk; if (ddi_copyout((caddr_t)&dmp32, data, sizeof (dmp32), mode) != 0) err = EFAULT; } #endif /* _SYSCALL32 */ return (err); } case DKIOCGETEFI: { /* * This one can be done centralized, * no need to put in the same code for all types of metadevices */ return (md_dkiocgetefi(mnum, data, mode)); } case DKIOCSETEFI: { /* * This one can be done centralized, * no need to put in the same code for all types of metadevices */ return (md_dkiocsetefi(mnum, data, mode)); } case DKIOCPARTITION: { return (md_dkiocpartition(mnum, data, mode)); } default: return (ENOTTY); } }
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)); }
int stripe_build_incore(void *p, int snarfing) { ms_unit_t *un = (ms_unit_t *)p; struct ms_comp *mdcomp; minor_t mnum; int row; int i; int c; int ncomps; mnum = MD_SID(un); if (MD_UNIT(mnum) != NULL) return (0); MD_STATUS(un) = 0; /* * Reset all the is_open flags, these are probably set * cause they just came out of the database. */ mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]); ncomps = 0; for (row = 0; row < un->un_nrows; row++) { struct ms_row *mdr = &un->un_row[row]; ncomps += mdr->un_ncomp; } 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++) { struct ms_comp *mdc; set_t setno; md_dev64_t tmpdev; mdc = &mdcomp[c++]; mdc->un_mirror.ms_flags &= ~(MDM_S_ISOPEN | MDM_S_IOERR | MDM_S_RS_TRIED); if (!snarfing) continue; setno = MD_MIN2SET(mnum); tmpdev = md_getdevnum(setno, mddb_getsidenum(setno), mdc->un_key, MD_NOTRUST_DEVT); mdc->un_dev = tmpdev; /* * Check for hotspares. If the hotspares haven't been * snarfed yet, stripe_open_all_devs() will do the * remapping of the dev's later. */ if (mdc->un_mirror.ms_hs_id != 0) { mdc->un_mirror.ms_orig_dev = mdc->un_dev; (void) md_hot_spare_ifc(HS_MKDEV, 0, 0, 0, &mdc->un_mirror.ms_hs_id, NULL, &tmpdev, NULL); mdc->un_dev = tmpdev; } } } /* place various information in the in-core data structures */ md_nblocks_set(mnum, un->c.un_total_blocks); MD_UNIT(mnum) = un; return (0); }