Example #1
0
struct disklabel *
getdisklabel(char *s)
{
	static struct disklabel lab;
	struct disklabel *lp;

	if (is_file) {
		if (read(disk.d_fd, bootarea, BBSIZE) != BBSIZE)
			err(4, "cannot read bootarea");
		if (bsd_disklabel_le_dec(
		    bootarea + (0 /* labeloffset */ +
				1 /* labelsoffset */ * sectorsize),
		    &lab, MAXPARTITIONS))
			errx(1, "no valid label found");

		lp = &lab;
		return &lab;
	}

	if (ioctl(disk.d_fd, DIOCGDINFO, (char *)&lab) != -1)
		return (&lab);
	unlabeled++;
	if (disktype) {
		lp = getdiskbyname(disktype);
		if (lp != NULL)
			return (lp);
	}
	return (NULL);
}
Example #2
0
static int
g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset)
{
	int error;
	u_char *buf;
	struct disklabel *dl;
	off_t secoff;

	/*
	 * We need to read entire aligned sectors, and we assume that the
	 * disklabel does not span sectors, so one sector is enough.
	 */
	secoff = offset % secsize;
	buf = g_read_data(cp, offset - secoff, secsize, NULL);
	if (buf == NULL)
		return (ENOENT);

	/* Decode into our native format. */
	dl = &ms->ondisk;
	error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS);
	if (!error)
		bcopy(buf + secoff, ms->label, LABELSIZE);

	/* Remember to free the buffer g_read_data() gave us. */
	g_free(buf);

	ms->labeloffset = offset;
	return (error);
}
Example #3
0
/*
 * Fetch disklabel for disk.
 */
static int
readlabel(int flag)
{
	ssize_t nbytes;
	uint32_t lba;
	int f, i;
	int error;

	f = open(specname, O_RDONLY);
	if (f < 0)
		err(1, "%s", specname);
	if (is_file)
		get_file_parms(f);
	else {
		mediasize = g_mediasize(f);
		secsize = g_sectorsize(f);
		if (secsize < 0 || mediasize < 0)
			err(4, "cannot get disk geometry");
	}
	if (mediasize > (off_t)0xffffffff * secsize)
		errx(1,
		    "disks with more than 2^32-1 sectors are not supported");
	(void)lseek(f, (off_t)0, SEEK_SET);
	nbytes = read(f, bootarea, BBSIZE);
	if (nbytes == -1)
		err(4, "%s read", specname);
	if (nbytes != BBSIZE)
		errx(4, "couldn't read %d bytes from %s", BBSIZE, specname);
	close (f);
	error = bsd_disklabel_le_dec(
	    bootarea + (labeloffset + labelsoffset * secsize),
	    &lab, MAXPARTITIONS);
	if (flag && error)
		errx(1, "%s: no valid label found", specname);

	if (is_file)
		return(0);

	/*
	 * Compensate for absolute block addressing by finding the
	 * smallest partition offset and if the offset of the 'c'
	 * partition is equal to that, subtract it from all offsets.
	 */
	lba = ~0;
	for (i = 0; i < lab.d_npartitions; i++) {
		if (lab.d_partitions[i].p_size)
			lba = MIN(lba, lab.d_partitions[i].p_offset);
	}
	if (lba != 0 && lab.d_partitions[RAW_PART].p_offset == lba) {
		for (i = 0; i < lab.d_npartitions; i++) {
			if (lab.d_partitions[i].p_size)
				lab.d_partitions[i].p_offset -= lba;
		}
		/*
		 * Save the offset so that we can write the label
		 * back with absolute block addresses.
		 */
		lba_offset = lba;
	}
	return (error);
}
Example #4
0
/*
 * Modify our slicer to match proposed disklabel, if possible.
 * This is where we make sure we don't do something stupid.
 */
static int
g_bsd_modify(struct g_geom *gp, u_char *label)
{
	int i, error;
	struct partition *ppp;
	struct g_slicer *gsp;
	struct g_consumer *cp;
	struct g_bsd_softc *ms;
	u_int secsize, u;
	off_t rawoffset, o;
	struct disklabel dl;
	MD5_CTX md5sum;

	g_topology_assert();
	gsp = gp->softc;
	ms = gsp->softc;

	error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS);
	if (error) {
		return (error);
	}

	/* Get dimensions of our device. */
	cp = LIST_FIRST(&gp->consumer);
	secsize = cp->provider->sectorsize;

	/* ... or a smaller sector size. */
	if (dl.d_secsize < secsize) {
		return (EINVAL);
	}

	/* ... or a non-multiple sector size. */
	if (dl.d_secsize % secsize != 0) {
		return (EINVAL);
	}

	/* Historical braindamage... */
	rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize;

	for (i = 0; i < dl.d_npartitions; i++) {
		ppp = &dl.d_partitions[i];
		if (ppp->p_size == 0)
			continue;
	        o = (off_t)ppp->p_offset * dl.d_secsize;

		if (o < rawoffset)
			rawoffset = 0;
	}
	
	if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset)
		printf("WARNING: %s expected rawoffset %jd, found %jd\n",
		    gp->name,
		    (intmax_t)ms->mbroffset/dl.d_secsize,
		    (intmax_t)rawoffset/dl.d_secsize);

	/* Don't munge open partitions. */
	for (i = 0; i < dl.d_npartitions; i++) {
		ppp = &dl.d_partitions[i];

	        o = (off_t)ppp->p_offset * dl.d_secsize;
		if (o == 0)
			o = rawoffset;
		error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
		    o - rawoffset,
		    (off_t)ppp->p_size * dl.d_secsize,
		     dl.d_secsize,
		    "%s%c", gp->name, 'a' + i);
		if (error)
			return (error);
	}

	/* Look good, go for it... */
	for (u = 0; u < gsp->nslice; u++) {
		ppp = &dl.d_partitions[u];
	        o = (off_t)ppp->p_offset * dl.d_secsize;
		if (o == 0)
			o = rawoffset;
		g_slice_config(gp, u, G_SLICE_CONFIG_SET,
		    o - rawoffset,
		    (off_t)ppp->p_size * dl.d_secsize,
		     dl.d_secsize,
		    "%s%c", gp->name, 'a' + u);
	}

	/* Update our softc */
	ms->ondisk = dl;
	if (label != ms->label)
		bcopy(label, ms->label, LABELSIZE);
	ms->rawoffset = rawoffset;

	/*
	 * In order to avoid recursively attaching to the same
	 * on-disk label (it's usually visible through the 'c'
	 * partition) we calculate an MD5 and ask if other BSD's
	 * below us love that label.  If they do, we don't.
	 */
	MD5Init(&md5sum);
	MD5Update(&md5sum, ms->label, sizeof(ms->label));
	MD5Final(ms->labelsum, &md5sum);

	return (0);
}
Example #5
0
/*-
 * This start routine is only called for non-trivial requests, all the
 * trivial ones are handled autonomously by the slice code.
 * For requests we handle here, we must call the g_io_deliver() on the
 * bio, and return non-zero to indicate to the slice code that we did so.
 * This code executes in the "DOWN" I/O path, this means:
 *    * No sleeping.
 *    * Don't grab the topology lock.
 *    * Don't call biowait, g_getattr(), g_setattr() or g_read_data()
 */
static int
g_bsd_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td)
{
	struct g_geom *gp;
	struct g_bsd_softc *ms;
	struct g_slicer *gsp;
	u_char *label;
	int error;

	gp = pp->geom;
	gsp = gp->softc;
	ms = gsp->softc;

	switch(cmd) {
	case DIOCGDINFO:
		/* Return a copy of the disklabel to userland. */
		bsd_disklabel_le_dec(ms->label, data, MAXPARTITIONS);
		return(0);
	case DIOCBSDBB: {
		struct g_consumer *cp;
		u_char *buf;
		void *p;
		int error, i;
		uint64_t sum;

		if (!(fflag & FWRITE))
			return (EPERM);
		/* The disklabel to set is the ioctl argument. */
		buf = g_malloc(BBSIZE, M_WAITOK);
		p = *(void **)data;
		error = copyin(p, buf, BBSIZE);
		if (!error) {
			/* XXX: Rude, but supposedly safe */
			DROP_GIANT();
			g_topology_lock();
			/* Validate and modify our slice instance to match. */
			error = g_bsd_modify(gp, buf + ms->labeloffset);
			if (!error) {
				cp = LIST_FIRST(&gp->consumer);
				if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
					sum = 0;
					for (i = 0; i < 63; i++)
						sum += le64dec(buf + i * 8);
					le64enc(buf + 504, sum);
				}
				error = g_write_data(cp, 0, buf, BBSIZE);
			}
			g_topology_unlock();
			PICKUP_GIANT();
		}
		g_free(buf);
		return (error);
	}
	case DIOCSDINFO:
	case DIOCWDINFO: {
		if (!(fflag & FWRITE))
			return (EPERM);
		label = g_malloc(LABELSIZE, M_WAITOK);
		/* The disklabel to set is the ioctl argument. */
		bsd_disklabel_le_enc(label, data);

		DROP_GIANT();
		g_topology_lock();
		/* Validate and modify our slice instance to match. */
		error = g_bsd_modify(gp, label);
		if (error == 0 && cmd == DIOCWDINFO)
			error = g_bsd_writelabel(gp, NULL);
		g_topology_unlock();
		PICKUP_GIANT();
		g_free(label);
		return(error);
	}
	default:
		return (ENOIOCTL);
	}
}