/* * NAME: raid_hs_release * * DESCRIPTION: Release the hotspare. * * PARAMETERS: int error - indication of error on hotspare * mr_unit_t *un - raid unit * mddb_recid_t *recids - output records to commit revised hs info * int hs_index - component to release * * LOCKS: Expects Unit Writer Lock to be held across call. */ void raid_hs_release( hs_cmds_t cmd, mr_unit_t *un, mddb_recid_t *recids, int hs_index ) { mr_column_t *col; col = &un->un_column[hs_index]; /* close the hotspare device */ if (col->un_devflags & MD_RAID_DEV_ISOPEN) { md_layered_close(col->un_dev, MD_OFLG_NULL); col->un_devflags &= ~MD_RAID_DEV_ISOPEN; } /* return the hotspare to the pool */ (void) md_hot_spare_ifc(cmd, un->un_hsp_id, 0, 0, recids, &col->un_hs_key, NULL, NULL); col->un_hs_pwstart = 0; col->un_hs_devstart = 0; col->un_hs_id = (mddb_recid_t)0; col->un_hs_key = 0; }
/* * NAME: check_comp_4_hs * * DESCRIPTION: Check whether the input component has an error and can be * backed with a hot spare (RCS_ERRED state), and initiate * a resync if so. * * PARAMETERS: mr_unit_t *un - raid unit * int hs_index - component to check * * LOCKS: Expects Unit Writer Lock to be held upon entrance. Releases * the lock prior to calling raid_resync_unit, then reacquires * it before returning. */ static void check_comp_4_hs( mr_unit_t *un, int hs_index ) { mddb_recid_t recids[3]; minor_t mnum = MD_SID(un); mdi_unit_t *ui; rcs_state_t state; diskaddr_t size; int err; mr_column_t *col; md_error_t mde = mdnullerror; char devname[MD_MAX_CTDLEN]; char hs_devname[MD_MAX_CTDLEN]; set_t setno; md_dev64_t tmpdev; diskaddr_t tmpdaddr; /* initialize */ setno = MD_UN2SET(un); ui = MDI_UNIT(mnum); md_unit_readerexit(ui); (void) md_io_writerlock(ui); un = (mr_unit_t *)md_unit_writerlock(ui); col = &un->un_column[hs_index]; /* * add a hotspare for erred column only if not resyncing */ if ((!(COLUMN_STATE(un, hs_index) & RCS_ERRED)) || (raid_state_cnt(un, (RCS_ERRED | RCS_LAST_ERRED)) != 1) || (raid_state_cnt(un, RCS_RESYNC) > 0)) { goto errout; } recids[0] = 0; recids[1] = 0; /* if there is already a hotspare then just return */ if (HOTSPARED(un, hs_index) && (col->un_devstate & RCS_ERRED)) { raid_hs_release(HS_BAD, un, &recids[0], hs_index); cmn_err(CE_WARN, "md: %s: %s hotspare errored and released", md_shortname(mnum), md_devname(MD_MIN2SET(mnum), col->un_dev, NULL, 0)); col->un_dev = col->un_orig_dev; col->un_pwstart = col->un_orig_pwstart; col->un_devstart = col->un_orig_devstart; raid_commit(un, recids); SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_METADEVICE, setno, MD_SID(un)); } ASSERT(!HOTSPARED(un, hs_index)); state = col->un_devstate; size = col->un_pwstart + un->un_pwsize + (un->un_segsize * un->un_segsincolumn); again: /* quit if resync is already active */ col->un_devflags |= MD_RAID_REGEN_RESYNC; if (resync_request(mnum, hs_index, 0, NULL)) goto errout; recids[0] = 0; recids[1] = 0; tmpdev = col->un_dev; tmpdaddr = col->un_hs_pwstart; /* get a hotspare */ if (md_hot_spare_ifc(HS_GET, un->un_hsp_id, size, ((col->un_orig_pwstart >= 1) && (col->un_orig_pwstart != MD_DISKADDR_ERROR)), &col->un_hs_id, &col->un_hs_key, &tmpdev, &tmpdaddr) != 0) { col->un_dev = tmpdev; col->un_hs_pwstart = tmpdaddr; release_resync_request(mnum); raid_set_state(un, hs_index, state, 1); goto errout; } col->un_hs_pwstart = tmpdaddr; /* * record id is filled in by raid_commit, recids[0] filled in by * md_hot_spare_ifc if needed */ recids[0] = col->un_hs_id; recids[1] = 0; /* * close the device and open the hot spare. The device should * never be a hotspare here. */ if (col->un_devflags & MD_RAID_DEV_ISOPEN) { md_layered_close(col->un_orig_dev, MD_OFLG_NULL); col->un_devflags &= ~MD_RAID_DEV_ISOPEN; } /* * Try open by device id */ tmpdev = md_resolve_bydevid(mnum, tmpdev, col->un_hs_key); if (md_layered_open(mnum, &tmpdev, MD_OFLG_NULL)) { md_dev64_t hs_dev = tmpdev; /* cannot open return to orig */ raid_hs_release(HS_BAD, un, &recids[0], hs_index); release_resync_request(mnum); raid_set_state(un, hs_index, state, 1); col->un_dev = col->un_orig_dev; col->un_devstart = col->un_orig_devstart; col->un_pwstart = col->un_orig_pwstart; col->un_devflags &= ~MD_RAID_DEV_ISOPEN; raid_commit(un, recids); cmn_err(CE_WARN, "md: %s: open error of hotspare %s", md_shortname(mnum), md_devname(MD_MIN2SET(mnum), hs_dev, NULL, 0)); SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_HS, setno, MD_SID(un)); goto again; } col->un_dev = tmpdev; col->un_devflags |= MD_RAID_DEV_ISOPEN; /* * move the values into the device fields. Since in some cases * the pwstart is not zero this must be added into the start of * the hotspare to avoid over writting the label */ col->un_hs_pwstart += col->un_orig_pwstart; col->un_pwstart = col->un_hs_pwstart; col->un_hs_devstart = col->un_hs_pwstart + un->un_pwsize; col->un_devstart = col->un_hs_devstart; /* commit unit and hotspare records and release lock */ raid_commit(un, recids); md_unit_writerexit(ui); md_io_writerexit(ui); err = raid_resync_unit(mnum, &mde); /* if resync fails, transition back to erred state and reset */ if (err) { /* reaquire unit writerr lock */ un = (mr_unit_t *)md_unit_writerlock(ui); raid_set_state(un, hs_index, RCS_ERRED, 0); /* * close the hotspare and return it. Then restore the * original device back to the original state */ raid_hs_release(HS_FREE, un, &recids[0], hs_index); col->un_dev = col->un_orig_dev; col->un_devstart = col->un_orig_devstart; col->un_pwstart = col->un_orig_pwstart; raid_commit(un, recids); md_unit_writerexit(ui); un = (mr_unit_t *)md_unit_readerlock(ui); return; } setno = MD_MIN2SET(mnum); (void) md_devname(setno, col->un_orig_dev, devname, sizeof (devname)); (void) md_devname(setno, col->un_dev, hs_devname, sizeof (hs_devname)); cmn_err(CE_NOTE, "md: %s: hotspared device %s with %s", md_shortname(mnum), devname, hs_devname); SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HOTSPARED, SVM_TAG_HS, setno, MD_SID(un)); (void) md_unit_readerlock(ui); return; errout: md_unit_writerexit(ui); md_io_writerexit(ui); un = (mr_unit_t *)md_unit_readerlock(ui); }
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); }
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); }
static int stripe_open_all_devs(ms_unit_t *un, int md_oflags) { minor_t mnum = MD_SID(un); int row; int i; int c; struct ms_comp *mdcomp; int err; int cont_on_errors = (md_oflags & MD_OFLG_CONT_ERRS); int probe_err_cnt = 0; int total_comp_cnt = 0; set_t setno = MD_MIN2SET(MD_SID(un)); side_t side = mddb_getsidenum(setno); mdkey_t key; mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]); /* * For a probe call, if any component of a stripe or a concat * can be opened, it is considered to be a success. The total number * of components in a stripe are computed prior to starting a probe. * This number is then compared against the number of components * that could be be successfully opened. If none of the components * in a stripe can be opened, only then an ENXIO is returned for a * probe type open. */ for (row = 0; row < un->un_nrows; row++) { struct ms_row *mdr = &un->un_row[row]; if (md_oflags & MD_OFLG_PROBEDEV) total_comp_cnt += mdr->un_ncomp; for (i = 0, c = mdr->un_icomp; i < mdr->un_ncomp; i++) { struct ms_comp *mdc; md_dev64_t tmpdev; mdc = &mdcomp[c++]; tmpdev = mdc->un_dev; /* * Do the open by device id * Check if this comp is hotspared and * if it is then use the key for hotspare. * MN disksets don't use devids, so we better don't use * md_devid_found/md_resolve_bydevid there. Rather do, * what's done in stripe_build_incore() */ if (MD_MNSET_SETNO(setno)) { if (mdc->un_mirror.ms_hs_id != 0) { (void) md_hot_spare_ifc(HS_MKDEV, 0, 0, 0, &mdc->un_mirror.ms_hs_id, NULL, &tmpdev, NULL); } } else { key = mdc->un_mirror.ms_hs_id ? mdc->un_mirror.ms_hs_key : mdc->un_key; if ((md_getmajor(tmpdev) != md_major) && md_devid_found(setno, side, key) == 1) { tmpdev = md_resolve_bydevid(mnum, tmpdev, key); } } /* * For a submirror, we only want to open those devices * that are not errored. If the device is errored then * then there is no reason to open it and leaving it * closed allows the RCM/DR code to work so that the * errored device can be replaced. */ if ((md_oflags & MD_OFLG_PROBEDEV) || ! (mdc->un_mirror.ms_state & CS_ERRED)) { err = md_layered_open(mnum, &tmpdev, md_oflags); } else { err = ENXIO; } /* * Only set the un_dev if the tmpdev != NODEV64. If * it is NODEV64 then the md_layered_open() will have * failed in some manner. */ if (tmpdev != NODEV64) mdc->un_dev = tmpdev; if (err) { if (!cont_on_errors) { stripe_close_all_devs(un, md_oflags); return (ENXIO); } if (md_oflags & MD_OFLG_PROBEDEV) probe_err_cnt++; } else { if (md_oflags & MD_OFLG_PROBEDEV) { mdc->un_mirror.ms_flags |= MDM_S_PROBEOPEN; } else mdc->un_mirror.ms_flags |= MDM_S_ISOPEN; } } } /* If every component in a stripe could not be opened fail */ if ((md_oflags & MD_OFLG_PROBEDEV) && (probe_err_cnt == total_comp_cnt)) return (ENXIO); else return (0); }