Пример #1
0
/*
 * If the user tries to overwrite our disklabel through an open partition
 * or via a magicwrite config call, we end up here and try to prevent
 * footshooting as best we can.
 */
static void
g_bsd_hotwrite(void *arg, int flag)
{
	struct bio *bp;
	struct g_geom *gp;
	struct g_slicer *gsp;
	struct g_slice *gsl;
	struct g_bsd_softc *ms;
	u_char *p;
	int error;
	
	g_topology_assert();
	/*
	 * We should never get canceled, because that would amount to a removal
	 * of the geom while there was outstanding I/O requests.
	 */
	KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled"));
	bp = arg;
	gp = bp->bio_to->geom;
	gsp = gp->softc;
	ms = gsp->softc;
	gsl = &gsp->slices[bp->bio_to->index];
	p = (u_char*)bp->bio_data + ms->labeloffset -
	    (bp->bio_offset + gsl->offset);
	error = g_bsd_modify(gp, p);
	if (error) {
		g_io_deliver(bp, EPERM);
		return;
	}
	g_slice_finish_hot(bp);
}
Пример #2
0
static void
g_bsd_callconfig(void *arg, int flag)
{
	struct h0h0 *hp;

	hp = arg;
	hp->error = g_bsd_modify(hp->gp, hp->label);
	if (!hp->error)
		hp->error = g_bsd_writelabel(hp->gp, NULL);
}
Пример #3
0
static struct g_geom *
g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags)
{
	struct g_geom *gp;
	struct g_consumer *cp;
	int error, i;
	struct g_bsd_softc *ms;
	u_int secsize;
	struct g_slicer *gsp;
	u_char hash[16];
	MD5_CTX md5sum;
	struct uuid uuid;

	g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name);
	g_topology_assert();

	/* We don't implement transparent inserts. */
	if (flags == G_TF_TRANSPARENT)
		return (NULL);

	/*
	 * BSD labels are a subclass of the general "slicing" topology so
	 * a lot of the work can be done by the common "slice" code.
	 * Create a geom with space for MAXPARTITIONS providers, one consumer
	 * and a softc structure for us.  Specify the provider to attach
	 * the consumer to and our "start" routine for special requests.
	 * The provider is opened with mode (1,0,0) so we can do reads
	 * from it.
	 */
	gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms,
	     sizeof(*ms), g_bsd_start);
	if (gp == NULL)
		return (NULL);

	/* Get the geom_slicer softc from the geom. */
	gsp = gp->softc;

	/*
	 * The do...while loop here allows us to have multiple escapes
	 * using a simple "break".  This improves code clarity without
	 * ending up in deep nesting and without using goto or come from.
	 */
	do {
		/*
		 * If the provider is an MBR we will only auto attach
		 * to type 165 slices in the G_TF_NORMAL case.  We will
		 * attach to any other type.
		 */
		error = g_getattr("MBR::type", cp, &i);
		if (!error) {
			if (i != 165 && flags == G_TF_NORMAL)
				break;
			error = g_getattr("MBR::offset", cp, &ms->mbroffset);
			if (error)
				break;
		}

		/* Same thing if we are inside a PC98 */
		error = g_getattr("PC98::type", cp, &i);
		if (!error) {
			if (i != 0xc494 && flags == G_TF_NORMAL)
				break;
			error = g_getattr("PC98::offset", cp, &ms->mbroffset);
			if (error)
				break;
		}

		/* Same thing if we are inside a GPT */
		error = g_getattr("GPT::type", cp, &uuid);
		if (!error) {
			if (memcmp(&uuid, &freebsd_slice, sizeof(uuid)) != 0 &&
			    flags == G_TF_NORMAL)
				break;
		}

		/* Get sector size, we need it to read data. */
		secsize = cp->provider->sectorsize;
		if (secsize < 512)
			break;

		/* First look for a label at the start of the second sector. */
		error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize);

		/*
		 * If sector size is not 512 the label still can be at
		 * offset 512, not at the start of the second sector. At least
		 * it's true for labels created by the FreeBSD's bsdlabel(8).
		 */
		if (error && secsize != HISTORIC_LABEL_OFFSET)
			error = g_bsd_try(gp, gsp, cp, secsize, ms,
			    HISTORIC_LABEL_OFFSET);

		/* Next, look for alpha labels */
		if (error)
			error = g_bsd_try(gp, gsp, cp, secsize, ms,
			    ALPHA_LABEL_OFFSET);

		/* If we didn't find a label, punt. */
		if (error)
			break;

		/*
		 * 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);

		error = g_getattr("BSD::labelsum", cp, &hash);
		if (!error && !bcmp(ms->labelsum, hash, sizeof(hash)))
			break;

		/*
		 * Process the found disklabel, and modify our "slice"
		 * instance to match it, if possible.
		 */
		error = g_bsd_modify(gp, ms->label);
	} while (0);

	/* Success or failure, we can close our provider now. */
	g_access(cp, -1, 0, 0);

	/* If we have configured any providers, return the new geom. */
	if (gsp->nprovider > 0) {
		g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE,
		    G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL);
		gsp->hot = g_bsd_hotwrite;
		return (gp);
	}
	/*
	 * ...else push the "self-destruct" button, by spoiling our own
	 * consumer.  This triggers a call to g_slice_spoiled which will
	 * dismantle what was setup.
	 */
	g_slice_spoiled(cp);
	return (NULL);
}
Пример #4
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);
	}
}