From 6026dcd7ca888f3433f4df34ede69a77c1eb7701 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 13 Feb 2018 19:28:02 +0000 Subject: [PATCH] Add support for zstd-compressed user and kernel core dumps. This works similarly to the existing gzip compression support, but zstd is typically faster and gives better compression ratios. Support for this functionality must be configured by adding ZSTDIO to one's kernel configuration file. dumpon(8)'s new -Z option is used to configure zstd compression for kernel dumps. savecore(8) now recognizes and saves zstd-compressed kernel dumps with a .zst extension. Submitted by: cem (original version) Relnotes: yes Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D13101, https://reviews.freebsd.org/D13633 --- sbin/dumpon/dumpon.8 | 29 ++++- sbin/dumpon/dumpon.c | 23 ++-- sbin/savecore/savecore.c | 34 ++++-- share/man/man5/core.5 | 15 ++- sys/conf/NOTES | 4 + sys/conf/files | 3 +- sys/conf/options | 1 + sys/kern/kern_shutdown.c | 20 +++- sys/kern/kern_sig.c | 11 +- sys/kern/subr_compressor.c | 229 +++++++++++++++++++++++++++++++++++++ sys/sys/compressor.h | 1 + sys/sys/kerneldump.h | 1 + 12 files changed, 339 insertions(+), 32 deletions(-) diff --git a/sbin/dumpon/dumpon.8 b/sbin/dumpon/dumpon.8 index 572bd030aef1..e6aace1bbbc0 100644 --- a/sbin/dumpon/dumpon.8 +++ b/sbin/dumpon/dumpon.8 @@ -28,7 +28,7 @@ .\" From: @(#)swapon.8 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd October 24, 2017 +.Dd February 13, 2018 .Dt DUMPON 8 .Os .Sh NAME @@ -39,6 +39,7 @@ .Op Fl v .Op Fl k Ar public_key_file .Op Fl z +.Op Fl Z .Ar special_file .Nm .Op Fl v @@ -116,8 +117,10 @@ kernel option. .Pp The .Fl z -option configures the kernel to compress the dump in gzip format before writing -it to the dump device. +and +.Fl Z +options configure the kernel to compress the dump before writing it to +the dump device. This reduces the amount of space required for the dump and accelerates recovery with .Xr savecore 8 @@ -126,9 +129,21 @@ 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 +The +.Fl z +and +.Fl Z +options cause the dump to be written in +.Xr gzip 1 +and +.Xr zstd 1 +format, respectively. +These flags require a kernel compiled with the .Dv GZIO -kernel option. +or +.Dv ZSTDIO +kernel options. +.Pp .Pp The .Fl l @@ -269,15 +284,17 @@ The core was decrypted properly if .Xr kgdb 1 does not print any errors. .Sh SEE ALSO +.Xr gzip 1 , .Xr kgdb 1 , +.Xr zstd 1 , .Xr ddb 4 , .Xr fstab 5 , .Xr rc.conf 5 , .Xr config 8 , +.Xr decryptcore 8 , .Xr init 8 , .Xr loader 8 , .Xr rc 8 , -.Xr decryptcore 8 , .Xr savecore 8 , .Xr swapon 8 , .Xr panic 9 diff --git a/sbin/dumpon/dumpon.c b/sbin/dumpon/dumpon.c index 19fdb3f5d572..0ae95e6e1847 100644 --- a/sbin/dumpon/dumpon.c +++ b/sbin/dumpon/dumpon.c @@ -73,7 +73,7 @@ static void usage(void) { fprintf(stderr, "%s\n%s\n%s\n", - "usage: dumpon [-v] [-k public_key_file] [-z] special_file", + "usage: dumpon [-v] [-k public_key_file] [-Zz] special_file", " dumpon [-v] off", " dumpon [-v] -l"); exit(EX_USAGE); @@ -192,12 +192,12 @@ main(int argc, char *argv[]) int ch; int i, fd; int do_listdumpdev = 0; - bool enable, gzip; + bool enable, gzip, zstd; - gzip = false; + gzip = zstd = false; pubkeyfile = NULL; - while ((ch = getopt(argc, argv, "k:lvz")) != -1) + while ((ch = getopt(argc, argv, "k:lvZz")) != -1) switch((char)ch) { case 'k': pubkeyfile = optarg; @@ -208,6 +208,9 @@ main(int argc, char *argv[]) case 'v': verbose = 1; break; + case 'Z': + zstd = true; + break; case 'z': gzip = true; break; @@ -215,6 +218,9 @@ main(int argc, char *argv[]) usage(); } + if (gzip && zstd) + errx(EX_USAGE, "The -z and -Z options are mutually exclusive."); + argc -= optind; argv += optind; @@ -254,7 +260,7 @@ main(int argc, char *argv[]) if (fd < 0) err(EX_OSFILE, "%s", dumpdev); - if (!gzip) + if (!gzip && !zstd) check_size(fd, dumpdev); bzero(&kda, sizeof(kda)); @@ -268,8 +274,11 @@ main(int argc, char *argv[]) #endif kda.kda_enable = 1; - kda.kda_compression = gzip ? KERNELDUMP_COMP_GZIP : - KERNELDUMP_COMP_NONE; + kda.kda_compression = KERNELDUMP_COMP_NONE; + if (zstd) + kda.kda_compression = KERNELDUMP_COMP_ZSTD; + else if (gzip) + kda.kda_compression = KERNELDUMP_COMP_GZIP; i = ioctl(fd, DIOCSKERNELDUMP, &kda); explicit_bzero(kda.kda_encryptedkey, kda.kda_encryptedkeysize); free(kda.kda_encryptedkey); diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c index 14257421361c..5414b1910451 100644 --- a/sbin/savecore/savecore.c +++ b/sbin/savecore/savecore.c @@ -109,6 +109,7 @@ printheader(xo_handle_t *xo, const struct kerneldumpheader *h, uint64_t dumplen; time_t t; const char *stat_str; + const char *comp_str; xo_flush_h(xo); xo_emit_h(xo, "{Lwc:Dump header from device}{:dump_device/%s}\n", @@ -123,10 +124,21 @@ printheader(xo_handle_t *xo, const struct kerneldumpheader *h, (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"); - + switch (h->compression) { + case KERNELDUMP_COMP_NONE: + comp_str = "none"; + break; + case KERNELDUMP_COMP_GZIP: + comp_str = "gzip"; + break; + case KERNELDUMP_COMP_ZSTD: + comp_str = "zstd"; + break; + default: + comp_str = "???"; + break; + } + xo_emit_h(xo, "{P: }{Lwc:Compression}{:compression/%s}\n", comp_str); t = dtoh64(h->dumptime); xo_emit_h(xo, "{P: }{Lwc:Dumptime}{:dumptime/%s}", ctime(&t)); xo_emit_h(xo, "{P: }{Lwc:Hostname}{:hostname/%s}\n", h->hostname); @@ -249,6 +261,8 @@ saved_dump_size(int bounds) dumpsize += file_size(path); (void)snprintf(path, sizeof(path), "vmcore.%d.gz", bounds); dumpsize += file_size(path); + (void)snprintf(path, sizeof(path), "vmcore.%d.zst", bounds); + dumpsize += file_size(path); (void)snprintf(path, sizeof(path), "textdump.tar.%d", bounds); dumpsize += file_size(path); (void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds); @@ -268,6 +282,8 @@ saved_dump_remove(int bounds) (void)unlink(path); (void)snprintf(path, sizeof(path), "vmcore.%d.gz", bounds); (void)unlink(path); + (void)snprintf(path, sizeof(path), "vmcore.%d.zst", bounds); + (void)unlink(path); (void)snprintf(path, sizeof(path), "textdump.tar.%d", bounds); (void)unlink(path); (void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds); @@ -282,6 +298,7 @@ symlinks_remove(void) (void)unlink("key.last"); (void)unlink("vmcore.last"); (void)unlink("vmcore.last.gz"); + (void)unlink("vmcore.last.zstd"); (void)unlink("vmcore_encrypted.last"); (void)unlink("vmcore_encrypted.last.gz"); (void)unlink("textdump.tar.last"); @@ -615,6 +632,7 @@ DoFile(const char *savedir, const char *device) case KERNELDUMP_COMP_NONE: break; case KERNELDUMP_COMP_GZIP: + case KERNELDUMP_COMP_ZSTD: if (compress && verbose) printf("dump is already compressed\n"); compress = false; @@ -743,7 +761,8 @@ DoFile(const char *savedir, const char *device) (isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); fp = zopen(corename, "w"); } else if (iscompressed && !isencrypted) { - snprintf(corename, sizeof(corename), "vmcore.%d.gz", bounds); + snprintf(corename, sizeof(corename), "vmcore.%d.%s", bounds, + (kdhl.compression == KERNELDUMP_COMP_GZIP) ? "gz" : "zst"); fp = fopen(corename, "w"); } else { snprintf(corename, sizeof(corename), "%s.%d", @@ -845,9 +864,10 @@ DoFile(const char *savedir, const char *device) } } if (compress || iscompressed) { - snprintf(linkname, sizeof(linkname), "%s.last.gz", + snprintf(linkname, sizeof(linkname), "%s.last.%s", istextdump ? "textdump.tar" : - (isencrypted ? "vmcore_encrypted" : "vmcore")); + (isencrypted ? "vmcore_encrypted" : "vmcore"), + (kdhl.compression == KERNELDUMP_COMP_ZSTD) ? "zst" : "gz"); } else { snprintf(linkname, sizeof(linkname), "%s.last", istextdump ? "textdump.tar" : diff --git a/share/man/man5/core.5 b/share/man/man5/core.5 index e050cf80d56c..e8c747ecd22b 100644 --- a/share/man/man5/core.5 +++ b/share/man/man5/core.5 @@ -28,7 +28,7 @@ .\" @(#)core.5 8.3 (Berkeley) 12/11/93 .\" $FreeBSD$ .\" -.Dd January 8, 2018 +.Dd February 13, 2018 .Dt CORE 5 .Os .Sh NAME @@ -112,10 +112,17 @@ The following sysctl control core file compression: .Bl -tag -width "kern.compress_user_cores_level" -compact -offset "12345" .It Em kern.compress_user_cores Enable compression of user cores. -A value of 1 configures gzip compression. -gzip-compressed core files will have a suffix of +A value of 1 configures +.Xr gzip 1 +compression, +and a value of 2 configures +.Xr zstd 1 +compression. +Compressed core files will have a suffix of .Ql .gz -appended to their filenames. +or +.Ql .zst +appended to their filenames depending on the selected format. .It Em kern.compress_user_cores_level Compression level. Defaults to 6. diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 6c7386992f19..d3ca05b7aa4f 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -3018,6 +3018,10 @@ options IMAGACT_BINMISC # This enables support for compressed core dumps. options GZIO +# zstd I/O stream support +# This enables support for Zstd compressed core dumps. +options ZSTDIO + # BHND(4) drivers options BHND_LOGLEVEL # Logging threshold level diff --git a/sys/conf/files b/sys/conf/files index 15cb532b3eca..4caf4bae44c9 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3836,7 +3836,8 @@ kern/subr_bus_dma.c standard kern/subr_bufring.c standard kern/subr_capability.c standard kern/subr_clock.c standard -kern/subr_compressor.c standard +kern/subr_compressor.c standard \ + compile-with "${NORMAL_C} -I$S/contrib/zstd/lib/freebsd" kern/subr_counter.c standard kern/subr_devstat.c standard kern/subr_disk.c standard diff --git a/sys/conf/options b/sys/conf/options index b784079e2311..adef51b5067a 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -222,6 +222,7 @@ TURNSTILE_PROFILING UMTX_PROFILING UMTX_CHAINS opt_global.h VERBOSE_SYSINIT +ZSTDIO opt_zstdio.h # POSIX kernel options P1003_1B_MQUEUE opt_posix.h diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index 0979b3081286..aa60eecc5fa1 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -174,6 +174,7 @@ struct kerneldumpcrypto { #endif struct kerneldumpcomp { + uint8_t kdc_format; struct compressor *kdc_stream; uint8_t *kdc_buf; size_t kdc_resid; @@ -987,12 +988,23 @@ static struct kerneldumpcomp * kerneldumpcomp_create(struct dumperinfo *di, uint8_t compression) { struct kerneldumpcomp *kdcomp; + int format; - if (compression != KERNELDUMP_COMP_GZIP) + switch (compression) { + case KERNELDUMP_COMP_GZIP: + format = COMPRESS_GZIP; + break; + case KERNELDUMP_COMP_ZSTD: + format = COMPRESS_ZSTD; + break; + default: return (NULL); + } + kdcomp = malloc(sizeof(*kdcomp), M_DUMPER, M_WAITOK | M_ZERO); + kdcomp->kdc_format = compression; kdcomp->kdc_stream = compressor_init(kerneldumpcomp_write_cb, - COMPRESS_GZIP, di->maxiosize, kerneldump_gzlevel, di); + format, di->maxiosize, kerneldump_gzlevel, di); if (kdcomp->kdc_stream == NULL) { free(kdcomp, M_DUMPER); return (NULL); @@ -1293,7 +1305,7 @@ dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh) * 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() + * be enough, the bounds checking in dump_write() * will catch us and cause the dump to fail. */ dumpextent = di->mediasize - SIZEOF_METADATA - @@ -1463,7 +1475,7 @@ dump_init_header(const struct dumperinfo *di, struct kerneldumpheader *kdh, if (panicstr != NULL) strlcpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); if (di->kdcomp != NULL) - kdh->compression = KERNELDUMP_COMP_GZIP; + kdh->compression = di->kdcomp->kdc_format; kdh->parity = kerneldump_parity(kdh); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 24c1cbdf1618..a71de7a5848f 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -3253,7 +3253,8 @@ sysctl_debug_num_cores_check (SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_debug, OID_AUTO, ncores, CTLTYPE_INT|CTLFLAG_RW, 0, sizeof(int), sysctl_debug_num_cores_check, "I", ""); -#define GZ_SUFFIX ".gz" +#define GZIP_SUFFIX ".gz" +#define ZSTD_SUFFIX ".zst" int compress_user_cores = 0; @@ -3273,7 +3274,9 @@ sysctl_compress_user_cores(SYSCTL_HANDLER_ARGS) } SYSCTL_PROC(_kern, OID_AUTO, compress_user_cores, CTLTYPE_INT | CTLFLAG_RWTUN, 0, sizeof(int), sysctl_compress_user_cores, "I", - "Enable compression of user corefiles (" __XSTRING(COMPRESS_GZIP) " = gzip)"); + "Enable compression of user corefiles (" + __XSTRING(COMPRESS_GZIP) " = gzip, " + __XSTRING(COMPRESS_ZSTD) " = zstd)"); int compress_user_cores_level = 6; SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_level, CTLFLAG_RWTUN, @@ -3377,7 +3380,9 @@ corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td, sx_sunlock(&corefilename_lock); free(hostname, M_TEMP); if (compress == COMPRESS_GZIP) - sbuf_printf(&sb, GZ_SUFFIX); + sbuf_printf(&sb, GZIP_SUFFIX); + else if (compress == COMPRESS_ZSTD) + sbuf_printf(&sb, ZSTD_SUFFIX); if (sbuf_error(&sb) != 0) { log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too " "long\n", (long)pid, comm, (u_long)uid); diff --git a/sys/kern/subr_compressor.c b/sys/kern/subr_compressor.c index 0ddf27274511..cc8c3e504526 100644 --- a/sys/kern/subr_compressor.c +++ b/sys/kern/subr_compressor.c @@ -2,6 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2014, 2017 Mark Johnston + * Copyright (c) 2017 Conrad Meyer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -34,8 +35,10 @@ __FBSDID("$FreeBSD$"); #include "opt_gzio.h" +#include "opt_zstdio.h" #include +#include #include #include @@ -245,6 +248,232 @@ DATA_SET(compressors, gzip_methods); #endif /* GZIO */ +#ifdef ZSTDIO + +#define ZSTD_STATIC_LINKING_ONLY +#include + +struct zstdio_stream { + ZSTD_CCtx *zst_stream; + ZSTD_inBuffer zst_inbuffer; + ZSTD_outBuffer zst_outbuffer; + uint8_t * zst_buffer; /* output buffer */ + size_t zst_maxiosz; /* Max output IO size */ + off_t zst_off; /* offset into the output stream */ + void * zst_static_wkspc; +}; + +static void *zstdio_init(size_t maxiosize, int level); +static void zstdio_reset(void *stream); +static int zstdio_write(void *stream, void *data, size_t len, + compressor_cb_t, void *); +static void zstdio_fini(void *stream); + +static void * +zstdio_init(size_t maxiosize, int level) +{ + ZSTD_CCtx *dump_compressor; + struct zstdio_stream *s; + void *wkspc, *owkspc, *buffer; + size_t wkspc_size, buf_size; + + wkspc_size = ZSTD_estimateCStreamSize(level); + owkspc = wkspc = malloc(wkspc_size + 8, M_COMPRESS, + M_WAITOK | M_NODUMP); + /* Zstd API requires 8-byte alignment. */ + if ((uintptr_t)wkspc % 8 != 0) + wkspc = (void *)roundup2((uintptr_t)wkspc, 8); + + dump_compressor = ZSTD_initStaticCCtx(wkspc, wkspc_size); + if (dump_compressor == NULL) { + free(owkspc, M_COMPRESS); + printf("%s: workspace too small.\n", __func__); + return (NULL); + } + + (void)ZSTD_CCtx_setParameter(dump_compressor, ZSTD_p_checksumFlag, 1); + + buf_size = ZSTD_CStreamOutSize() * 2; + buffer = malloc(buf_size, M_COMPRESS, M_WAITOK | M_NODUMP); + + s = malloc(sizeof(*s), M_COMPRESS, M_NODUMP | M_WAITOK); + s->zst_buffer = buffer; + s->zst_outbuffer.dst = buffer; + s->zst_outbuffer.size = buf_size; + s->zst_maxiosz = maxiosize; + s->zst_stream = dump_compressor; + s->zst_static_wkspc = owkspc; + + zstdio_reset(s); + + return (s); +} + +static void +zstdio_reset(void *stream) +{ + struct zstdio_stream *s; + size_t res; + + s = stream; + res = ZSTD_resetCStream(s->zst_stream, 0); + if (ZSTD_isError(res)) + panic("%s: could not reset stream %p: %s\n", __func__, s, + ZSTD_getErrorName(res)); + + s->zst_off = 0; + s->zst_inbuffer.src = NULL; + s->zst_inbuffer.size = 0; + s->zst_inbuffer.pos = 0; + s->zst_outbuffer.pos = 0; +} + +static int +zst_flush_intermediate(struct zstdio_stream *s, compressor_cb_t cb, void *arg) +{ + size_t bytes_to_dump; + int error; + + /* Flush as many full output blocks as possible. */ + /* XXX: 4096 is arbitrary safe HDD block size for kernel dumps */ + while (s->zst_outbuffer.pos >= 4096) { + bytes_to_dump = rounddown(s->zst_outbuffer.pos, 4096); + + if (bytes_to_dump > s->zst_maxiosz) + bytes_to_dump = s->zst_maxiosz; + + error = cb(s->zst_buffer, bytes_to_dump, s->zst_off, arg); + if (error != 0) + return (error); + + /* + * Shift any non-full blocks up to the front of the output + * buffer. + */ + s->zst_outbuffer.pos -= bytes_to_dump; + memmove(s->zst_outbuffer.dst, + (char *)s->zst_outbuffer.dst + bytes_to_dump, + s->zst_outbuffer.pos); + s->zst_off += bytes_to_dump; + } + return (0); +} + +static int +zstdio_flush(struct zstdio_stream *s, compressor_cb_t cb, void *arg) +{ + size_t rc, lastpos; + int error; + + /* + * Positive return indicates unflushed data remaining; need to call + * endStream again after clearing out room in output buffer. + */ + rc = 1; + lastpos = s->zst_outbuffer.pos; + while (rc > 0) { + rc = ZSTD_endStream(s->zst_stream, &s->zst_outbuffer); + if (ZSTD_isError(rc)) { + printf("%s: ZSTD_endStream failed (%s)\n", __func__, + ZSTD_getErrorName(rc)); + return (EIO); + } + if (lastpos == s->zst_outbuffer.pos) { + printf("%s: did not make forward progress endStream %zu\n", + __func__, lastpos); + return (EIO); + } + + error = zst_flush_intermediate(s, cb, arg); + if (error != 0) + return (error); + + lastpos = s->zst_outbuffer.pos; + } + + /* + * We've already done an intermediate flush, so all full blocks have + * been written. Only a partial block remains. Padding happens in a + * higher layer. + */ + if (s->zst_outbuffer.pos != 0) { + error = cb(s->zst_buffer, s->zst_outbuffer.pos, s->zst_off, + arg); + if (error != 0) + return (error); + } + + return (0); +} + +static int +zstdio_write(void *stream, void *data, size_t len, compressor_cb_t cb, + void *arg) +{ + struct zstdio_stream *s; + size_t lastpos, rc; + int error; + + s = stream; + if (data == NULL) + return (zstdio_flush(s, cb, arg)); + + s->zst_inbuffer.src = data; + s->zst_inbuffer.size = len; + s->zst_inbuffer.pos = 0; + lastpos = 0; + + while (s->zst_inbuffer.pos < s->zst_inbuffer.size) { + rc = ZSTD_compressStream(s->zst_stream, &s->zst_outbuffer, + &s->zst_inbuffer); + if (ZSTD_isError(rc)) { + printf("%s: Compress failed on %p! (%s)\n", + __func__, data, ZSTD_getErrorName(rc)); + return (EIO); + } + + if (lastpos == s->zst_inbuffer.pos) { + /* + * XXX: May need flushStream to make forward progress + */ + printf("ZSTD: did not make forward progress @pos %zu\n", + lastpos); + return (EIO); + } + lastpos = s->zst_inbuffer.pos; + + error = zst_flush_intermediate(s, cb, arg); + if (error != 0) + return (error); + } + return (0); +} + +static void +zstdio_fini(void *stream) +{ + struct zstdio_stream *s; + + s = stream; + if (s->zst_static_wkspc != NULL) + free(s->zst_static_wkspc, M_COMPRESS); + else + ZSTD_freeCCtx(s->zst_stream); + free(s->zst_buffer, M_COMPRESS); + free(s, M_COMPRESS); +} + +static struct compressor_methods zstd_methods = { + .format = COMPRESS_ZSTD, + .init = zstdio_init, + .reset = zstdio_reset, + .write = zstdio_write, + .fini = zstdio_fini, +}; +DATA_SET(compressors, zstd_methods); + +#endif /* ZSTDIO */ + bool compressor_avail(int format) { diff --git a/sys/sys/compressor.h b/sys/sys/compressor.h index 9407b950d5a8..5406ef3c3298 100644 --- a/sys/sys/compressor.h +++ b/sys/sys/compressor.h @@ -35,6 +35,7 @@ /* Supported formats. */ #define COMPRESS_GZIP 1 +#define COMPRESS_ZSTD 2 typedef int (*compressor_cb_t)(void *, size_t, off_t, void *); diff --git a/sys/sys/kerneldump.h b/sys/sys/kerneldump.h index 607b6848c80f..9e2b8aaad02c 100644 --- a/sys/sys/kerneldump.h +++ b/sys/sys/kerneldump.h @@ -59,6 +59,7 @@ #define KERNELDUMP_COMP_NONE 0 #define KERNELDUMP_COMP_GZIP 1 +#define KERNELDUMP_COMP_ZSTD 2 #define KERNELDUMP_ENC_NONE 0 #define KERNELDUMP_ENC_AES_256_CBC 1