diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/geom/geom.h | 5 | ||||
-rw-r--r-- | sys/geom/geom_dev.c | 19 | ||||
-rw-r--r-- | sys/geom/geom_disk.c | 20 | ||||
-rw-r--r-- | sys/geom/geom_slice.c | 9 |
4 files changed, 53 insertions, 0 deletions
diff --git a/sys/geom/geom.h b/sys/geom/geom.h index 6dfe745..e4c37b7 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -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 * diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c index 3711fb0..b845b06 100644 --- a/sys/geom/geom_dev.c +++ b/sys/geom/geom_dev.c @@ -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); diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c index e6a2bcd..6abb492 100644 --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -99,6 +99,24 @@ g_disk_access(struct g_provider *pp, int r, int w, int e) } 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; diff --git a/sys/geom/geom_slice.c b/sys/geom/geom_slice.c index 21b514c..513ed26 100644 --- a/sys/geom/geom_slice.c +++ b/sys/geom/geom_slice.c @@ -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); |