Exemplo n.º 1
0
/*
 * resync raid
 */
int
meta_raid_resync(
	mdsetname_t		*sp,
	mdname_t		*raidnp,
	daddr_t			size,
	md_error_t		*ep
)
{
	char			*miscname;
	md_resync_ioctl_t	ri;

	/* should have a set */
	assert(sp != NULL);
	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));

	/* make sure we have a raid */
	if ((miscname = metagetmiscname(raidnp, ep)) == NULL)
		return (-1);
	if (strcmp(miscname, MD_RAID) != 0) {
		return (mdmderror(ep, MDE_NOT_RAID, meta_getminor(raidnp->dev),
		    raidnp->cname));
	}

	/* start resync */
	(void) memset(&ri, 0, sizeof (ri));
	MD_SETDRIVERNAME(&ri, MD_RAID, sp->setno);
	ri.ri_mnum = meta_getminor(raidnp->dev);
	ri.ri_copysize = size;
	if (metaioctl(MD_IOCSETSYNC, &ri, &ri.mde, raidnp->cname) != 0)
		return (mdstealerror(ep, &ri.mde));

	/* return success */
	return (0);
}
Exemplo n.º 2
0
/*
 * Return the current root filesystem block device name. This is only valid
 * when root is either a slice, a stripe or a mirror.
 */
mdname_t *
meta_get_current_root_dev(
    mdsetname_t	*sp,
    md_error_t	*ep
)
{
    md_stripe_t	*stripep;
    md_mirror_t	*mirrorp;
    md_row_t	*rp;
    md_comp_t	*cp;
    mdname_t	*rootnp;
    void		*curroot;
    char		*miscname;
    int		smi;

    if ((curroot = meta_get_current_root(ep)) == NULL)
        return (NULL);
    if ((rootnp = metaname(&sp, curroot, UNKNOWN, ep)) == NULL)
        return (NULL);
    if (metaismeta(rootnp)) {
        if ((miscname = metagetmiscname(rootnp, ep)) == NULL)
            return (NULL);
        if ((strcmp(miscname, MD_MIRROR) == 0) &&
                ((mirrorp = meta_get_mirror(sp, rootnp, ep)) != NULL)) {
            for (smi = 0; smi < NMIRROR; smi++) {
                md_submirror_t *mdsp =
                    &mirrorp->submirrors[smi];
                rootnp = mdsp->submirnamep;
                /* skip unused submirrors */
                if (rootnp == NULL) {
                    assert(mdsp->state == SMS_UNUSED);
                    continue;
                }
                if ((miscname = metagetmiscname(rootnp, ep))
                        == NULL) {
                    (void) mdmderror(ep, MDE_UNKNOWN_TYPE,
                                     meta_getminor(rootnp->dev),
                                     rootnp->cname);
                    return (NULL);
                }
                break;
            }
        }
        if ((strcmp(miscname, MD_STRIPE) == 0) &&
                ((stripep = meta_get_stripe(sp, rootnp, ep)) != NULL)) {
            rp = &stripep->rows.rows_val[0];
            cp = &rp->comps.comps_val[0];
            if (metachkcomp(cp->compnamep, ep) == 0)
                return (cp->compnamep);
        }
        /* Root is not a single stripe metadevice */
        (void) mddeverror(ep, MDE_INV_ROOT, rootnp->dev, rootnp->cname);
        return (NULL);
    } else return (rootnp);
}
Exemplo n.º 3
0
int
md_probe_ioctl(mdnamelist_t *nlp, int ndevs, char *drvname, boolean_e verbose)
{
	mdnamelist_t	*p;
	mdname_t	*np;
	md_probedev_t	probe_ioc,
			*iocp;
	int		i,
			retval = 0;
	/*
	 * Allocate space for all the metadevices and fill in
	 * the minor numbers.
	 */

	memset(&probe_ioc, 0, sizeof (probe_ioc));
	iocp = &probe_ioc;

	if ((iocp->mnum_list = (uintptr_t)calloc(ndevs, sizeof (minor_t)))
	    == 0) {
		monitord_print(0, "md_probe_ioctl: calloc");
		return (-1);
	}

	(void) strcpy(iocp->test_name, MD_PROBE_OPEN_T);
	MD_SETDRIVERNAME(&probe_ioc, drvname, sp->setno);

	if (verbose == True) {
		monitord_print(6, "\n\nmd_probe_ioctl: %s: %s\n",
		    (strcmp(sp->setname, MD_LOCAL_NAME) == 0) ?
		    gettext("local_set") :
		    sp->setname, iocp->md_driver.md_drivername);
	}

	iocp->nmdevs = ndevs;
	if (verbose == True)
		monitord_print(6, "...ndevs 0x%x\n", ndevs);

	for (p = nlp, i = 0; p; p = p->next, i++) {
		np = p->namep;
		((minor_t *)(uintptr_t)iocp->mnum_list)[i] =
		    meta_getminor(np->dev);
		if (verbose == True)
			monitord_print(6, "...%s 0x%lx\n", np->cname,
			    ((minor_t *)(uintptr_t)iocp->mnum_list)[i]);
	}


	if (issue_ioctl == True) {
		if (metaioctl(MD_IOCPROBE_DEV, iocp, &(iocp->mde), NULL) != 0)
			retval = -1;
	}
	return (retval);
}
Exemplo n.º 4
0
/*
 * grow generic device
 */
int
meta_concat_generic(
	mdsetname_t		*sp,
	mdname_t		*namep,
	u_longlong_t		big_or_little,
	md_error_t		*ep
)
{
	md_grow_params_t	mgp;
	char			*miscname;

	/* should have a set */
	assert(sp != NULL);
	assert(sp->setno == MD_MIN2SET(meta_getminor(namep->dev)));

	/* get type */
	if ((miscname = metagetmiscname(namep, ep)) == NULL)
		return (-1);

	/* grow device */
	(void) memset(&mgp, 0, sizeof (mgp));
	if (big_or_little & MD_64BIT_META_DEV)
		mgp.options = MD_CRO_64BIT;
	else
		mgp.options = MD_CRO_32BIT;

	mgp.mnum = meta_getminor(namep->dev);
	MD_SETDRIVERNAME(&mgp, miscname, sp->setno);
	if (metaioctl(MD_IOCGROW, &mgp, &mgp.mde, namep->cname) != 0)
		return (mdstealerror(ep, &mgp.mde));

	/* clear cache */
	meta_invalidate_name(namep);

	/* return success */
	return (0);
}
Exemplo n.º 5
0
/*
 * grow the parent of a device
 */
int
meta_concat_parent(
	mdsetname_t	*sp,
	mdname_t	*childnp,
	md_error_t	*ep
)
{
	md_common_t	*mdp;
	mdname_t	*parentnp;
	md_unit_t	*mup;

	/* should have a set */
	assert(sp != NULL);
	assert(sp->setno == MD_MIN2SET(meta_getminor(childnp->dev)));

	/* get parent */
	if ((mdp = meta_get_unit(sp, childnp, ep)) == NULL)
		return (-1);
	if (! MD_HAS_PARENT(mdp->parent))
		return (0);
	if (mdp->parent == MD_MULTI_PARENT)
		return (0);

	/* single parent */
	if ((parentnp = metamnumname(&sp, mdp->parent, 0, ep)) == NULL)
		return (-1);
	/* don't grow non-metadevices or soft partitions */
	if (! metaismeta(parentnp) || meta_sp_issp(sp, parentnp, ep) == 0)
		return (0);

	if ((mup = meta_get_mdunit(sp, childnp, ep)) == NULL)
		return (-1);

	/* grow parent */
	if (meta_concat_generic(sp, parentnp, mup->c.un_revision, ep) != 0)
		return (-1);

	/* recursively check for parents of parents */
	return (meta_concat_parent(sp, parentnp, ep));
}
Exemplo n.º 6
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));
}
Exemplo n.º 7
0
/*
 * FUNCTION:	meta_repartition_drive()
 * INPUT:	sp	- the set name for the device to check
 *		dnp	- the name of the drive to partition
 *              options - options (see NOTES)
 * OUTPUT:	vtocp	- pointer to an mdvtoc_t structure in which
 *			  to return the new VTOC to the caller
 *		ep	- pointer to an md_error_t structure in which
 *			  to return errors to the caller
 * RETURNS:	int	-  0 - drive was or can be repartitioned
 *			  -1 - drive could not or should not be
 *			       repartitioned
 * PURPOSE:	Repartition a disk for use in a disk set or in order
 *		to create soft partitions on it.  Alternatively,
 *		return the VTOC that the disk would have if it were
 *		repartitioned without actually repartitioning it.
 *
 * NOTES:
 *
 *     This routine will repartition a drive to make it suitable for
 *     inclusion in a diskset.  Specifically, it will create a
 *     proposed VTOC that specifies a replica slice that begins at the
 *     first valid lba, is large enough to hold a label and a metadb
 *     replica, does not overlap any other slices, and is unmountable.
 *     If the current replica slice already satisfies those criteria,
 *     the routine will neither create a proposed VTOC nor repartition
 *     the drive unless the MD_REPART_FORCE flag is passed into the
 *     routine in the options argument.  If the routine does create a
 *     proposed VTOC, it will return the proposed VTOC in *vtocp if
 *     vtocp isn't NULL.
 *
 *     The slice to be used as the replica slice is determined by the
 *     function meta_replicaslice().
 *
 *     If the replica slice does not satisfy the above criteria or the
 *     MD_REPART_FORCE flag is set, the proposed VTOC will specify a
 *     replica slice that satisfies the above criteria, a slice zero
 *     that contains the remaining space on the disk, and no other
 *     slices.  If that repartitioning would cause the replica slice
 *     to move or shrink, and the MD_REPART_LEAVE_REP option is set,
 *     the routine will return -1 without creating or returning a
 *     proposed vtoc, and without repartitioning the disk.  Otherwise
 *     the routine will repartition the disk unless the
 *     MD_REPART_DONT_LABEL flag is set in the options argument.
 *
 *     If the MD_REPART_DONT_LABEL flag is set in the options argument,
 *     but the routine would otherwise repartition the drive, the
 *     routine won't repartition the drive, but will create a proposed
 *     VTOC that satisfies the criteria defined above and return it
 *     it in *vtocp if vtocp isn't NULL,  The MD_REPART_DONT_LABEL
 *     option allows calling routines to determine what the contents of
 *     the drive's VTOC would be if the drive were repartitioned without
 *     actually repartitioning the drive.
 */
int
meta_repartition_drive(
	mdsetname_t	*sp,
	mddrivename_t	*dnp,
	int		options,
	mdvtoc_t	*vtocp,
	md_error_t	*ep
)
{
	uint_t			 replicaslice;
	diskaddr_t		 first_lba, last_lba;
	int			 round_sizes = 1;
	unsigned long long	 cylsize;
	unsigned long long	 drvsize;
	int			 i;
	mdgeom_t		*mdgp;
	mdvtoc_t		*mdvp;
	mdvtoc_t		 proposed_vtoc;
	uint_t			 reservedcyl;
	ushort_t		 resflag;
	mdname_t		*resnp;
	unsigned long long	 ressize;
	md_set_desc		*sd;
	daddr_t			 dbsize;
	diskaddr_t		 replica_start;
	diskaddr_t		 replica_size;
	diskaddr_t		 replica_end;
	diskaddr_t		 data_start;
	diskaddr_t		 data_size;

	if (meta_replicaslice(dnp, &replicaslice, ep) != 0) {
		return (-1);
	}

	/* Don't round for EFI disks */
	if (replicaslice == MD_SLICE6)
		round_sizes = 0;

	/*
	 * We took as argument a drive name pointer, but we need a
	 * slice name pointer to retrieve vtoc information.  So get
	 * the name pointer for slice zero first, then use it to get
	 * the vtoc info for the disk.
	 */
	if ((resnp = metaslicename(dnp, MD_SLICE0, ep)) == NULL)
		return (-1);

	if ((mdvp = metagetvtoc(resnp, FALSE, NULL, ep)) == NULL)
		return (-1);

	/*
	 * Determine the metadb size.
	 */
	dbsize = MD_DBSIZE;
	if (!metaislocalset(sp)) {
		if ((sd = metaget_setdesc(sp, ep)) == NULL)
			return (-1);

		if (MD_MNSET_DESC(sd))
			dbsize = MD_MN_DBSIZE;
	}

	/* If we've got an efi disk, we better have lba info */
	first_lba = mdvp->first_lba;
	last_lba = mdvp->last_lba;
	ASSERT((round_sizes != 0) || (last_lba > 0));

	/*
	 * At this point, ressize is used as a minimum value.  Later
	 * it will be rounded up to a cylinder boundary if
	 * appropriate.  ressize is in units of disk sectors.
	 */
	ressize = dbsize + VTOC_SIZE;
	resflag = V_UNMNT;

	/*
	 * If we're forcing the repartition, we can skip the replica
	 * slice and overlap tests.
	 */
	if (options & MD_REPART_FORCE) {
		goto do_repartition;
	}

	/*
	 * Replica slice tests: it must begin at first_lba, be long
	 * enough, have the right flags, and not overlap any other
	 * slices.  If any of these conditions is violated, we need to
	 * repartition the disk.
	 */
	if (mdvp->parts[replicaslice].start != first_lba) {
		goto do_repartition;
	}

	if (mdvp->parts[replicaslice].size < ressize) {
		goto do_repartition;
	}

	if (mdvp->parts[replicaslice].flag != resflag) {
		goto do_repartition;
	}

	/*
	 * Check for overlap: this test should use the actual size of
	 * the replica slice, as contained in the vtoc, and NOT the
	 * minimum size calculated above.
	 */
	replica_end = first_lba + mdvp->parts[replicaslice].size;
	for (i = 0; i < mdvp->nparts; i++) {
		if (i != replicaslice) {
			if ((mdvp->parts[i].size > 0) &&
			    (mdvp->parts[i].start < replica_end)) {
				goto do_repartition;
			}
		}
	}

	/*
	 * If we passed the above tests, then the disk is already
	 * partitioned appropriately, and we're not being told to
	 * force a change.
	 */
	return (0);

do_repartition:

	/* Retrieve disk geometry info and round to cylinder sizes */
	if (round_sizes != 0) {

		if ((mdgp = metagetgeom(resnp, ep)) == NULL)
			return (-1);

		/*
		 * Both cylsize and drvsize are in units of disk
		 * sectors.
		 *
		 * The intended results are of type unsigned long
		 * long.  Since each operand of the first
		 * multiplication is of type unsigned int, we risk
		 * overflow by multiplying and then converting the
		 * result.  Therefore we explicitly cast (at least)
		 * one of the operands, forcing conversion BEFORE
		 * multiplication, and avoiding overflow.  The second
		 * assignment is OK, since one of the operands is
		 * already of the desired type.
		 */
		cylsize =
		    ((unsigned long long)mdgp->nhead) * mdgp->nsect;
		drvsize = cylsize * mdgp->ncyl;

		/*
		 * How many cylinders must we reserve for the replica
		 * slice to ensure that it meets the previously
		 * calculated minimum size?
		 */
		reservedcyl = (ressize + cylsize - 1) / cylsize;
		ressize = reservedcyl * cylsize;
	} else {
		drvsize = last_lba - first_lba;
	}

	/* Would this require a forbidden change? */
	if (options & MD_REPART_LEAVE_REP) {
		if ((mdvp->parts[replicaslice].start != first_lba) ||
		    (mdvp->parts[replicaslice].size < ressize)) {
			return (mddeverror(ep, MDE_REPART_REPLICA,
			    resnp->dev, NULL));
		}
	}

	/*
	 * It seems unlikely that someone would pass us too small a
	 * disk, but it's still worth checking for...
	 */
	if (((round_sizes != 0) && (reservedcyl >= (int)mdgp->ncyl)) ||
	    ((round_sizes == 0) && (ressize + first_lba >= last_lba))) {
		return (mdmddberror(ep, MDE_DB_TOOSMALL,
		    meta_getminor(resnp->dev), sp->setno, 0, NULL));
	}

	replica_start = first_lba;
	replica_size = ressize;
	data_start = first_lba + ressize;
	data_size = drvsize - ressize;

	/*
	 * Create the proposed VTOC.  First copy the current VTOC
	 * into the proposed VTOC to duplicate the values that don't
	 * need to change.  Then change the partition table and set
	 * the flag value for the replica slice to resflag to reserve it
	 * for metadata.
	 */
	proposed_vtoc = *mdvp;
	/* We need at least replicaslice partitions in the proposed vtoc */
	if (replicaslice >= proposed_vtoc.nparts) {
		proposed_vtoc.nparts = replicaslice + 1;
	}
	for (i = 0; i < proposed_vtoc.nparts; i++) {
		/* don't change the reserved partition of an EFI device */
		if (proposed_vtoc.parts[i].tag == V_RESERVED)
			data_size = proposed_vtoc.parts[i].start - data_start;
		else
			(void) memset(&proposed_vtoc.parts[i], '\0',
				sizeof (proposed_vtoc.parts[i]));
	}

	proposed_vtoc.parts[MD_SLICE0].start = data_start;
	proposed_vtoc.parts[MD_SLICE0].size = data_size;
	proposed_vtoc.parts[MD_SLICE0].tag = V_USR;
	proposed_vtoc.parts[replicaslice].start = replica_start;
	proposed_vtoc.parts[replicaslice].size = replica_size;
	proposed_vtoc.parts[replicaslice].flag = resflag;
	proposed_vtoc.parts[replicaslice].tag = V_USR;

	if (!(options & MD_REPART_DONT_LABEL)) {
		/*
		 * Label the disk with the proposed VTOC.
		 */
		*mdvp = proposed_vtoc;
		if (metasetvtoc(resnp, ep) != 0) {
			return (-1);
		}
	}

	if (vtocp != NULL) {
		/*
		 * Return the proposed VTOC.
		 */
		*vtocp = proposed_vtoc;
	}

	return (0);
}