static int get_hs( get_hs_params_t *ghs ) { hot_spare_t *hs; set_t setno = ghs->md_driver.md_setno; mdclrerror(&ghs->mde); /* Scan the hot spare list for the hs */ hs = (hot_spare_t *)md_set[setno].s_hs; while (hs) { if (hs->hs_key == ghs->ghs_key) { break; } hs = hs->hs_next; } if (hs == NULL) { return (mddeverror(&ghs->mde, MDE_INVAL_HS, ghs->ghs_devnum)); } ghs->ghs_start_blk = hs->hs_start_blk; ghs->ghs_number_blks = hs->hs_number_blks; ghs->ghs_state = hs->hs_state; ghs->ghs_timestamp = hs->hs_timestamp; ghs->ghs_revision = hs->hs_revision; return (0); }
/* * check to see if a device is in a metadevice */ int meta_check_inmeta( mdsetname_t *sp, mdname_t *np, mdchkopts_t options, diskaddr_t slblk, diskaddr_t nblks, md_error_t *ep ) { uint_t partno; /* see if replica slice is ok, only applies to disks in sets */ if (! (options & MDCHK_ALLOW_REPSLICE) && ! metaislocalset(sp)) { uint_t rep_slice; if (metagetvtoc(np, FALSE, &partno, ep) == NULL) return (-1); if (meta_replicaslice(np->drivenamep, &rep_slice, ep) != 0) return (-1); if (partno == rep_slice) return (mddeverror(ep, MDE_REPCOMP_INVAL, np->dev, np->cname)); } /* check for databases */ if (meta_check_inreplica(sp, np, slblk, nblks, ep) != 0) { if (mdisuseerror(ep, MDE_ALREADY)) { if (options & MDCHK_ALLOW_MDDB) { mdclrerror(ep); } else { return (mddeverror(ep, MDE_HAS_MDDB, np->dev, np->cname)); } } else { return (-1); } } /* check metadevices */ if (meta_check_instripe(sp, np, slblk, nblks, ep) != 0) return (-1); if (meta_check_inmirror(sp, np, slblk, nblks, ep) != 0) return (-1); if (meta_check_intrans(sp, np, options, slblk, nblks, ep) != 0) return (-1); if (meta_check_insp(sp, np, slblk, nblks, ep) != 0) return (-1); if (! (options & MDCHK_ALLOW_HS)) { if (meta_check_inhsp(sp, np, slblk, nblks, ep) != 0) return (-1); } if (meta_check_inraid(sp, np, slblk, nblks, ep) != 0) return (-1); /* return success */ return (0); }
/* * check to see if a device is in its set */ int meta_check_inset( mdsetname_t *sp, mdname_t *np, md_error_t *ep ) { mdsetname_t *npsp; int bypass_daemon = FALSE; /* check devices set */ if (metaislocalset(sp)) bypass_daemon = TRUE; if ((npsp = metagetset(np, bypass_daemon, ep)) == NULL) { if ((! metaismeta(np)) && (metaislocalset(sp)) && (mdismddberror(ep, MDE_DB_NODB))) { mdclrerror(ep); npsp = sp; } else { return (-1); } } /* check set */ if (metaissameset(sp, npsp)) return (0); /* return appropriate error */ if (metaislocalset(sp)) return (mddeverror(ep, MDE_IN_SHARED_SET, np->dev, np->cname)); else return (mddeverror(ep, MDE_NOT_IN_SET, np->dev, np->cname)); }
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); }
/* * Is a file system currently mounted on this disk drive? */ int meta_check_drivemounted( mdsetname_t *sp, mddrivename_t *dnp, md_error_t *ep ) { FILE *mfp; struct mnttab m; int rval = 0; char mountp[MNT_LINE_MAX]; char mnt_special[MNT_LINE_MAX]; /* should have a set */ assert(sp != NULL); /* look in mnttab */ if ((mfp = open_mnttab()) == NULL) return (mdsyserror(ep, errno, MNTTAB)); while ((getmntent(mfp, &m) == 0) && (rval == 0)) { char **fstype = skip_these_mntents; int skipit = 0; mdname_t *mnp; if ((m.mnt_special == NULL) || (m.mnt_mountp == NULL)) continue; if (m.mnt_mountp[0] != '/') continue; while (*fstype != NULL) if (strcmp(m.mnt_fstype, *fstype++) == 0) { skipit++; break; } if (skipit == 1) continue; (void) strcpy(mountp, m.mnt_mountp); (void) strcpy(mnt_special, m.mnt_special); if ((mnp = metaname(&sp, mnt_special, LOGICAL_DEVICE, ep)) == NULL) { mdclrerror(ep); continue; } if (strcmp(dnp->cname, mnp->drivenamep->cname) == 0) { rval = mduseerror(ep, MDE_IS_MOUNTED, NODEV64, mountp, dnp->cname); } } /* return success */ return (rval); }
int meta_check_driveinset(mdsetname_t *sp, mddrivename_t *dn, md_error_t *ep) { set_t setno; set_t max_sets; if ((max_sets = get_max_sets(ep)) == 0) return (-1); for (setno = 1; setno < max_sets; setno++) { mdsetname_t *sp1; int is_it; if (setno == sp->setno) continue; if ((sp1 = metasetnosetname(setno, ep)) == NULL) { if (mdismddberror(ep, MDE_DB_NODB)) { mdclrerror(ep); return (0); } if (mdiserror(ep, MDE_NO_SET)) { mdclrerror(ep); continue; } return (-1); } metaflushsetname(sp1); if ((is_it = meta_is_drive_in_thisset(sp1, dn, FALSE, ep)) == -1) return (-1); if (is_it) return (mddserror(ep, MDE_DS_DRIVEINSET, sp->setno, sp1->setname, dn->cname, sp->setname)); } return (0); }
void create_diskset_links() { int max_sets; int i; md_error_t error = mdnullerror; /* * Resolve the function pointers for libsds_sc so that we can * snarf the set records. */ (void) sdssc_bind_library(); (void) init_metalib(); if ((max_sets = get_max_sets(&error)) == 0) { debug_printf("create_diskset_links(): get_max_sets failed\n"); mdclrerror(&error); return; } for (i = 1; i < max_sets; i++) { md_set_record *sr; char setname[MAXPATHLEN]; char setnum[MAXPATHLEN]; if ((sr = metad_getsetbynum(i, &error)) == NULL) { mdclrerror(&error); continue; } (void) snprintf(setname, MAXPATHLEN, "/dev/md/%s", sr->sr_setname); (void) snprintf(setnum, MAXPATHLEN, "shared/%d", i); /* * Ignore failures to create the symlink. This could * happen because suninstall is restartable so the * symlink might have already been created. */ (void) symlink(setnum, setname); } }
/* * free disk status list */ void meta_free_disk_status_list( md_disk_status_list_t *dslp ) { md_disk_status_list_t *next = NULL; for (/* void */; (dslp != NULL); dslp = next) { next = dslp->next; mdclrerror(&dslp->status); Free(dslp); } }
/* * NAME: meta_raid_resync_all * DESCRIPTION: loop through the RAID devices synch'ing all * PARAMETERS: char *sp - the set to synch * daddr_t size - resync size * md_error_t *ep - return error info * */ int meta_raid_resync_all( mdsetname_t *sp, daddr_t size, md_error_t *ep ) { mdnamelist_t *nlp = NULL; mdnamelist_t *p; int rval = 0, fval; /* should have a set */ assert(sp != NULL); /* get raids */ if (meta_get_raid_names(sp, &nlp, 0, ep) < 0) return (-1); /* fork a process */ if ((fval = md_daemonize(sp, ep)) != 0) { /* * md_daemonize forks off a process to do the work. This * is the parent or errror. */ if (fval > 0) { if (nlp != NULL) metafreenamelist(nlp); return (0); } mdclrerror(ep); } assert((fval == 0) || (fval == -1)); /* resync each raid */ for (p = nlp; (p != NULL); p = p->next) { mdname_t *raidnp = p->namep; if (meta_raid_resync(sp, raidnp, size, ep) != 0) rval = -1; } /* cleanup, return success */ if (nlp != NULL) metafreenamelist(nlp); if (fval == 0) exit(0); return (rval); }
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); }
/* * check whether device is swapped on */ static int meta_check_swapped( mdsetname_t *sp, mdname_t *np, md_error_t *ep ) { struct swaptable *swtp; int nswap; int i; int rval = 0; /* should have a set */ assert(sp != NULL); /* get swap info */ if (get_swapinfo(&swtp, &nswap, ep) != 0) return (-1); /* look for match */ for (i = 0; ((i < nswap) && (rval == 0)); ++i) { mdname_t *snp; if ((snp = metaname(&sp, swtp->swt_ent[i].ste_path, UNKNOWN, ep)) == NULL) { mdclrerror(ep); continue; } if (np->dev == snp->dev) { rval = mddeverror(ep, MDE_IS_SWAPPED, np->dev, np->cname); } else { /* not swap - does it overlap */ rval = meta_check_overlap(snp->cname, np, 0, -1, snp, 0, -1, ep); if (rval != 0) { (void) mdoverlaperror(ep, MDE_OVERLAP_SWAP, np->cname, NULL, snp->cname); } } } free_swapinfo(swtp); /* return success */ return (rval); }
/* * check whether device is a dump device */ static int meta_check_dump( mdsetname_t *sp, mdname_t *np, md_error_t *ep ) { int rval = 0; int dump_fd; char device[MAXPATHLEN]; if ((dump_fd = open("/dev/dump", O_RDONLY)) < 0) return (mdsyserror(ep, errno, "/dev/dump")); if (ioctl(dump_fd, DIOCGETDEV, device) != -1) { mdname_t *dump_np; if ((dump_np = metaname(&sp, device, UNKNOWN, ep)) == NULL) { mdclrerror(ep); (void) close(dump_fd); return (0); } if (np->dev == dump_np->dev) { rval = mddeverror(ep, MDE_IS_DUMP, np->dev, np->cname); } else { /* not a dump device - but does it overlap? */ rval = meta_check_overlap(dump_np->cname, np, 0, -1, dump_np, 0, -1, ep); if (rval != 0) { (void) mdoverlaperror(ep, MDE_OVERLAP_DUMP, np->cname, NULL, dump_np->cname); } } } (void) close(dump_fd); return (rval); }
/* * Is a driver currently swapped on? */ int meta_check_driveswapped( mdsetname_t *sp, mddrivename_t *dnp, md_error_t *ep ) { struct swaptable *swtp; int nswap; int i; int rval = 0; /* should have a set */ assert(sp != NULL); /* get swap info */ if (get_swapinfo(&swtp, &nswap, ep) != 0) return (-1); /* look for match */ for (i = 0; (i < nswap); ++i) { mdname_t *snp; if ((snp = metaname(&sp, swtp->swt_ent[i].ste_path, LOGICAL_DEVICE, ep)) == NULL) { mdclrerror(ep); continue; } if (strcmp(dnp->cname, snp->drivenamep->cname) == 0) { rval = mddeverror(ep, MDE_IS_SWAPPED, NODEV64, dnp->cname); } } free_swapinfo(swtp); /* return success */ return (rval); }
/*ARGSUSED*/ static int stripe_get(void *d, int mode, IOLOCK *lock) { minor_t mnum; mdi_unit_t *ui; ms_unit_t *un; md_error_t *mdep; md_i_get_t *migp = d; mnum = migp->id; mdep = &migp->mde; mdclrerror(mdep); if ((MD_MIN2SET(mnum) >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits)) return (mdmderror(mdep, MDE_INVAL_UNIT, mnum)); if ((ui = MDI_UNIT(mnum)) == NULL) { return (mdmderror(mdep, MDE_UNIT_NOT_SETUP, mnum)); } un = (ms_unit_t *)md_ioctl_readerlock(lock, ui); if (migp->size == 0) { migp->size = un->c.un_size; return (0); } if (migp->size < un->c.un_size) { return (EFAULT); } if (ddi_copyout(un, (void *)(uintptr_t)migp->mdp, un->c.un_size, mode)) return (EFAULT); return (0); }
static int set_hs( set_hs_params_t *shs ) { mdclrerror(&shs->mde); if (md_get_setstatus(shs->md_driver.md_setno) & MD_SET_STALE) return (mdmddberror(&shs->mde, MDE_DB_STALE, NODEV32, shs->md_driver.md_setno)); switch (shs->shs_cmd) { case ADD_HOT_SPARE: return (seths_add(shs)); case DELETE_HOT_SPARE: return (seths_delete(shs)); case REPLACE_HOT_SPARE: return (seths_replace(shs)); case FIX_HOT_SPARE: return (seths_enable(shs)); default: return (mderror(&shs->mde, MDE_INVAL_HSOP)); } }
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); }
int get_mdcomponents(char *uname, svm_info_t **svmpp) { svm_info_t *svmp; md_error_t status, *ep; mdname_t *namep; mdnamelist_t *nlp = NULL; mdnamelist_t *p; mdsetname_t *sp = NULL; char *strp = NULL; int rval, cnt; rval = RET_SUCCESS; cnt = 0; status = mdnullerror; ep = &status; svmp = *svmpp; (void) init_metalib(); debug_printf("get_mdcomponents(): Enter unit name %s\n", uname); if (((namep = metaname(&sp, uname, META_DEVICE, ep)) == NULL) || (metachkmeta(namep, ep) != 0)) { debug_printf("get_mdcomponents(): " "metaname or metachkmeta failed\n"); mdclrerror(ep); return (RET_ERROR); } debug_printf("get_mdcomponents(): meta_getdevs %s\n", namep->cname); if ((meta_getdevs(sp, namep, &nlp, ep)) < 0) { debug_printf("get_mdcomponents(): " "comp %s - meta_getdevs failed\n", uname); metafreenamelist(nlp); mdclrerror(ep); return (RET_ERROR); } /* compute the number of devices */ for (p = nlp, cnt = 0; p != NULL; p = p->next, cnt++) ; /* * Need to add n -1 components since slvmp already has space * for one device. */ svmp = (svm_info_t *)realloc(svmp, sizeof (svm_info_t) + (sizeof (char *) * (cnt - 1))); if (svmp == NULL) { debug_printf("get_mdcomponents(): realloc of svmp failed\n"); metafreenamelist(nlp); return (RET_ERROR); } for (p = nlp, cnt = 0; p != NULL; p = p->next, cnt++) { mdname_t *devnp = p->namep; if ((strp = strdup(devnp->cname)) == NULL) { rval = RET_ERROR; break; } svmp->md_comps[cnt] = strp; } /* count is set to the number of devices in the list */ svmp->count = cnt; svmp->root_md = strdup(uname); if (rval == RET_SUCCESS && svmp->root_md != NULL) { debug_printf("get_mdcomponents(): root_md %s count %d \n", svmp->root_md, svmp->count); for (cnt = 0; cnt < svmp->count; cnt++) debug_printf("get_mdcomponents(): %s\n", svmp->md_comps[cnt]); } else { rval = RET_ERROR; svm_free(svmp); svmp = NULL; debug_printf("get_mdcomponents(): malloc failed\n"); } metafreenamelist(nlp); *svmpp = svmp; return (rval); }
/* * check for same drive * * Differentiate between matching on name/dev_t and devid. In the latter * case it is correct to fail but misleading to give the same error msg as * for an overlapping slice. * */ int meta_check_samedrive( mdname_t *np1, /* first comp */ mdname_t *np2, /* second comp */ md_error_t *ep ) { mdcinfo_t *cinfop1, *cinfop2; mdnmtype_t type1 = np1->drivenamep->type; mdnmtype_t type2 = np2->drivenamep->type; int l = 0; char *name1 = NULL; char *name2 = NULL; int retval = CANT_TELL; int fd1 = -1; int fd2 = -1; int rc1 = -2, rc2 = -2; uint_t strl1 = 0, strl2 = 0; int devid1_found = 0; int devid2_found = 0; ddi_devid_t devid1 = NULL; ddi_devid_t devid2 = NULL; dev_list_t *dnlp = NULL; assert(type1 != MDT_FAST_META && type1 != MDT_FAST_COMP); assert(type2 != MDT_FAST_META && type2 != MDT_FAST_COMP); /* * The process of determining if 2 names are the same drive is * as follows: * * Case 1 - The filenames are identical * * Case 2 - Both devices have a devid * get and compare the devids for the devices. If both * devices have a devid then the compare will is all * that is needed we are done. * * Case 3 - One or more devices does not have a devid * start by doing a simple compare of the name, if they * are the same just return. * * If the names differ then keep going and see if the * may be the same underlying devic. First check to * see if the sd name is the same (old code). * * Then check the major and minor numbers to see if * they are the same. If they are then return (old code). * * Next compare the raw name and the component name and * if they are the same then return. * * All else has failed so use the component name (cname) * component number and unit number. If they all are * equal then call them the same drive. * */ if ((np1 == NULL) || (np2 == NULL)) return (NOT_SAMEDRIVE); /* if the name structs are the same then the drives must be */ if (np1 == np2) return (IDENTICAL_NAME_DEVT); name1 = np1->bname; name2 = np2->bname; if ((name1 == NULL) || ((strl1 = strlen(name1)) == 0) || (name2 == NULL) || ((strl2 = strlen(name2)) == 0)) return (NOT_SAMEDRIVE); if ((strl1 == strl2) && (strcmp(name1, name2) == 0)) { /* names are identical */ return (IDENTICAL_NAME_DEVT); } if (is_metaname(name1) || is_metaname(name2)) return (NOT_SAMEDRIVE); /* * Check to see if the devicename is in the static list. If so, * use its devid. Otherwise do the expensive operations * of opening the device, getting the devid, and closing the * device. Add the result into the static list. * * The case where this list will be useful is when there are soft * partitions on multiple drives and a new soft partition is being * created. In that situation the underlying physical device name * for the new soft partition would be compared against each of the * existing soft partititions. Without this static list that would * involve 2 opens, closes, and devid gets for each existing soft * partition */ for (dnlp = devnamelist; (dnlp != NULL) && !(devid1_found && devid2_found); dnlp = dnlp->dev_nxt) { if (!devid1_found && (strcmp(dnlp->dev_name, name1) == 0)) { devid1_found = 1; devid1 = dnlp->devid; if (devid1 == NULL) rc1 = 1; else rc1 = 0; continue; } if (!devid2_found && (strcmp(dnlp->dev_name, name2) == 0)) { devid2_found = 1; devid2 = dnlp->devid; if (devid2 == NULL) rc2 = 1; else rc2 = 0; continue; } } /* * Start by checking if the device has a device id, and if they * are equal. If they are there is no question there is a match. * * The process here is open each disk, get the devid for each * disk. If they both have a devid compare them and return * the results. */ if (!devid1_found) { if ((fd1 = open(name1, O_RDONLY | O_NDELAY)) < 0) { return (NOT_SAMEDRIVE); } rc1 = devid_get(fd1, &devid1); (void) close(fd1); /* add the name and devid to the cache */ add_to_devname_list(name1, devid1); } if (!devid2_found) { if ((fd2 = open(name2, O_RDONLY | O_NDELAY)) < 0) { return (NOT_SAMEDRIVE); } rc2 = devid_get(fd2, &devid2); (void) close(fd2); /* add the name and devid to the cache */ add_to_devname_list(name2, devid2); } if ((rc1 == 0) && (rc2 == 0)) { if (devid_compare(devid1, devid2) == 0) retval = IDENTICAL_DEVIDS; /* same devid */ else retval = NOT_SAMEDRIVE; /* different drives */ } if (retval >= 0) { return (retval); } /* * At this point in time one of the two drives did not have a * device ID. Do not make the assumption that is one drive * did have a device id and the other did not that they are not * the same. One drive could be covered by a device and still * be the same drive. This is a general flaw in the system at * this time. */ /* * The optimization can not happen if we are given an old style name * in the form /dev/XXNN[a-h], since the name caches differently and * allows overlaps to happen. */ if (! ((sscanf(np1->bname, "/dev/%*[^0-9/]%*u%*[a-h]%n", &l) == 0 && l == strlen(np1->bname)) || (sscanf(np2->bname, "/dev/%*[^0-9/]%*u%*[a-h]%n", &l) == 0 && l == strlen(np2->bname))) && ((type1 == MDT_COMP) || (type1 == MDT_META)) && ((type2 == MDT_COMP) || (type2 == MDT_META))) if (np1->drivenamep == np2->drivenamep) return (IDENTICAL_NAME_DEVT); else return (NOT_SAMEDRIVE); /* check for same drive */ if (meta_getmajor(np1->dev) != meta_getmajor(np2->dev)) return (NOT_SAMEDRIVE); /* not same drive */ if (((cinfop1 = metagetcinfo(np1, ep)) == NULL) || ((cinfop2 = metagetcinfo(np2, ep)) == NULL)) { if ((strcmp(np1->drivenamep->cname, np2->drivenamep->cname) != 0) && (strcmp(np1->drivenamep->rname, np2->drivenamep->rname) != 0)) { mdclrerror(ep); return (NOT_SAMEDRIVE); /* not same drive */ } else { return (CANT_TELL); /* can't tell */ } } else if ((strncmp(cinfop1->cname, cinfop2->cname, sizeof (cinfop1->cname)) != 0) || (cinfop1->cnum != cinfop2->cnum) || (cinfop1->unit != cinfop2->unit)) { return (NOT_SAMEDRIVE); /* not same drive */ } /* same drive */ return (IDENTICAL_NAME_DEVT); }
/* * check whether device is mounted */ static int meta_check_mounted( mdsetname_t *sp, mdname_t *np, md_error_t *ep ) { FILE *mfp; struct mnttab m; int rval = 0; char mountp[MNT_LINE_MAX]; char mnt_special[MNT_LINE_MAX]; /* should have a set */ assert(sp != NULL); /* look in mnttab */ if ((mfp = open_mnttab()) == NULL) return (mdsyserror(ep, errno, MNTTAB)); while ((getmntent(mfp, &m) == 0) && (rval == 0)) { char **fstype = skip_these_mntents; int skipit = 0; mdname_t *mnp; if ((m.mnt_special == NULL) || (m.mnt_mountp == NULL)) continue; if (m.mnt_mountp[0] != '/') continue; while (*fstype != NULL) if (strcmp(m.mnt_fstype, *fstype++) == 0) { skipit++; break; } if (skipit == 1) continue; (void) strcpy(mountp, m.mnt_mountp); (void) strcpy(mnt_special, m.mnt_special); if ((mnp = metaname(&sp, mnt_special, UNKNOWN, ep)) == NULL) { mdclrerror(ep); continue; } if (np->dev == mnp->dev) { rval = mduseerror(ep, MDE_IS_MOUNTED, np->dev, mountp, np->cname); } else { /* device isn't in mnttab - does it overlap? */ rval = meta_check_overlap(mnp->cname, np, 0, -1, mnp, 0, -1, ep); if (rval != 0) { (void) mdoverlaperror(ep, MDE_OVERLAP_MOUNTED, np->cname, mountp, mnp->cname); } } } /* return success */ return (rval); }
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); }
/* * setup RPC service * * if can't authenticate return < 0 * any other error return > 0 */ int svc_init( struct svc_req *rqstp, /* RPC stuff */ int amode, /* R_OK | W_OK */ md_error_t *ep /* returned status */ ) { SVCXPRT *transp; if (sdssc_bind_library() == SDSSC_ERROR) { mdsyserror(ep, EACCES, "can't bind to cluster library"); return (1); } /* * if we have no rpc service info, we must have been * called recursively from within the daemon */ if (rqstp == NULL) { mdclrerror(ep); return (0); /* OK */ } /* * initialize */ transp = rqstp->rq_xprt; assert(transp != NULL); *ep = mdnullerror; /* * check credentials */ switch (rqstp->rq_cred.oa_flavor) { /* UNIX flavor */ case AUTH_SYS: { if (check_sys(rqstp, amode, ep) != 0) return (1); /* error */ break; } /* can't authenticate anything else */ default: svcerr_weakauth(transp); return (-1); /* weak authentication */ } /* * (re)initialize */ if (md_init_daemon("rpc.metad", ep) != 0) return (1); /* error */ if (set_snarf(ep)) return (1); sr_validate(); /* success */ return (0); }
static int init_entries( mdsetname_t **spp, md_tab_t *tabp, mdcmdopts_t options, uint_t flags, bool_t called_thru_rpc, md_error_t *ep ) { uint_t cnt = 0; uint_t line; int rval = 0; int ret; /* for all matching entries, which haven't already been done */ for (line = 0; (line < tabp->nlines); ++line) { md_tab_line_t *linep = &tabp->lines[line]; char *uname = linep->argv[0]; /* see if already done */ if (linep->flags != DO_AGAIN) continue; /* clear the metadev/hsp caches between inits */ metaflushmetanames(); /* try it */ if ((called_thru_rpc == FALSE) && meta_is_mn_name(spp, uname, ep)) { /* * MN set, send command to all nodes * Note that is sp is NULL, meta_is_mn_name() derives * sp from linep->argv which is the metadevice arg */ ret = mn_send_command(spp, linep->argc, linep->argv, options, flags, linep->context, ep); } else { char *cname = NULL; cname = meta_name_getname(spp, uname, META_DEVICE, ep); if (cname == NULL) { mde_perror(ep, ""); mdclrerror(ep); } else { ret = meta_init_name(spp, linep->argc, linep->argv, cname, options, ep); Free(cname); if (ret != 0) { if (!(flags & MD_IGNORE_STDERR)) { mderrorextra(ep, linep->context); mde_perror(ep, ""); rval = -1; } mdclrerror(ep); } } } if (ret == 0) { linep->flags = IS_DONE; ++cnt; } } /* return success */ if (rval != 0) return (rval); return (cnt); }
char * obj2devname(uint32_t tag, set_t setno, md_dev64_t dev) { char *setname; char *uname; char name[MD_MAX_CTDLEN]; mdsetname_t *sp; md_error_t status = mdnullerror; md_set_record *md_sr; minor_t mnum = meta_getminor(dev); int rtn = 0; setname = NULL; if ((setno != MD_SET_BAD) && ((sp = metasetnosetname(setno, &status)) != NULL)) { setname = sp->setname; } name[0] = '\0'; switch (tag) { case SVM_TAG_HS: case SVM_TAG_METADEVICE: case SVM_TAG_MIRROR: case SVM_TAG_RAID5: case SVM_TAG_STRIPE: case SVM_TAG_TRANS: uname = get_mdname(sp, mnum); if (uname == NULL) return (NULL); (void) strcpy(name, uname); break; case SVM_TAG_HSP: uname = get_hspname(sp, mnum); if (uname == NULL) return (NULL); (void) strcpy(name, uname); break; case SVM_TAG_DRIVE: (void) sprintf(name, "drive"); break; case SVM_TAG_HOST: md_sr = NULL; if (setname != NULL) { md_sr = getsetbyname(setname, &status); } if ((md_sr != NULL) && (md_sr->sr_nodes[mnum] != NULL)) { /* * Get the host data from the node array. */ rtn = snprintf(name, sizeof (name), "%s", md_sr->sr_nodes[mnum]); } if ((name[0] == '\0') || (rtn >= sizeof (name))) { (void) sprintf(name, "host"); rtn = 0; } break; case SVM_TAG_SET: if (setname == NULL) { (void) sprintf(name, "diskset"); } else { rtn = snprintf(name, sizeof (name), "%s", setname); } break; default: if ((setname = get_devname(setno, dev)) != NULL) { rtn = snprintf(name, sizeof (name), "%s", setname); } break; } mdclrerror(&status); /* Check if we got any rubbish for any of the snprintf's */ if ((name[0] == '\0') || (rtn >= sizeof (name))) { return (NULL); } return (strdup(name)); }
/* * initialize all devices in set */ static int init_all( mdsetname_t **spp, mdcmdopts_t options, bool_t called_thru_rpc, md_error_t *ep ) { md_tab_t *tabp = NULL; size_t setlen; uint_t more; int done; int eval = -1; /* * Only take the lock if this is not a MN set * We can only enter this code for a MN set if we are the initiator * and in this case, we don't want to take locks. */ if (meta_is_mn_set((*spp), ep) == 0) { /* grab set lock */ if (meta_lock(*spp, TRUE, ep)) { mde_perror(ep, ""); mdclrerror(ep); return (eval); } /* check for ownership */ if (meta_check_ownership(*spp, ep) != 0) { mde_perror(ep, ""); mdclrerror(ep); return (eval); } /* lock is held across init_entries */ options |= MDCMD_NOLOCK; } /* get md.tab, preen entries */ if ((tabp = meta_tab_parse(NULL, ep)) == NULL) { mde_perror(ep, ""); mdclrerror(ep); return (eval); } setlen = strlen((*spp)->setname); for (more = 0; (more < tabp->nlines); ++more) { md_tab_line_t *linep = &tabp->lines[more]; char *cname = linep->cname; char *p; size_t len; /* better have args */ assert((linep->argc > 0) && (linep->argv[0] != NULL)); /* only do metadevices and hotspare pools in set */ if (linep->type & TAB_MD_HSP) { if ((p = strrchr(cname, '/')) == NULL) { len = 0; } else { len = p - cname; } if ((len == setlen) && (strncmp(cname, (*spp)->setname, len) == 0)) { linep->flags = DO_AGAIN; } else { linep->flags = DONT_DO; } } else { linep->flags = DONT_DO; } } eval = 1; /* while more devices get made */ do { done = init_entries(spp, tabp, options, MD_IGNORE_STDERR|MD_RETRY_BUSY, called_thru_rpc, ep); } while (done > 0); /* now do it and report errors */ if (init_entries(spp, tabp, options, MD_RETRY_BUSY, called_thru_rpc, ep) >= 0) eval = 0; /* success */ mdclrerror(ep); /* cleanup, return success */ out: meta_tab_free(tabp); return (eval); }
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 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_getdevs( void *d, int mode, IOLOCK *lock ) { minor_t mnum; mdi_unit_t *ui; ms_unit_t *un; struct ms_row *mdr; ms_comp_t *mdcomp, *mdc; int r, c, i; int cnt; md_error_t *mdep; md_dev64_t *devsp; md_dev64_t unit_dev; md_getdevs_params_t *mgdp = d; mnum = mgdp->mnum; mdep = &mgdp->mde; /* check out unit */ mdclrerror(mdep); if ((MD_MIN2SET(mnum) >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits)) return (mdmderror(mdep, MDE_INVAL_UNIT, mnum)); if ((ui = MDI_UNIT(mnum)) == NULL) { return (mdmderror(mdep, MDE_UNIT_NOT_SETUP, mnum)); } un = (ms_unit_t *)md_ioctl_readerlock(lock, ui); mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]); devsp = (md_dev64_t *)(uintptr_t)mgdp->devs; for (cnt = 0, 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 (cnt < mgdp->cnt) { unit_dev = mdc->un_dev; if (md_getmajor(unit_dev) != md_major) { if ((unit_dev = md_xlate_mini_2_targ (unit_dev)) == NODEV64) return (ENODEV); } if (ddi_copyout((caddr_t)&unit_dev, devsp, sizeof (*devsp), mode) != 0) return (EFAULT); ++devsp; } ++cnt; } } mgdp->cnt = cnt; return (0); }
/*ARGSUSED*/ int meta_get_drive_names( mdsetname_t *sp, mddrivenamelist_t **dnlpp, int options, md_error_t *ep ) { mhd_did_flags_t flags = MHD_DID_SERIAL; mhd_drive_info_list_t list; mhd_drive_info_t *mp; uint_t i; unsigned cnt = 0; int rval = -1; mddrivenamelist_t **tailpp = dnlpp; /* must have a set */ assert(sp != NULL); load_paths_to_metamhd(); (void) memset(&list, 0, sizeof (list)); if ((meta_list_drives(NULL, NULL, flags, &list, ep)) < 0) return (-1); /* find drives in set */ for (i = 0; (i < list.mhd_drive_info_list_t_len); ++i) { mddrivename_t *dnp; mdname_t *np; mp = &list.mhd_drive_info_list_t_val[i]; if (mp->dif_id.did_flags & MHD_DID_DUPLICATE) continue; /* quietly skip drives which don't conform */ if ((dnp = metadrivename(&sp, mp->dif_name, ep)) == NULL) { mdclrerror(ep); continue; } /* check in set */ if ((np = metaslicename(dnp, MD_SLICE0, ep)) == NULL) goto out; if (meta_check_inset(sp, np, ep) != 0) { mdclrerror(ep); continue; } /* * Add the drivename struct to the end of the * drivenamelist but keep a pointer to the last * element so that we don't incur the overhead * of traversing the list each time */ tailpp = meta_drivenamelist_append_wrapper(tailpp, dnp); ++cnt; } rval = cnt; /* cleanup, return error */ out: meta_free_drive_info_list(&list); return (rval); }
/* * This routine is called from preenlib the first time. It is then * recursively called through preen_subdev. * * The argument passed in (uname) starts with the special device from * /etc/vfstab. Recursive calls pass in the underlying physical device * names. */ void preen_build_devs( char *uname, /* name of metadevice */ struct dk_cinfo *dkiop, /* associated controller info */ void *dp /* magic info */ ) { char *setname = NULL; char *tname = NULL; mdsetname_t *sp; mdname_t *namep; /* metadevice name */ mdnamelist_t *nlp = NULL; /* list of real devices */ mdnamelist_t *p; devid_nmlist_t *nm_list = NULL; md_error_t status = mdnullerror; md_error_t *ep = &status; int ep_valid = 0; /* does ep contain a real error */ struct stat statb; static int md_major = -1; side_t sideno; /* * The rest of the code in this library can't work within a * non-global zone so we just return the top level metadevice back * to be fscked. */ if (getzoneid() != GLOBAL_ZONEID) { preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); return; } if (stat(uname, &statb) != 0) return; if (md_major == -1 && get_major_from_n2m(MD_MODULE, &md_major) != 0) return; /* * If the path passed in is not a metadevice, then add that * device to the list (preen_addunit) since it has to be a * physical device. */ if (major(statb.st_rdev) != md_major) { preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); return; } /* * Bind to the cluster library */ if (sdssc_bind_library() == SDSSC_ERROR) return; if (md_init_daemon("fsck", ep) != 0) { ep_valid = 1; goto out; } /* * parse the path name to get the diskset name. */ parse_device(NULL, uname, &tname, &setname); Free(tname); if ((sp = metasetname(setname, ep)) == NULL) { ep_valid = 1; goto out; } /* check for ownership */ if (meta_check_ownership(sp, ep) != 0) { /* * Don't own the set but we are here implies * that this is a clustered proxy device. Simply add * the unit. */ preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); ep_valid = 1; goto out; } /* * get list of underlying physical devices. */ if ((namep = metaname(&sp, uname, UNKNOWN, ep)) == NULL) { ep_valid = 1; goto out; } if (namep->dev == NODEV64) { goto out; } if (meta_getdevs(sp, namep, &nlp, ep) != 0) { ep_valid = 1; goto out; } if ((sideno = getmyside(sp, ep)) == MD_SIDEWILD) { ep_valid = 1; goto out; } /* gather and add the underlying devs */ for (p = nlp; (p != NULL); p = p->next) { mdname_t *devnp = p->namep; int fd; struct dk_cinfo cinfo; ddi_devid_t md_did; char *devname; char *minor_name = NULL; char mname[MAXPATHLEN]; /* * we don't want to use the rname anymore because * that may have changed. Use the device id information * to find the correct ctd name and open based on that. * If there isn't a devid or we have a did device, then * use the rname. In clustering, it's corrected for us. * If no devid it's at least worth a try. */ if (((md_did = meta_getdidbykey(sp->setno, sideno, devnp->key, ep)) == NULL) || ((minor_name = meta_getdidminorbykey(sp->setno, sideno, devnp->key, ep)) == NULL)) { devname = devnp->rname; if (md_did) Free(md_did); } else { if (strstr(minor_name, ",raw") == NULL) { (void) snprintf(mname, MAXPATHLEN, "%s,raw", minor_name); } else { (void) snprintf(mname, MAXPATHLEN, "%s", minor_name); } /* * We need to make sure we call this with a specific * mname (raw mname) so that we get the exact slice * with the given device id. Otherwise we could try * to open a slice that doesn't really exist. */ if (meta_deviceid_to_nmlist("/dev", md_did, mname, &nm_list) != 0) { (void) mdsyserror(ep, errno, devnp->rname); ep_valid = 1; Free(md_did); Free(minor_name); goto out; } devname = Strdup(nm_list->devname); Free(md_did); Free(minor_name); devid_free_nmlist(nm_list); } /* get device name and (real) cinfo */ if ((fd = open(devname, O_RDONLY, 0)) < 0) { (void) mdsyserror(ep, errno, devname); ep_valid = 1; /* * We need to scan all sub devices even if some fail * since exit here would end up in not finishing fsck * on all devices and prevent us from going into * multiuser mode. */ continue; } if (ioctl(fd, DKIOCINFO, &cinfo) != 0) { (void) mdsyserror(ep, errno, devname); (void) close(fd); ep_valid = 1; /* Continue here too. See comment from before */ continue; } (void) close(fd); /* sd/ssd bug */ /* * preen_subdev fails when the device name has been * resolved to the physical layer. Hence it is added * to preen_addunit. */ if (preen_subdev(devname, &cinfo, dp) != 0) { preen_addunit(dp, cinfo.dki_dname, NULL, NULL, cinfo.dki_unit); } } /* cleanup, if we fail, just add this composite device to the list */ out: if (setname != NULL) Free(setname); if (ep_valid != 0) { mde_perror(&status, ""); mdclrerror(&status); } metafreenamelist(nlp); }