Make kernel dumps work with GEOM.

Notice that if the device on which the dump is set is destroyed for
any reason, the dump setting is lost.  This in particular will
happen in the case of spoilage.  For instance if you set dump on
ad0s1b and open ad0 for writing, ad0s* will be spoilt and the dump
setting lost.  See geom(4) for more about spoiling.

Sponsored by: DARPA & NAI Labs.
This commit is contained in:
phk 2002-04-19 09:24:12 +00:00
parent 905cf22e4e
commit 7abca11056
4 changed files with 53 additions and 0 deletions

View File

@ -229,6 +229,11 @@ struct g_ioctl {
#ifdef _KERNEL
struct g_kerneldump {
off_t offset;
off_t length;
};
MALLOC_DECLARE(M_GEOM);
static __inline void *

View File

@ -48,6 +48,7 @@
#include <sys/disk.h>
#include <sys/fcntl.h>
#include <geom/geom.h>
#include <machine/limits.h>
#define CDEV_MAJOR 4
@ -239,7 +240,9 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
{
struct g_geom *gp;
struct g_consumer *cp;
struct g_kerneldump kd;
int i, error;
u_int u;
struct g_ioctl *gio;
gp = dev->si_drv1;
@ -265,6 +268,20 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
case DIOCGFRONTSTUFF:
error = g_io_getattr("GEOM::frontstuff", cp, &i, data);
break;
case DIOCSKERNELDUMP:
u = *((u_int *)data);
if (!u) {
set_dumper(NULL);
error = 0;
break;
}
kd.offset = 0;
kd.length = OFF_MAX;
i = sizeof kd;
error = g_io_getattr("GEOM::kerneldump", cp, &i, &kd);
if (!error)
dev->si_flags |= SI_DUMPDEV;
break;
default:
gio = g_malloc(sizeof *gio, M_WAITOK);
gio->cmd = cmd;
@ -378,6 +395,8 @@ g_dev_orphan(struct g_consumer *cp)
if (cp->biocount > 0)
return;
dev = gp->softc;
if (dev->si_flags & SI_DUMPDEV)
set_dumper(NULL);
destroy_dev(dev);
if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
g_access_rel(cp, -cp->acr, -cp->acw, -cp->ace);

View File

@ -98,6 +98,24 @@ g_disk_access(struct g_provider *pp, int r, int w, int e)
return (error);
}
static void
g_disk_kerneldump(struct bio *bp, struct disk *dp)
{
int error;
struct g_kerneldump *gkd;
struct dumperinfo di;
gkd = (struct g_kerneldump*)bp->bio_data;
printf("Kerneldump off=%lld len=%lld\n", gkd->offset, gkd->length);
di.dumper = (dumper_t *)dp->d_devsw->d_dump;
di.priv = dp->d_dev;
di.blocksize = dp->d_label.d_secsize;
di.mediaoffset = gkd->offset;
di.mediasize = gkd->length;
error = set_dumper(&di);
g_io_fail(bp, error);
}
static void
g_disk_done(struct bio *bp)
{
@ -148,6 +166,8 @@ g_disk_start(struct bio *bp)
break;
else if (g_haveattr_off_t(bp, "GEOM::frontstuff", 0))
break;
else if (!strcmp(bp->bio_attribute, "GEOM::kerneldump"))
g_disk_kerneldump(bp, dp);
else if (!strcmp(bp->bio_attribute, "GEOM::ioctl") &&
bp->bio_length == sizeof *gio) {
gio = (struct g_ioctl *)bp->bio_data;

View File

@ -173,6 +173,15 @@ g_slice_start(struct bio *bp)
g_haveattr_off_t(bp, "GEOM::frontstuff", t);
return;
}
if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
struct g_kerneldump *gkd;
gkd = (struct g_kerneldump *)bp->bio_data;
gkd->offset += gsp->slices[index].offset;
if (gkd->length > gsp->slices[index].length)
gkd->length = gsp->slices[index].length;
/* now, pass it on downwards... */
}
bp2 = g_clone_bio(bp);
bp2->bio_done = g_std_done;
g_io_request(bp2, cp);