Index: etc/defaults/rc.conf =================================================================== --- etc/defaults/rc.conf +++ etc/defaults/rc.conf @@ -595,9 +595,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: etc/rc.d/dumpon =================================================================== --- etc/rc.d/dumpon +++ 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: sbin/dumpon/dumpon.8 =================================================================== --- sbin/dumpon/dumpon.8 +++ sbin/dumpon/dumpon.8 @@ -28,7 +28,7 @@ .\" From: @(#)swapon.8 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd December 10, 2016 +.Dd July 29, 2017 .Dt DUMPON 8 .Os .Sh NAME @@ -37,6 +37,7 @@ .Sh SYNOPSIS .Nm .Op Fl v +.Op Fl c .Op Fl k Ar public_key_file .Ar special_file .Nm @@ -85,6 +86,23 @@ variable. .Pp The +.Op c +option configures the kernel to write a compressed dump to the dump device. +This reduces the amount of space required for the dump. +When compression is enabled, the +.Nm +utility will not verify that the dump device is sufficiently large for a full +dump. +Currently the +.Op c +and +.Op k +options can not be combined. +This feature depends on the +.Dv GZIO +kernel option. +.Pp +The .Op Fl k Ar public_key_file flag causes .Nm Index: sbin/dumpon/dumpon.c =================================================================== --- sbin/dumpon/dumpon.c +++ 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] [-c] [-k public_key_file] special_file", " dumpon [-v] off", " dumpon [-v] -l"); exit(EX_USAGE); @@ -190,12 +190,16 @@ int ch; int i, fd; int do_listdumpdev = 0; - bool enable; + bool compress, enable; + compress = false; pubkeyfile = NULL; - while ((ch = getopt(argc, argv, "k:lv")) != -1) + while ((ch = getopt(argc, argv, "ck:lv")) != -1) switch((char)ch) { + case 'c': + compress = true; + break; case 'k': pubkeyfile = optarg; break; @@ -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 (!compress) + 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,7 @@ #endif kda.kda_enable = 1; + kda.kda_compress = compress; i = ioctl(fd, DIOCSKERNELDUMP, &kda); explicit_bzero(kda.kda_encryptedkey, kda.kda_encryptedkeysize); free(kda.kda_encryptedkey); Index: sbin/savecore/savecore.c =================================================================== --- sbin/savecore/savecore.c +++ 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_COMPRESSION_DEFLATE ? + "DEFLATE" : "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,11 @@ if (force == 0) goto closefd; } + if (kdhl.compression == KERNELDUMP_COMPRESSION_DEFLATE) { + if (compress && verbose) + printf("dump is already compressed\n"); + iscompressed = true; + } } else { if (verbose) printf("magic mismatch on last dump header on %s\n", @@ -619,8 +626,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 +654,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 +703,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 +731,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 +802,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 +833,7 @@ "key.last"); } } - if (compress) { + if (compress || iscompressed) { snprintf(linkname, sizeof(linkname), "%s.last.gz", istextdump ? "textdump.tar" : (isencrypted ? "vmcore_encrypted" : "vmcore")); Index: share/man/man5/rc.conf.5 =================================================================== --- share/man/man5/rc.conf.5 +++ share/man/man5/rc.conf.5 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 26, 2017 +.Dd July 29, 2017 .Dt RC.CONF 5 .Os .Sh NAME @@ -3377,6 +3377,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 @@ -3397,18 +3404,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: sys/dev/null/null.c =================================================================== --- sys/dev/null/null.c +++ 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, false, 0, NULL, 0, NULL); break; case FIONBIO: break; Index: sys/geom/geom_dev.c =================================================================== --- sys/geom/geom_dev.c +++ 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, false, 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_compress, + kda->kda_encryption, kda->kda_key, kda->kda_encryptedkeysize, + kda->kda_encryptedkey); if (error == 0) dev->si_flags |= SI_DUMPDEV; @@ -817,7 +818,8 @@ /* 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, false, 0, NULL, 0, + NULL); /* Destroy the struct cdev *so we get no more requests */ destroy_dev_sched_cb(dev, g_dev_callback, cp); Index: sys/kern/kern_shutdown.c =================================================================== --- sys/kern/kern_shutdown.c +++ 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 #include #include +#include #include #include #include @@ -162,6 +164,20 @@ }; #endif +#ifdef GZIO +static struct gzio_stream *dumpgzs; +static uint8_t *gzbuffer; + +static int kerneldump_gz_configure(struct dumperinfo *di); +static void kerneldump_gz_disable(void); +static int kerneldump_gz_write_cb(void *cb, size_t len, off_t off, void *arg); + +static int kerneldump_gz_level = 6; +SYSCTL_INT(_kern, OID_AUTO, kerneldump_gz_level, CTLFLAG_RWTUN, + &kerneldump_gz_level, 0, + "Kernel crash dump 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. @@ -858,6 +874,9 @@ SYSCTL_STRING(_kern_shutdown, OID_AUTO, dumpdevname, CTLFLAG_RD, dumpdevname, 0, "Device for kernel dumps"); +static int _dump_write(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, @@ -948,11 +967,37 @@ } #endif /* EKCD */ +#ifdef GZIO +static int +kerneldump_gz_configure(struct dumperinfo *di) +{ + + dumpgzs = gzio_init(kerneldump_gz_write_cb, GZIO_DEFLATE, di->maxiosize, + kerneldump_gz_level, di); + if (dumpgzs == NULL) + return (EINVAL); + gzbuffer = malloc(di->maxiosize, M_DUMPER, M_WAITOK | M_NODUMP); + return (0); +} + +static void +kerneldump_gz_disable(void) +{ + + if (dumpgzs != NULL) { + gzio_fini(dumpgzs); + dumpgzs = NULL; + } + free(gzbuffer, M_DUMPER); + gzbuffer = NULL; +} +#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) + bool compress, uint8_t encryption, const uint8_t *key, + uint32_t encryptedkeysize, const uint8_t *encryptedkey) { size_t wantcopy; int error; @@ -988,7 +1033,26 @@ 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 (compress) { +#ifdef GZIO + /* + * We currently can't support simultaneous encryption and + * compression. + */ + if (encryption != KERNELDUMP_ENC_NONE) { + error = EOPNOTSUPP; + goto cleanup; + } + error = kerneldump_gz_configure(&dumper); + if (error != 0) + goto cleanup; +#else + error = EOPNOTSUPP; + goto cleanup; +#endif } dumper.blockbuf = malloc(di->blocksize, M_DUMPER, M_WAITOK | M_ZERO); @@ -1001,6 +1065,11 @@ free(dumper.kdc, M_EKCD); } #endif + +#ifdef GZIO + kerneldump_gz_disable(); +#endif + if (dumper.blockbuf != NULL) { explicit_bzero(dumper.blockbuf, dumper.blocksize); free(dumper.blockbuf, M_DUMPER); @@ -1104,6 +1173,41 @@ } #endif /* EKCD */ +#ifdef GZIO +static int +kerneldump_gz_write_cb(void *base, size_t length, off_t offset, void *arg) +{ + struct dumperinfo *di; + size_t 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_write(di, base, 0, rlength); + if (error != 0) + return (error); + } + di->resid = length - rlength; + memmove(di->blockbuf, (uint8_t *)base + rlength, di->resid); + return (EAGAIN); + } + return (_dump_write(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) @@ -1133,19 +1237,29 @@ #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 are written starting 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. */ 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); @@ -1153,33 +1267,37 @@ keysize = 0; #endif - dumpsize = dtoh64(kdh->dumplength) + 2 * di->blocksize + keysize; - if (di->mediasize < SIZEOF_METADATA + dumpsize) - return (ENOSPC); - - dumpoff = di->mediaoffset + di->mediasize - dumpsize; + dumpextent = dtoh64(kdh->dumpextent); + if (di->mediasize < SIZEOF_METADATA + dumpextent + 2 * di->blocksize + + keysize) { +#ifdef GZIO + if (dumpgzs != 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_raw_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 (ENOSPC); + } - error = dump_write_header(di, kdh, 0, dumpoff); - if (error != 0) - return (error); - dumpoff += di->blocksize; + /* The offset at which to begin writing the dump. */ + dumpoff = di->mediaoffset + di->mediasize - di->blocksize - dumpextent; -#ifdef EKCD - error = dump_write_key(di, 0, dumpoff); - if (error != 0) - return (error); - dumpoff += keysize; -#endif + di->resid = 0; return (0); } -/* - * Write the trailing kernel dump header and signal to the lower layers that the - * dump has completed. - */ -int -dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, +static int +_dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, size_t length) { int error; @@ -1196,6 +1314,31 @@ return (error); } +/* + * 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_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, + size_t length) +{ + +#ifdef GZIO + if (dumpgzs != NULL) { + /* Bounce through a buffer to avoid gzip CRC errors. */ + if (length > di->maxiosize) + return (EINVAL); + memmove(gzbuffer, virtual, length); + return (gzio_write(dumpgzs, gzbuffer, length)); + } +#endif + return (_dump_write(di, virtual, physical, length)); +} + +/* + * Write to the dump device at the specified offset. + */ int dump_raw_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, off_t offset, size_t length) @@ -1209,12 +1352,70 @@ return (di->dumper(di->priv, virtual, physical, offset, length)); } +/* + * 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, dumpoff); + extent = dtoh64(kdh->dumpextent); + +#ifdef EKCD + keysize = kerneldumpcrypto_dumpkeysize(di->kdc); +#else + keysize = 0; +#endif + +#ifdef GZIO + if (dumpgzs != NULL) { + error = gzio_flush(dumpgzs); + if (error == EAGAIN) { + /* We have residual data in di->blockbuf. */ + error = dump_raw_write(di, di->blockbuf, 0, dumpoff, + di->blocksize); + dumpoff += di->resid; + di->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(dumpoff - + (di->mediaoffset + di->mediasize - di->blocksize - extent)); + kdh->parity = 0; + kdh->parity = kerneldump_parity(kdh); + } +#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, 0, + di->mediaoffset + di->mediasize - 2 * di->blocksize - extent - + keysize); + if (error != 0) + return (error); + +#ifdef EKCD + error = dump_write_key(di, 0, + di->mediaoffset + di->mediasize - di->blocksize - extent - keysize); + if (error != 0) + return (error); +#endif + + error = dump_write_header(di, kdh, 0, + di->mediaoffset + di->mediasize - di->blocksize); if (error != 0) return (error); @@ -1234,6 +1435,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(dumper.kdc)); @@ -1247,6 +1449,10 @@ kdh->versionstring[dstsize - 2] = '\n'; if (panicstr != NULL) strlcpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); +#ifdef GZIO + if (dumpgzs != NULL) + kdh->compression = KERNELDUMP_COMPRESSION_DEFLATE; +#endif kdh->parity = kerneldump_parity(kdh); } Index: sys/sys/conf.h =================================================================== --- sys/sys/conf.h +++ sys/sys/conf.h @@ -336,12 +336,13 @@ off_t mediaoffset; /* Initial offset in bytes. */ off_t mediasize; /* Space available in bytes. */ void *blockbuf; /* Buffer for padding shorter dump blocks */ + size_t resid; /* Residual data from compression stream. */ struct kerneldumpcrypto *kdc; /* Kernel dump crypto. */ }; 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); + bool compress, uint8_t encrypt, const uint8_t *key, + uint32_t encryptedkeysize, const uint8_t *encryptedkey); int dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh); int dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh); int dump_write(struct dumperinfo *, void *, vm_offset_t, size_t); Index: sys/sys/disk.h =================================================================== --- sys/sys/disk.h +++ sys/sys/disk.h @@ -142,6 +142,7 @@ struct diocskerneldump_arg { uint8_t kda_enable; + uint8_t kda_compress; uint8_t kda_encryption; uint8_t kda_key[KERNELDUMP_KEY_MAX_SIZE]; uint32_t kda_encryptedkeysize; Index: sys/sys/kerneldump.h =================================================================== --- sys/sys/kerneldump.h +++ sys/sys/kerneldump.h @@ -75,8 +75,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 @@ -86,13 +86,17 @@ #define KERNELDUMP_POWERPC_VERSION 1 #define KERNELDUMP_RISCV_VERSION 1 #define KERNELDUMP_SPARC64_VERSION 1 - uint64_t dumplength; /* excl headers */ + uint64_t dumplength; + uint64_t dumpextent; uint64_t dumptime; uint32_t dumpkeysize; uint32_t blocksize; + uint8_t compression; +#define KERNELDUMP_COMPRESSION_UNCOMPRESSED 0 +#define KERNELDUMP_COMPRESSION_DEFLATE 1 char hostname[64]; char versionstring[192]; - char panicstring[188]; + char panicstring[179]; uint32_t parity; };