Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F103520163
D11723.id34309.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D11723.id34309.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D11723: Add support for compressed kernel dumps.
Attached
Detach File
Event Timeline
Log In to Comment