Page MenuHomeFreeBSD

D11723.id34309.diff
No OneTemporary

D11723.id34309.diff

Index: head/etc/defaults/rc.conf
===================================================================
--- head/etc/defaults/rc.conf
+++ head/etc/defaults/rc.conf
@@ -596,9 +596,8 @@
chkprintcap_enable="NO" # Run chkprintcap(8) before running lpd.
chkprintcap_flags="-d" # Create missing directories by default.
dumpdev="AUTO" # Device to crashdump to (device name, AUTO, or NO).
+dumpon_flags="" # Options to pass to dumpon(8), followed by dumpdev.
dumpdir="/var/crash" # Directory where crash dumps are to be stored
-dumppubkey="" # Public key for encrypted kernel crash dumps.
- # See dumpon(8) for more details.
savecore_enable="YES" # Extract core from dump devices if any
savecore_flags="-m 10" # Used if dumpdev is enabled above, and present.
# By default, only the 10 most recent kernel dumps
Index: head/etc/rc.d/dumpon
===================================================================
--- head/etc/rc.d/dumpon
+++ head/etc/rc.d/dumpon
@@ -16,11 +16,14 @@
dumpon_try()
{
+ local flags
+
+ flags=${dumpon_flags}
if [ -n "${dumppubkey}" ]; then
- /sbin/dumpon -k "${dumppubkey}" "${1}"
- else
- /sbin/dumpon "${1}"
+ warn "The dumppubkey variable is deprecated. Use dumpon_flags."
+ flags="${flags} -k ${dumppubkey}"
fi
+ /sbin/dumpon ${flags} "${1}"
if [ $? -eq 0 ]; then
# Make a symlink in devfs for savecore
ln -fs "${1}" /dev/dumpdev
Index: head/sbin/dumpon/dumpon.8
===================================================================
--- head/sbin/dumpon/dumpon.8
+++ head/sbin/dumpon/dumpon.8
@@ -28,7 +28,7 @@
.\" From: @(#)swapon.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd December 10, 2016
+.Dd October 24, 2017
.Dt DUMPON 8
.Os
.Sh NAME
@@ -38,6 +38,7 @@
.Nm
.Op Fl v
.Op Fl k Ar public_key_file
+.Op Fl z
.Ar special_file
.Nm
.Op Fl v
@@ -114,6 +115,22 @@
kernel option.
.Pp
The
+.Fl z
+option configures the kernel to compress the dump in gzip format before writing
+it to the dump device.
+This reduces the amount of space required for the dump and accelerates
+recovery with
+.Xr savecore 8
+since less data needs to be copied from the dump device.
+When compression is enabled, the
+.Nm
+utility will not verify that the dump device is sufficiently large for a full
+dump.
+This flag requires a kernel compiled with the
+.Dv GZIO
+kernel option.
+.Pp
+The
.Fl l
flag causes
.Nm
@@ -272,3 +289,7 @@
.Sh BUGS
Because the file system layer is already dead by the time a crash dump
is taken, it is not possible to send crash dumps directly to a file.
+.Pp
+It is currently not possible to configure both compression and encryption.
+The encrypted dump format assumes that the kernel dump size is a multiple
+of the cipher block size, which may not be true when the dump is compressed.
Index: head/sbin/dumpon/dumpon.c
===================================================================
--- head/sbin/dumpon/dumpon.c
+++ head/sbin/dumpon/dumpon.c
@@ -71,7 +71,7 @@
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n",
- "usage: dumpon [-v] [-k public_key_file] special_file",
+ "usage: dumpon [-v] [-k public_key_file] [-z] special_file",
" dumpon [-v] off",
" dumpon [-v] -l");
exit(EX_USAGE);
@@ -190,11 +190,12 @@
int ch;
int i, fd;
int do_listdumpdev = 0;
- bool enable;
+ bool enable, gzip;
+ gzip = false;
pubkeyfile = NULL;
- while ((ch = getopt(argc, argv, "k:lv")) != -1)
+ while ((ch = getopt(argc, argv, "k:lvz")) != -1)
switch((char)ch) {
case 'k':
pubkeyfile = optarg;
@@ -205,6 +206,9 @@
case 'v':
verbose = 1;
break;
+ case 'z':
+ gzip = true;
+ break;
default:
usage();
}
@@ -247,9 +251,11 @@
fd = open(dumpdev, O_RDONLY);
if (fd < 0)
err(EX_OSFILE, "%s", dumpdev);
- check_size(fd, dumpdev);
- bzero(&kda, sizeof(kda));
+ if (!gzip)
+ check_size(fd, dumpdev);
+
+ bzero(&kda, sizeof(kda));
kda.kda_enable = 0;
i = ioctl(fd, DIOCSKERNELDUMP, &kda);
explicit_bzero(&kda, sizeof(kda));
@@ -260,6 +266,8 @@
#endif
kda.kda_enable = 1;
+ kda.kda_compression = gzip ? KERNELDUMP_COMP_GZIP :
+ KERNELDUMP_COMP_NONE;
i = ioctl(fd, DIOCSKERNELDUMP, &kda);
explicit_bzero(kda.kda_encryptedkey, kda.kda_encryptedkeysize);
free(kda.kda_encryptedkey);
Index: head/sbin/savecore/savecore.8
===================================================================
--- head/sbin/savecore/savecore.8
+++ head/sbin/savecore/savecore.8
@@ -28,7 +28,7 @@
.\" From: @(#)savecore.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd December 10, 2016
+.Dd October 24, 2017
.Dt SAVECORE 8
.Os
.Sh NAME
@@ -96,8 +96,12 @@
Print out some additional debugging information.
Specify twice for more information.
.It Fl z
-Compress the core dump and kernel (see
+Compress the dump (see
.Xr gzip 1 ) .
+The dump may already be compressed if the kernel was configured to
+do so by
+.Xr dumpon 8 .
+In this case, the option has no effect.
.El
.Pp
The
Index: head/sbin/savecore/savecore.c
===================================================================
--- head/sbin/savecore/savecore.c
+++ head/sbin/savecore/savecore.c
@@ -121,6 +121,9 @@
(long long)dumplen);
xo_emit_h(xo, "{P: }{Lwc:Blocksize}{:blocksize/%d}\n",
dtoh32(h->blocksize));
+ xo_emit_h(xo, "{P: }{Lwc:Compression}{:compression/%s}\n",
+ h->compression == KERNELDUMP_COMP_GZIP ?
+ "gzip" : "none");
t = dtoh64(h->dumptime);
xo_emit_h(xo, "{P: }{Lwc:Dumptime}{:dumptime/%s}", ctime(&t));
@@ -357,7 +360,7 @@
#define BLOCKMASK (~(BLOCKSIZE-1))
static int
-DoRegularFile(int fd, bool isencrypted, off_t dumpsize, char *buf,
+DoRegularFile(int fd, off_t dumpsize, u_int sectorsize, bool sparse, char *buf,
const char *device, const char *filename, FILE *fp)
{
int he, hs, nr, nw, wl;
@@ -370,8 +373,8 @@
wl = BUFFERSIZE;
if (wl > dumpsize)
wl = dumpsize;
- nr = read(fd, buf, wl);
- if (nr != wl) {
+ nr = read(fd, buf, roundup(wl, sectorsize));
+ if (nr != (int)roundup(wl, sectorsize)) {
if (nr == 0)
syslog(LOG_WARNING,
"WARNING: EOF on dump device");
@@ -380,7 +383,7 @@
nerr++;
return (-1);
}
- if (compress || isencrypted) {
+ if (!sparse) {
nw = fwrite(buf, 1, wl, fp);
} else {
for (nw = 0; nw < nr; nw = he) {
@@ -506,15 +509,14 @@
char *temp = NULL;
struct kerneldumpheader kdhf, kdhl;
uint8_t *dumpkey;
- off_t mediasize, dumpsize, firsthd, lasthd;
+ off_t mediasize, dumpextent, dumplength, firsthd, lasthd;
FILE *info, *fp;
mode_t oumask;
int fd, fdinfo, error;
int bounds, status;
u_int sectorsize, xostyle;
- int istextdump;
uint32_t dumpkeysize;
- bool isencrypted, ret;
+ bool iscompressed, isencrypted, istextdump, ret;
bounds = getbounds();
dumpkey = NULL;
@@ -582,12 +584,12 @@
goto closefd;
}
memcpy(&kdhl, temp, sizeof(kdhl));
- istextdump = 0;
+ iscompressed = istextdump = false;
if (compare_magic(&kdhl, TEXTDUMPMAGIC)) {
if (verbose)
printf("textdump magic on last dump header on %s\n",
device);
- istextdump = 1;
+ istextdump = true;
if (dtoh32(kdhl.version) != KERNELDUMP_TEXT_VERSION) {
syslog(LOG_ERR,
"unknown version (%d) in last dump header on %s",
@@ -607,6 +609,20 @@
if (force == 0)
goto closefd;
}
+ switch (kdhl.compression) {
+ case KERNELDUMP_COMP_NONE:
+ break;
+ case KERNELDUMP_COMP_GZIP:
+ if (compress && verbose)
+ printf("dump is already compressed\n");
+ compress = false;
+ iscompressed = true;
+ break;
+ default:
+ syslog(LOG_ERR, "unknown compression type %d on %s",
+ kdhl.compression, device);
+ break;
+ }
} else {
if (verbose)
printf("magic mismatch on last dump header on %s\n",
@@ -619,8 +635,7 @@
if (compare_magic(&kdhl, KERNELDUMPMAGIC_CLEARED)) {
if (verbose)
printf("forcing magic on %s\n", device);
- memcpy(kdhl.magic, KERNELDUMPMAGIC,
- sizeof kdhl.magic);
+ memcpy(kdhl.magic, KERNELDUMPMAGIC, sizeof(kdhl.magic));
} else {
syslog(LOG_ERR, "unable to force dump - bad magic");
goto closefd;
@@ -648,9 +663,10 @@
if (force == 0)
goto closefd;
}
- dumpsize = dtoh64(kdhl.dumplength);
+ dumpextent = dtoh64(kdhl.dumpextent);
+ dumplength = dtoh64(kdhl.dumplength);
dumpkeysize = dtoh32(kdhl.dumpkeysize);
- firsthd = lasthd - dumpsize - sectorsize - dumpkeysize;
+ firsthd = lasthd - dumpextent - sectorsize - dumpkeysize;
if (lseek(fd, firsthd, SEEK_SET) != firsthd ||
read(fd, temp, sectorsize) != (ssize_t)sectorsize) {
syslog(LOG_ERR,
@@ -696,7 +712,7 @@
if (verbose)
printf("Checking for available free space\n");
- if (!check_space(savedir, dumpsize, bounds)) {
+ if (!check_space(savedir, dumplength, bounds)) {
nerr++;
goto closefd;
}
@@ -724,6 +740,9 @@
istextdump ? "textdump.tar" :
(isencrypted ? "vmcore_encrypted" : "vmcore"), bounds);
fp = zopen(corename, "w");
+ } else if (iscompressed && !isencrypted) {
+ snprintf(corename, sizeof(corename), "vmcore.%d.gz", bounds);
+ fp = fopen(corename, "w");
} else {
snprintf(corename, sizeof(corename), "%s.%d",
istextdump ? "textdump.tar" :
@@ -792,11 +811,12 @@
savedir, corename);
if (istextdump) {
- if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device,
+ if (DoTextdumpFile(fd, dumplength, lasthd, buf, device,
corename, fp) < 0)
goto closeall;
} else {
- if (DoRegularFile(fd, isencrypted, dumpsize, buf, device,
+ if (DoRegularFile(fd, dumplength, sectorsize,
+ !(compress || iscompressed || isencrypted), buf, device,
corename, fp) < 0) {
goto closeall;
}
@@ -822,7 +842,7 @@
"key.last");
}
}
- if (compress) {
+ if (compress || iscompressed) {
snprintf(linkname, sizeof(linkname), "%s.last.gz",
istextdump ? "textdump.tar" :
(isencrypted ? "vmcore_encrypted" : "vmcore"));
Index: head/share/man/man5/rc.conf.5
===================================================================
--- head/share/man/man5/rc.conf.5
+++ head/share/man/man5/rc.conf.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 26, 2017
+.Dd October 24, 2017
.Dt RC.CONF 5
.Os
.Sh NAME
@@ -3380,6 +3380,13 @@
.Xr dumpon 8 .
To disable crash dumps, set this variable to
.Dq Li NO .
+.It Va dumpon_flags
+.Pq Vt str
+Flags to pass to
+.Xr dumpon 8
+when configuring
+.Va dumpdev
+as the system dump device.
.It Va dumpdir
.Pq Vt str
When the system reboots after a crash and a crash dump is found on the
@@ -3400,18 +3407,6 @@
at boot time when
.Va dumpdir
is set.
-.It Va dumppubkey
-.Pq Vt str
-Path to a public key.
-It is used by
-.Xr dumpon 8
-to encrypt a one-time key for a crash dump.
-The public key has to match a private key used by
-.Xr decryptcore 8
-to decrypt a crash dump after reboot.
-See
-.Xr dumpon 8
-for more details.
.It Va savecore_enable
.Pq Vt bool
If set to
Index: head/sys/dev/null/null.c
===================================================================
--- head/sys/dev/null/null.c
+++ head/sys/dev/null/null.c
@@ -114,7 +114,7 @@
case DIOCSKERNELDUMP_FREEBSD11:
#endif
case DIOCSKERNELDUMP:
- error = set_dumper(NULL, NULL, td, 0, NULL, 0, NULL);
+ error = set_dumper(NULL, NULL, td, 0, 0, NULL, 0, NULL);
break;
case FIONBIO:
break;
Index: head/sys/geom/geom_dev.c
===================================================================
--- head/sys/geom/geom_dev.c
+++ head/sys/geom/geom_dev.c
@@ -138,7 +138,7 @@
int error, len;
if (dev == NULL || kda == NULL)
- return (set_dumper(NULL, NULL, td, 0, NULL, 0, NULL));
+ return (set_dumper(NULL, NULL, td, 0, 0, NULL, 0, NULL));
cp = dev->si_drv2;
len = sizeof(kd);
@@ -148,8 +148,9 @@
if (error != 0)
return (error);
- error = set_dumper(&kd.di, devtoname(dev), td, kda->kda_encryption,
- kda->kda_key, kda->kda_encryptedkeysize, kda->kda_encryptedkey);
+ error = set_dumper(&kd.di, devtoname(dev), td, kda->kda_compression,
+ kda->kda_encryption, kda->kda_key, kda->kda_encryptedkeysize,
+ kda->kda_encryptedkey);
if (error == 0)
dev->si_flags |= SI_DUMPDEV;
@@ -832,7 +833,7 @@
/* Reset any dump-area set on this device */
if (dev->si_flags & SI_DUMPDEV)
- (void)set_dumper(NULL, NULL, curthread, 0, NULL, 0, NULL);
+ (void)set_dumper(NULL, NULL, curthread, 0, 0, NULL, 0, NULL);
/* Destroy the struct cdev *so we get no more requests */
destroy_dev_sched_cb(dev, g_dev_callback, cp);
Index: head/sys/kern/kern_gzio.c
===================================================================
--- head/sys/kern/kern_gzio.c
+++ head/sys/kern/kern_gzio.c
@@ -60,7 +60,6 @@
gzio_init(gzio_cb cb, enum gzio_mode mode, size_t bufsz, int level, void *arg)
{
struct gzio_stream *s;
- uint8_t *hdr;
int error;
if (bufsz < KERN_GZ_HDRLEN)
@@ -72,7 +71,6 @@
s->gz_bufsz = bufsz;
s->gz_buffer = gz_alloc(NULL, 1, s->gz_bufsz);
s->gz_mode = mode;
- s->gz_crc = ~0U;
s->gz_cb = cb;
s->gz_arg = arg;
@@ -87,6 +85,26 @@
if (error != 0)
goto fail;
+ gzio_reset(s);
+
+ return (s);
+
+fail:
+ gz_free(NULL, s->gz_buffer);
+ gz_free(NULL, s);
+ return (NULL);
+}
+
+void
+gzio_reset(struct gzio_stream *s)
+{
+ uint8_t *hdr;
+
+ (void)deflateReset(&s->gz_stream);
+
+ s->gz_off = 0;
+ s->gz_crc = ~0U;
+
s->gz_stream.avail_out = s->gz_bufsz;
s->gz_stream.next_out = s->gz_buffer;
@@ -99,13 +117,6 @@
hdr[9] = OS_CODE;
s->gz_stream.next_out += KERN_GZ_HDRLEN;
s->gz_stream.avail_out -= KERN_GZ_HDRLEN;
-
- return (s);
-
-fail:
- gz_free(NULL, s->gz_buffer);
- gz_free(NULL, s);
- return (NULL);
}
int
Index: head/sys/kern/kern_shutdown.c
===================================================================
--- head/sys/kern/kern_shutdown.c
+++ head/sys/kern/kern_shutdown.c
@@ -39,6 +39,7 @@
#include "opt_ddb.h"
#include "opt_ekcd.h"
+#include "opt_gzio.h"
#include "opt_kdb.h"
#include "opt_panic.h"
#include "opt_sched.h"
@@ -52,6 +53,7 @@
#include <sys/cons.h>
#include <sys/eventhandler.h>
#include <sys/filedesc.h>
+#include <sys/gzio.h>
#include <sys/jail.h>
#include <sys/kdb.h>
#include <sys/kernel.h>
@@ -162,6 +164,24 @@
};
#endif
+#ifdef GZIO
+struct kerneldumpgz {
+ struct gzio_stream *kdgz_stream;
+ uint8_t *kdgz_buf;
+ size_t kdgz_resid;
+};
+
+static struct kerneldumpgz *kerneldumpgz_create(struct dumperinfo *di,
+ uint8_t compression);
+static void kerneldumpgz_destroy(struct dumperinfo *di);
+static int kerneldumpgz_write_cb(void *cb, size_t len, off_t off, void *arg);
+
+static int kerneldump_gzlevel = 6;
+SYSCTL_INT(_kern, OID_AUTO, kerneldump_gzlevel, CTLFLAG_RWTUN,
+ &kerneldump_gzlevel, 0,
+ "Kernel crash dump gzip compression level");
+#endif /* GZIO */
+
/*
* Variable panicstr contains argument to first call to panic; used as flag
* to indicate that the kernel has already called panic.
@@ -857,6 +877,9 @@
SYSCTL_STRING(_kern_shutdown, OID_AUTO, dumpdevname, CTLFLAG_RD,
dumpdevname, 0, "Device for kernel dumps");
+static int _dump_append(struct dumperinfo *di, void *virtual,
+ vm_offset_t physical, size_t length);
+
#ifdef EKCD
static struct kerneldumpcrypto *
kerneldumpcrypto_create(size_t blocksize, uint8_t encryption,
@@ -947,11 +970,45 @@
}
#endif /* EKCD */
+#ifdef GZIO
+static struct kerneldumpgz *
+kerneldumpgz_create(struct dumperinfo *di, uint8_t compression)
+{
+ struct kerneldumpgz *kdgz;
+
+ if (compression != KERNELDUMP_COMP_GZIP)
+ return (NULL);
+ kdgz = malloc(sizeof(*kdgz), M_DUMPER, M_WAITOK | M_ZERO);
+ kdgz->kdgz_stream = gzio_init(kerneldumpgz_write_cb, GZIO_DEFLATE,
+ di->maxiosize, kerneldump_gzlevel, di);
+ if (kdgz->kdgz_stream == NULL) {
+ free(kdgz, M_DUMPER);
+ return (NULL);
+ }
+ kdgz->kdgz_buf = malloc(di->maxiosize, M_DUMPER, M_WAITOK | M_NODUMP);
+ return (kdgz);
+}
+
+static void
+kerneldumpgz_destroy(struct dumperinfo *di)
+{
+ struct kerneldumpgz *kdgz;
+
+ kdgz = di->kdgz;
+ if (kdgz == NULL)
+ return;
+ gzio_fini(kdgz->kdgz_stream);
+ explicit_bzero(kdgz->kdgz_buf, di->maxiosize);
+ free(kdgz->kdgz_buf, M_DUMPER);
+ free(kdgz, M_DUMPER);
+}
+#endif /* GZIO */
+
/* Registration of dumpers */
int
set_dumper(struct dumperinfo *di, const char *devname, struct thread *td,
- uint8_t encryption, const uint8_t *key, uint32_t encryptedkeysize,
- const uint8_t *encryptedkey)
+ uint8_t compression, uint8_t encryption, const uint8_t *key,
+ uint32_t encryptedkeysize, const uint8_t *encryptedkey)
{
size_t wantcopy;
int error;
@@ -969,6 +1026,7 @@
dumper = *di;
dumper.blockbuf = NULL;
dumper.kdc = NULL;
+ dumper.kdgz = NULL;
if (encryption != KERNELDUMP_ENC_NONE) {
#ifdef EKCD
@@ -987,9 +1045,30 @@
wantcopy = strlcpy(dumpdevname, devname, sizeof(dumpdevname));
if (wantcopy >= sizeof(dumpdevname)) {
printf("set_dumper: device name truncated from '%s' -> '%s'\n",
- devname, dumpdevname);
+ devname, dumpdevname);
}
+ if (compression != KERNELDUMP_COMP_NONE) {
+#ifdef GZIO
+ /*
+ * We currently can't support simultaneous encryption and
+ * compression.
+ */
+ if (encryption != KERNELDUMP_ENC_NONE) {
+ error = EOPNOTSUPP;
+ goto cleanup;
+ }
+ dumper.kdgz = kerneldumpgz_create(&dumper, compression);
+ if (dumper.kdgz == NULL) {
+ error = EINVAL;
+ goto cleanup;
+ }
+#else
+ error = EOPNOTSUPP;
+ goto cleanup;
+#endif
+ }
+
dumper.blockbuf = malloc(di->blocksize, M_DUMPER, M_WAITOK | M_ZERO);
return (0);
cleanup:
@@ -1000,6 +1079,11 @@
free(dumper.kdc, M_EKCD);
}
#endif
+
+#ifdef GZIO
+ kerneldumpgz_destroy(&dumper);
+#endif
+
if (dumper.blockbuf != NULL) {
explicit_bzero(dumper.blockbuf, dumper.blocksize);
free(dumper.blockbuf, M_DUMPER);
@@ -1090,22 +1174,57 @@
}
static int
-dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset)
+dump_write_key(struct dumperinfo *di, off_t offset)
{
struct kerneldumpcrypto *kdc;
kdc = di->kdc;
if (kdc == NULL)
return (0);
-
- return (dump_write(di, kdc->kdc_dumpkey, physical, offset,
+ return (dump_write(di, kdc->kdc_dumpkey, 0, offset,
kdc->kdc_dumpkeysize));
}
#endif /* EKCD */
+#ifdef GZIO
static int
+kerneldumpgz_write_cb(void *base, size_t length, off_t offset, void *arg)
+{
+ struct dumperinfo *di;
+ size_t resid, rlength;
+ int error;
+
+ di = arg;
+
+ if (length % di->blocksize != 0) {
+ /*
+ * This must be the final write after flushing the compression
+ * stream. Write as many full blocks as possible and stash the
+ * residual data in the dumper's block buffer. It will be
+ * padded and written in dump_finish().
+ */
+ rlength = rounddown(length, di->blocksize);
+ if (rlength != 0) {
+ error = _dump_append(di, base, 0, rlength);
+ if (error != 0)
+ return (error);
+ }
+ resid = length - rlength;
+ memmove(di->blockbuf, (uint8_t *)base + rlength, resid);
+ di->kdgz->kdgz_resid = resid;
+ return (EAGAIN);
+ }
+ return (_dump_append(di, base, 0, length));
+}
+#endif /* GZIO */
+
+/*
+ * Write a kerneldumpheader at the specified offset. The header structure is 512
+ * bytes in size, but we must pad to the device sector size.
+ */
+static int
dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh,
- vm_offset_t physical, off_t offset)
+ off_t offset)
{
void *buf;
size_t hdrsz;
@@ -1122,7 +1241,7 @@
memcpy(buf, kdh, hdrsz);
}
- return (dump_write(di, buf, physical, offset, di->blocksize));
+ return (dump_write(di, buf, 0, offset, di->blocksize));
}
/*
@@ -1132,19 +1251,30 @@
#define SIZEOF_METADATA (64 * 1024)
/*
- * Do some preliminary setup for a kernel dump: verify that we have enough space
- * on the dump device, write the leading header, and optionally write the crypto
- * key.
+ * Do some preliminary setup for a kernel dump: initialize state for encryption,
+ * if requested, and make sure that we have enough space on the dump device.
+ *
+ * We set things up so that the dump ends before the last sector of the dump
+ * device, at which the trailing header is written.
+ *
+ * +-----------+------+-----+----------------------------+------+
+ * | | lhdr | key | ... kernel dump ... | thdr |
+ * +-----------+------+-----+----------------------------+------+
+ * 1 blk opt <------- dump extent --------> 1 blk
+ *
+ * Dumps written using dump_append() start at the beginning of the extent.
+ * 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.
*/
int
dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
- uint64_t dumpsize;
+ uint64_t dumpextent;
uint32_t keysize;
- int error;
#ifdef EKCD
- error = kerneldumpcrypto_init(di->kdc);
+ int error = kerneldumpcrypto_init(di->kdc);
if (error != 0)
return (error);
keysize = kerneldumpcrypto_dumpkeysize(di->kdc);
@@ -1152,30 +1282,36 @@
keysize = 0;
#endif
- dumpsize = dtoh64(kdh->dumplength) + 2 * di->blocksize + keysize;
- if (di->mediasize < SIZEOF_METADATA + dumpsize)
- return (E2BIG);
-
- di->dumpoff = di->mediaoffset + di->mediasize - dumpsize;
-
- error = dump_write_header(di, kdh, 0, di->dumpoff);
- if (error != 0)
- return (error);
- di->dumpoff += di->blocksize;
-
-#ifdef EKCD
- error = dump_write_key(di, 0, di->dumpoff);
- if (error != 0)
- return (error);
- di->dumpoff += keysize;
+ dumpextent = dtoh64(kdh->dumpextent);
+ if (di->mediasize < SIZEOF_METADATA + dumpextent + 2 * di->blocksize +
+ keysize) {
+#ifdef GZIO
+ if (di->kdgz != NULL) {
+ /*
+ * We don't yet know how much space the compressed dump
+ * will occupy, so try to use the whole swap partition
+ * (minus the first 64KB) in the hope that the
+ * compressed dump will fit. If that doesn't turn out to
+ * be enouch, the bounds checking in dump_write()
+ * will catch us and cause the dump to fail.
+ */
+ dumpextent = di->mediasize - SIZEOF_METADATA -
+ 2 * di->blocksize - keysize;
+ kdh->dumpextent = htod64(dumpextent);
+ } else
#endif
+ return (E2BIG);
+ }
+ /* The offset at which to begin writing the dump. */
+ di->dumpoff = di->mediaoffset + di->mediasize - di->blocksize -
+ dumpextent;
+
return (0);
}
-/* Write to the dump device at the current dump offset. */
-int
-dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical,
+static int
+_dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical,
size_t length)
{
int error;
@@ -1192,8 +1328,34 @@
return (error);
}
-/* Perform a raw write to the dump device at the specified offset. */
+/*
+ * Write to the dump device starting at dumpoff. When compression is enabled,
+ * writes to the device will be performed using a callback that gets invoked
+ * when the compression stream's output buffer is full.
+ */
int
+dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical,
+ size_t length)
+{
+#ifdef GZIO
+ void *buf;
+
+ if (di->kdgz != NULL) {
+ /* Bounce through a buffer to avoid gzip CRC errors. */
+ if (length > di->maxiosize)
+ return (EINVAL);
+ buf = di->kdgz->kdgz_buf;
+ memmove(buf, virtual, length);
+ return (gzio_write(di->kdgz->kdgz_stream, buf, length));
+ }
+#endif
+ return (_dump_append(di, virtual, physical, length));
+}
+
+/*
+ * Write to the dump device at the specified offset.
+ */
+int
dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
off_t offset, size_t length)
{
@@ -1206,18 +1368,74 @@
}
/*
- * Write the trailing kernel dump header and signal to the lower layers that the
- * dump has completed.
+ * Perform kernel dump finalization: flush the compression stream, if necessary,
+ * write the leading and trailing kernel dump headers now that we know the true
+ * length of the dump, and optionally write the encryption key following the
+ * leading header.
*/
int
dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
+ uint64_t extent;
+ uint32_t keysize;
int error;
- error = dump_write_header(di, kdh, 0, di->dumpoff);
+ extent = dtoh64(kdh->dumpextent);
+
+#ifdef EKCD
+ keysize = kerneldumpcrypto_dumpkeysize(di->kdc);
+#else
+ keysize = 0;
+#endif
+
+#ifdef GZIO
+ if (di->kdgz != NULL) {
+ error = gzio_flush(di->kdgz->kdgz_stream);
+ if (error == EAGAIN) {
+ /* We have residual data in di->blockbuf. */
+ error = dump_write(di, di->blockbuf, 0, di->dumpoff,
+ di->blocksize);
+ di->dumpoff += di->kdgz->kdgz_resid;
+ di->kdgz->kdgz_resid = 0;
+ }
+ if (error != 0)
+ return (error);
+
+ /*
+ * 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->parity = 0;
+ kdh->parity = kerneldump_parity(kdh);
+
+ gzio_reset(di->kdgz->kdgz_stream);
+ }
+#endif
+
+ /*
+ * 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);
+ if (error != 0)
+ return (error);
+
(void)dump_write(di, NULL, 0, 0, 0);
return (0);
}
@@ -1234,6 +1452,7 @@
kdh->version = htod32(KERNELDUMPVERSION);
kdh->architectureversion = htod32(archver);
kdh->dumplength = htod64(dumplen);
+ kdh->dumpextent = kdh->dumplength;
kdh->dumptime = htod64(time_second);
#ifdef EKCD
kdh->dumpkeysize = htod32(kerneldumpcrypto_dumpkeysize(di->kdc));
@@ -1247,6 +1466,10 @@
kdh->versionstring[dstsize - 2] = '\n';
if (panicstr != NULL)
strlcpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring));
+#ifdef GZIO
+ if (di->kdgz != NULL)
+ kdh->compression = KERNELDUMP_COMP_GZIP;
+#endif
kdh->parity = kerneldump_parity(kdh);
}
Index: head/sys/sys/conf.h
===================================================================
--- head/sys/sys/conf.h
+++ head/sys/sys/conf.h
@@ -338,14 +338,15 @@
void *blockbuf; /* Buffer for padding shorter dump blocks */
off_t dumpoff; /* Offset of ongoing kernel dump. */
struct kerneldumpcrypto *kdc; /* Kernel dump crypto. */
+ struct kerneldumpgz *kdgz; /* Kernel dump compression. */
};
extern int dumping; /* system is dumping */
int doadump(boolean_t);
int set_dumper(struct dumperinfo *di, const char *devname, struct thread *td,
- uint8_t encrypt, const uint8_t *key, uint32_t encryptedkeysize,
- const uint8_t *encryptedkey);
+ uint8_t compression, uint8_t encryption, const uint8_t *key,
+ uint32_t encryptedkeysize, const uint8_t *encryptedkey);
int dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh);
int dump_append(struct dumperinfo *, void *, vm_offset_t, size_t);
Index: head/sys/sys/disk.h
===================================================================
--- head/sys/sys/disk.h
+++ head/sys/sys/disk.h
@@ -143,6 +143,7 @@
struct diocskerneldump_arg {
uint8_t kda_enable;
+ uint8_t kda_compression;
uint8_t kda_encryption;
uint8_t kda_key[KERNELDUMP_KEY_MAX_SIZE];
uint32_t kda_encryptedkeysize;
Index: head/sys/sys/gzio.h
===================================================================
--- head/sys/sys/gzio.h
+++ head/sys/sys/gzio.h
@@ -40,6 +40,7 @@
struct gzio_stream;
struct gzio_stream *gzio_init(gzio_cb cb, enum gzio_mode, size_t, int, void *);
+void gzio_reset(struct gzio_stream *);
int gzio_write(struct gzio_stream *, void *, u_int);
int gzio_flush(struct gzio_stream *);
void gzio_fini(struct gzio_stream *);
Index: head/sys/sys/kerneldump.h
===================================================================
--- head/sys/sys/kerneldump.h
+++ head/sys/sys/kerneldump.h
@@ -55,6 +55,9 @@
#define htod64(x) (x)
#endif
+#define KERNELDUMP_COMP_NONE 0
+#define KERNELDUMP_COMP_GZIP 1
+
#define KERNELDUMP_ENC_NONE 0
#define KERNELDUMP_ENC_AES_256_CBC 1
@@ -75,8 +78,8 @@
#define KERNELDUMPMAGIC_CLEARED "Cleared Kernel Dump"
char architecture[12];
uint32_t version;
-#define KERNELDUMPVERSION 2
-#define KERNELDUMP_TEXT_VERSION 2
+#define KERNELDUMPVERSION 3
+#define KERNELDUMP_TEXT_VERSION 3
uint32_t architectureversion;
#define KERNELDUMP_AARCH64_VERSION 1
#define KERNELDUMP_AMD64_VERSION 2
@@ -87,12 +90,14 @@
#define KERNELDUMP_RISCV_VERSION 1
#define KERNELDUMP_SPARC64_VERSION 1
uint64_t dumplength; /* excl headers */
+ uint64_t dumpextent;
uint64_t dumptime;
uint32_t dumpkeysize;
uint32_t blocksize;
+ uint8_t compression;
char hostname[64];
char versionstring[192];
- char panicstring[188];
+ char panicstring[179];
uint32_t parity;
};

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 27, 1:14 AM (20 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14874652
Default Alt Text
D11723.id34309.diff (28 KB)

Event Timeline