summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/geom/geom.h5
-rw-r--r--sys/geom/geom_dev.c19
-rw-r--r--sys/geom/geom_disk.c20
-rw-r--r--sys/geom/geom_slice.c9
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);
OpenPOWER on IntegriCloud