Exemple #1
0
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);
}
Exemple #2
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);
}
Exemple #3
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);
}
Exemple #5
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);
}
Exemple #6
0
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);
	}
}
Exemple #8
0
/*
 * 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);
}
Exemple #10
0
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);
}
Exemple #11
0
/*
 * 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);
}
Exemple #12
0
/*
 * 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);
}
Exemple #13
0
/*
 * 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);
}
Exemple #15
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);
}
Exemple #17
0
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);
}
Exemple #18
0
/*
 * 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);
}
Exemple #19
0
/*
 * 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);
}
Exemple #21
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);
}
Exemple #22
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);
}
Exemple #23
0
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));
}
Exemple #24
0
/*
 * 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(&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);
}
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);
}
Exemple #28
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);
}
Exemple #29
0
/*
 * 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);
}