예제 #1
0
파일: md.c 프로젝트: lacombar/netbsd-alc
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;
}
예제 #2
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);
}
예제 #3
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);
}
예제 #4
0
파일: md.c 프로젝트: lacombar/netbsd-alc
/*
 * 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);
}
예제 #5
0
파일: md.c 프로젝트: lacombar/netbsd-alc
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));
}
예제 #6
0
파일: md.c 프로젝트: lacombar/netbsd-alc
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);
}
예제 #7
0
/*
 * 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;
}
예제 #8
0
/*
 * 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);
}
예제 #9
0
파일: md.c 프로젝트: lacombar/netbsd-alc
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;
}
예제 #10
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(&params->mde);

	un = (ms_unit_t *)MD_UNIT(mnum);

	if (MD_STATUS(un) & MD_UN_RESYNC_ACTIVE) {
		return (mdmderror(&params->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);
}
예제 #11
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);
}
예제 #12
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);
}
예제 #13
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);
	}
}
예제 #14
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));
}
예제 #15
0
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);
}