svn commit: r333282 - in head/sys: dev/null geom kern sys
Mark Johnston
markj at FreeBSD.org
Sun May 6 00:22:39 UTC 2018
Author: markj
Date: Sun May 6 00:22:38 2018
New Revision: 333282
URL: https://svnweb.freebsd.org/changeset/base/333282
Log:
Refactor some of the MI kernel dump code in preparation for netdump.
- Add clear_dumper() to complement set_dumper().
- Drain netdump's preallocated mbuf pool when clearing the dumper.
- Don't do bounds checking for dumpers with mediasize 0.
- Add dumper callbacks for initialization for writing out headers.
Reviewed by: sbruno
MFC after: 1 month
Sponsored by: Dell EMC Isilon
Differential Revision: https://reviews.freebsd.org/D15252
Modified:
head/sys/dev/null/null.c
head/sys/geom/geom_dev.c
head/sys/kern/kern_shutdown.c
head/sys/sys/conf.h
Modified: head/sys/dev/null/null.c
==============================================================================
--- head/sys/dev/null/null.c Sun May 6 00:19:48 2018 (r333281)
+++ head/sys/dev/null/null.c Sun May 6 00:22:38 2018 (r333282)
@@ -107,14 +107,14 @@ null_ioctl(struct cdev *dev __unused, u_long cmd, cadd
int flags __unused, struct thread *td)
{
int error;
- error = 0;
+ error = 0;
switch (cmd) {
#ifdef COMPAT_FREEBSD11
case DIOCSKERNELDUMP_FREEBSD11:
#endif
case DIOCSKERNELDUMP:
- error = set_dumper(NULL, NULL, td, 0, 0, NULL, 0, NULL);
+ error = clear_dumper(td);
break;
case FIONBIO:
break;
Modified: head/sys/geom/geom_dev.c
==============================================================================
--- head/sys/geom/geom_dev.c Sun May 6 00:19:48 2018 (r333281)
+++ head/sys/geom/geom_dev.c Sun May 6 00:22:38 2018 (r333282)
@@ -138,10 +138,11 @@ g_dev_setdumpdev(struct cdev *dev, struct diocskerneld
int error, len;
if (dev == NULL || kda == NULL)
- return (set_dumper(NULL, NULL, td, 0, 0, NULL, 0, NULL));
+ return (clear_dumper(td));
cp = dev->si_drv2;
len = sizeof(kd);
+ memset(&kd, 0, len);
kd.offset = 0;
kd.length = OFF_MAX;
error = g_io_getattr("GEOM::kerneldump", cp, &len, &kd);
@@ -833,7 +834,7 @@ g_dev_orphan(struct g_consumer *cp)
/* Reset any dump-area set on this device */
if (dev->si_flags & SI_DUMPDEV)
- (void)set_dumper(NULL, NULL, curthread, 0, 0, NULL, 0, NULL);
+ (void)clear_dumper(curthread);
/* Destroy the struct cdev *so we get no more requests */
destroy_dev_sched_cb(dev, g_dev_callback, cp);
Modified: head/sys/kern/kern_shutdown.c
==============================================================================
--- head/sys/kern/kern_shutdown.c Sun May 6 00:19:48 2018 (r333281)
+++ head/sys/kern/kern_shutdown.c Sun May 6 00:22:38 2018 (r333282)
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kthread.h>
#include <sys/ktr.h>
#include <sys/malloc.h>
+#include <sys/mbuf.h>
#include <sys/mount.h>
#include <sys/priv.h>
#include <sys/proc.h>
@@ -1090,10 +1091,6 @@ set_dumper(struct dumperinfo *di, const char *devname,
if (error != 0)
return (error);
- if (di == NULL) {
- error = 0;
- goto cleanup;
- }
if (dumper.dumper != NULL)
return (EBUSY);
dumper = *di;
@@ -1139,7 +1136,25 @@ set_dumper(struct dumperinfo *di, const char *devname,
dumper.blockbuf = malloc(di->blocksize, M_DUMPER, M_WAITOK | M_ZERO);
return (0);
+
cleanup:
+ (void)clear_dumper(td);
+ return (error);
+}
+
+int
+clear_dumper(struct thread *td)
+{
+ int error;
+
+ error = priv_check(td, PRIV_SETDUMPER);
+ if (error != 0)
+ return (error);
+
+#ifdef NETDUMP
+ netdump_mbuf_drain();
+#endif
+
#ifdef EKCD
if (dumper.kdcrypto != NULL) {
explicit_bzero(dumper.kdcrypto, sizeof(*dumper.kdcrypto) +
@@ -1156,14 +1171,14 @@ cleanup:
}
explicit_bzero(&dumper, sizeof(dumper));
dumpdevname[0] = '\0';
- return (error);
+ return (0);
}
static int
dump_check_bounds(struct dumperinfo *di, off_t offset, size_t length)
{
- if (length != 0 && (offset < di->mediaoffset ||
+ if (di->mediasize > 0 && length != 0 && (offset < di->mediaoffset ||
offset - di->mediaoffset + length > di->mediasize)) {
if (di->kdcomp != NULL && offset >= di->mediaoffset) {
printf(
@@ -1244,18 +1259,6 @@ dump_encrypted_write(struct dumperinfo *di, void *virt
return (0);
}
-
-static int
-dump_write_key(struct dumperinfo *di, off_t offset)
-{
- struct kerneldumpcrypto *kdc;
-
- kdc = di->kdcrypto;
- if (kdc == NULL)
- return (0);
- return (dump_write(di, kdc->kdc_dumpkey, 0, offset,
- kdc->kdc_dumpkeysize));
-}
#endif /* EKCD */
static int
@@ -1289,20 +1292,42 @@ kerneldumpcomp_write_cb(void *base, size_t length, off
}
/*
- * Write a kerneldumpheader at the specified offset. The header structure is 512
- * bytes in size, but we must pad to the device sector size.
+ * Write kernel dump headers at the beginning and end of the dump extent.
+ * Write the kernel dump encryption key after the leading header if we were
+ * configured to do so.
*/
static int
-dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh,
- off_t offset)
+dump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
- void *buf;
+#ifdef EKCD
+ struct kerneldumpcrypto *kdc;
+#endif
+ void *buf, *key;
size_t hdrsz;
+ uint64_t extent;
+ uint32_t keysize;
+ int error;
hdrsz = sizeof(*kdh);
if (hdrsz > di->blocksize)
return (ENOMEM);
+#ifdef EKCD
+ kdc = di->kdcrypto;
+ key = kdc->kdc_dumpkey;
+ keysize = kerneldumpcrypto_dumpkeysize(kdc);
+#else
+ key = NULL;
+ keysize = 0;
+#endif
+
+ /*
+ * If the dump device has special handling for headers, let it take care
+ * of writing them out.
+ */
+ if (di->dumper_hdr != NULL)
+ return (di->dumper_hdr(di, kdh, key, keysize));
+
if (hdrsz == di->blocksize)
buf = kdh;
else {
@@ -1311,7 +1336,24 @@ dump_write_header(struct dumperinfo *di, struct kernel
memcpy(buf, kdh, hdrsz);
}
- return (dump_write(di, buf, 0, offset, di->blocksize));
+ extent = dtoh64(kdh->dumpextent);
+#ifdef EKCD
+ if (kdc != NULL) {
+ error = dump_write(di, kdc->kdc_dumpkey, 0,
+ di->mediaoffset + di->mediasize - di->blocksize - extent -
+ keysize, keysize);
+ if (error != 0)
+ return (error);
+ }
+#endif
+
+ error = dump_write(di, buf, 0,
+ di->mediaoffset + di->mediasize - 2 * di->blocksize - extent -
+ keysize, di->blocksize);
+ if (error == 0)
+ error = dump_write(di, buf, 0, di->mediaoffset + di->mediasize -
+ di->blocksize, di->blocksize);
+ return (error);
}
/*
@@ -1336,26 +1378,37 @@ dump_write_header(struct dumperinfo *di, struct kernel
* Uncompressed dumps will use the entire extent, but compressed dumps typically
* will not. The true length of the dump is recorded in the leading and trailing
* headers once the dump has been completed.
+ *
+ * The dump device may provide a callback, in which case it will initialize
+ * dumpoff and take care of laying out the headers.
*/
int
dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
- uint64_t dumpextent;
+ uint64_t dumpextent, span;
uint32_t keysize;
+ int error;
#ifdef EKCD
- int error = kerneldumpcrypto_init(di->kdcrypto);
+ error = kerneldumpcrypto_init(di->kdcrypto);
if (error != 0)
return (error);
keysize = kerneldumpcrypto_dumpkeysize(di->kdcrypto);
#else
+ error = 0;
keysize = 0;
#endif
- dumpextent = dtoh64(kdh->dumpextent);
- if (di->mediasize < SIZEOF_METADATA + dumpextent + 2 * di->blocksize +
- keysize) {
- if (di->kdcomp != NULL) {
+ if (di->dumper_start != NULL) {
+ error = di->dumper_start(di);
+ } else {
+ dumpextent = dtoh64(kdh->dumpextent);
+ span = SIZEOF_METADATA + dumpextent + 2 * di->blocksize +
+ keysize;
+ if (di->mediasize < span) {
+ if (di->kdcomp == NULL)
+ return (E2BIG);
+
/*
* We don't yet know how much space the compressed dump
* will occupy, so try to use the whole swap partition
@@ -1364,18 +1417,18 @@ dump_start(struct dumperinfo *di, struct kerneldumphea
* be enough, the bounds checking in dump_write()
* will catch us and cause the dump to fail.
*/
- dumpextent = di->mediasize - SIZEOF_METADATA -
- 2 * di->blocksize - keysize;
+ dumpextent = di->mediasize - span + dumpextent;
kdh->dumpextent = htod64(dumpextent);
- } else
- return (E2BIG);
- }
+ }
- /* The offset at which to begin writing the dump. */
- di->dumpoff = di->mediaoffset + di->mediasize - di->blocksize -
- dumpextent;
-
- return (0);
+ /*
+ * The offset at which to begin writing the dump.
+ */
+ di->dumpoff = di->mediaoffset + di->mediasize - di->blocksize -
+ dumpextent;
+ }
+ di->origdumpoff = di->dumpoff;
+ return (error);
}
static int
@@ -1443,17 +1496,10 @@ int
dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
uint64_t extent;
- uint32_t keysize;
int error;
extent = dtoh64(kdh->dumpextent);
-#ifdef EKCD
- keysize = kerneldumpcrypto_dumpkeysize(di->kdcrypto);
-#else
- keysize = 0;
-#endif
-
if (di->kdcomp != NULL) {
error = compressor_flush(di->kdcomp->kdc_stream);
if (error == EAGAIN) {
@@ -1470,33 +1516,14 @@ dump_finish(struct dumperinfo *di, struct kerneldumphe
* We now know the size of the compressed dump, so update the
* header accordingly and recompute parity.
*/
- kdh->dumplength = htod64(di->dumpoff -
- (di->mediaoffset + di->mediasize - di->blocksize - extent));
+ kdh->dumplength = htod64(di->dumpoff - di->origdumpoff);
kdh->parity = 0;
kdh->parity = kerneldump_parity(kdh);
compressor_reset(di->kdcomp->kdc_stream);
}
- /*
- * Write kerneldump headers at the beginning and end of the dump extent.
- * Write the key after the leading header.
- */
- error = dump_write_header(di, kdh,
- di->mediaoffset + di->mediasize - 2 * di->blocksize - extent -
- keysize);
- if (error != 0)
- return (error);
-
-#ifdef EKCD
- error = dump_write_key(di,
- di->mediaoffset + di->mediasize - di->blocksize - extent - keysize);
- if (error != 0)
- return (error);
-#endif
-
- error = dump_write_header(di, kdh,
- di->mediaoffset + di->mediasize - di->blocksize);
+ error = dump_write_headers(di, kdh);
if (error != 0)
return (error);
Modified: head/sys/sys/conf.h
==============================================================================
--- head/sys/sys/conf.h Sun May 6 00:19:48 2018 (r333281)
+++ head/sys/sys/conf.h Sun May 6 00:22:38 2018 (r333282)
@@ -101,6 +101,8 @@ struct cdev {
struct bio;
struct buf;
+struct dumperinfo;
+struct kerneldumpheader;
struct thread;
struct uio;
struct knote;
@@ -131,6 +133,9 @@ typedef int dumper_t(
vm_offset_t _physical, /* Physical address of virtual. */
off_t _offset, /* Byte-offset to write at. */
size_t _length); /* Number of bytes to dump. */
+typedef int dumper_start_t(struct dumperinfo *di);
+typedef int dumper_hdr_t(struct dumperinfo *di, struct kerneldumpheader *kdh,
+ void *key, uint32_t keylen);
#endif /* _KERNEL */
@@ -332,13 +337,18 @@ struct kerneldumpheader;
struct dumperinfo {
dumper_t *dumper; /* Dumping function. */
+ dumper_start_t *dumper_start; /* Dumper callback for dump_start(). */
+ dumper_hdr_t *dumper_hdr; /* Dumper callback for writing headers. */
void *priv; /* Private parts. */
u_int blocksize; /* Size of block in bytes. */
u_int maxiosize; /* Max size allowed for an individual I/O */
off_t mediaoffset; /* Initial offset in bytes. */
off_t mediasize; /* Space available in bytes. */
+
+ /* MI kernel dump state. */
void *blockbuf; /* Buffer for padding shorter dump blocks */
off_t dumpoff; /* Offset of ongoing kernel dump. */
+ off_t origdumpoff; /* Starting dump offset. */
struct kerneldumpcrypto *kdcrypto; /* Kernel dump crypto. */
struct kerneldumpcomp *kdcomp; /* Kernel dump compression. */
};
@@ -349,6 +359,7 @@ int doadump(boolean_t);
int set_dumper(struct dumperinfo *di, const char *devname, struct thread *td,
uint8_t compression, uint8_t encryption, const uint8_t *key,
uint32_t encryptedkeysize, const uint8_t *encryptedkey);
+int clear_dumper(struct thread *td);
int dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh);
int dump_append(struct dumperinfo *, void *, vm_offset_t, size_t);
More information about the svn-src-head
mailing list