Implement DIOCBSDBB ioctl which overwrites first BBSIZE bytes of BSD
labeled disk. This is complicated by the fact that BBSIZE is greater than the PAGE_SIZE limit ioctl inflicts on arguments which are automatically copied in. As long as we don't need access to userland memory (copyin/out) we can deal with the ioctl using g_callme() which executes it from the GEOM event thread. Once we need copyin/out, we need to return the bio with EDIRIOCTL in order to make geom_dev call us back in the original process context where copyin will work. Unfortunately, that results in us getting called with Giant, so we have to DROP_GIANT/PICKUP_GIANT around the code where we diddle GEOMs internals. Sometimes you just can't win... ... But it does make geom_bsd.c an almost complete example of the GEOM beastiarium.
This commit is contained in:
parent
afdc2f6786
commit
7253da9c05
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=109900
@ -546,6 +546,63 @@ g_bsd_ioctl(void *arg)
|
||||
g_io_deliver(bp, error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewrite the bootblock, which is BBSIZE bytes from the start of the disk.
|
||||
* We punch down the disklabel where we expect it to be before writing.
|
||||
*/
|
||||
static int
|
||||
g_bsd_diocbsdbb(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
|
||||
{
|
||||
struct g_geom *gp;
|
||||
struct g_slicer *gsp;
|
||||
struct g_bsd_softc *ms;
|
||||
struct disklabel *dl;
|
||||
struct g_consumer *cp;
|
||||
u_char *buf;
|
||||
void *p;
|
||||
u_int secsize;
|
||||
int error, i;
|
||||
uint64_t sum;
|
||||
|
||||
/* Get hold of the interesting bits from the bio. */
|
||||
gp = (void *)dev;
|
||||
gsp = gp->softc;
|
||||
ms = gsp->softc;
|
||||
|
||||
/* The disklabel to set is the ioctl argument. */
|
||||
buf = g_malloc(BBSIZE, 0);
|
||||
p = *(void **)data;
|
||||
error = copyin(p, buf, BBSIZE);
|
||||
if (error) {
|
||||
g_free(buf);
|
||||
return (error);
|
||||
}
|
||||
/* The disklabel to set is the ioctl argument. */
|
||||
dl = (void *)(buf + ms->labeloffset);
|
||||
|
||||
DROP_GIANT();
|
||||
|
||||
/* Validate and modify our slice instance to match. */
|
||||
error = g_bsd_modify(gp, dl); /* Picks up topology lock on success. */
|
||||
if (!error) {
|
||||
cp = LIST_FIRST(&gp->consumer);
|
||||
secsize = cp->provider->sectorsize;
|
||||
dl = &ms->ondisk;
|
||||
g_bsd_leenc_disklabel(buf + ms->labeloffset, dl);
|
||||
if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
|
||||
sum = 0;
|
||||
for (i = 0; i < 63; i++)
|
||||
sum += g_dec_le8(buf + i * 8);
|
||||
g_enc_le8(buf + 504, sum);
|
||||
}
|
||||
error = g_write_data(cp, 0, buf, BBSIZE);
|
||||
g_topology_unlock();
|
||||
}
|
||||
g_free(buf);
|
||||
PICKUP_GIANT();
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -655,6 +712,11 @@ g_bsd_start(struct bio *bp)
|
||||
bcopy(&ms->inram, gio->data, sizeof(ms->inram));
|
||||
g_io_deliver(bp, 0);
|
||||
return (1);
|
||||
case DIOCBSDBB:
|
||||
gio->func = g_bsd_diocbsdbb;
|
||||
gio->dev = (void *)gp;
|
||||
g_io_deliver(bp, EDIRIOCTL);
|
||||
return (1);
|
||||
case DIOCSDINFO:
|
||||
case DIOCWDINFO:
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user