Index: share/man/man5/core.5 =================================================================== --- share/man/man5/core.5 +++ share/man/man5/core.5 @@ -28,7 +28,7 @@ .\" @(#)core.5 8.3 (Berkeley) 12/11/93 .\" $FreeBSD$ .\" -.Dd October 5, 2015 +.Dd December 22, 2017 .Dt CORE 5 .Os .Sh NAME @@ -108,17 +108,17 @@ GZIO .El .Pp -When the GZIO option is included, the following sysctls control whether core -files will be compressed: -.Bl -tag -width "kern.compress_user_cores_gzlevel" -compact -offset "12345" -.It Em kern.compress_user_cores_gzlevel -Gzip compression level. -Defaults to 6. +The following sysctl control core file compression: +.Bl -tag -width "kern.compress_user_cores_level" -compact -offset "12345" .It Em kern.compress_user_cores -Actually compress user cores. -Compressed core files will have a suffix of +Enable compression of user cores. +A value of 1 configures gzip compression. +gzip-compressed core files will have a suffix of .Ql .gz -appended to them. +appended to their filenames. +.It Em kern.compress_user_cores_level +Compression level. +Defaults to 6. .El .Sh NOTES Corefiles are written with open file descriptor information as an ELF note. @@ -153,6 +153,7 @@ .Dl sysctl kern.corefile=/var/coredumps/\&%U/\&%N.core .Sh SEE ALSO .Xr gdb 1 , +.Xr gzip 1 , .Xr kgdb 1 , .Xr setrlimit 2 , .Xr sigaction 2 , Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -3750,7 +3750,6 @@ kern/kern_fail.c standard kern/kern_ffclock.c standard kern/kern_fork.c standard -kern/kern_gzio.c optional gzio kern/kern_hhook.c standard kern/kern_idle.c standard kern/kern_intr.c standard @@ -3825,6 +3824,7 @@ kern/subr_bufring.c standard kern/subr_capability.c standard kern/subr_clock.c standard +kern/subr_compressor.c standard kern/subr_counter.c standard kern/subr_devstat.c standard kern/subr_disk.c standard Index: sys/ddb/db_textdump.c =================================================================== --- sys/ddb/db_textdump.c +++ sys/ddb/db_textdump.c @@ -454,8 +454,8 @@ /* * Disable EKCD because we don't provide encrypted textdumps. */ - kdc = di->kdc; - di->kdc = NULL; + kdc = di->kdcrypto; + di->kdcrypto = NULL; /* * Position the start of the dump so that we'll write the kernel dump @@ -512,7 +512,7 @@ /* * Restore EKCD status. */ - di->kdc = kdc; + di->kdcrypto = kdc; } /*- Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -36,13 +36,12 @@ #include "opt_capsicum.h" #include "opt_compat.h" -#include "opt_gzio.h" #include #include +#include #include #include -#include #include #include #include @@ -1185,9 +1184,12 @@ struct ucred *file_cred; struct thread *td; struct vnode *vp; - struct gzio_stream *gzs; + struct compressor *comp; }; +extern int compress_user_cores; +extern int compress_user_cores_level; + static void cb_put_phdr(vm_map_entry_t, void *); static void cb_size_segment(vm_map_entry_t, void *); static int core_write(struct coredump_params *, const void *, size_t, off_t, @@ -1219,9 +1221,6 @@ static void note_procstat_umask(void *, struct sbuf *, size_t *); static void note_procstat_vmmap(void *, struct sbuf *, size_t *); -#ifdef GZIO -extern int compress_user_cores_gzlevel; - /* * Write out a core segment to the compression stream. */ @@ -1241,7 +1240,7 @@ error = copyin(base, buf, chunk_len); if (error != 0) bzero(buf, chunk_len); - error = gzio_write(p->gzs, buf, chunk_len); + error = compressor_write(p->comp, buf, chunk_len); if (error != 0) break; base += chunk_len; @@ -1251,13 +1250,12 @@ } static int -core_gz_write(void *base, size_t len, off_t offset, void *arg) +core_compressed_write(void *base, size_t len, off_t offset, void *arg) { return (core_write((struct coredump_params *)arg, base, len, offset, UIO_SYSSPACE)); } -#endif /* GZIO */ static int core_write(struct coredump_params *p, const void *base, size_t len, @@ -1275,10 +1273,9 @@ { int error; -#ifdef GZIO - if (p->gzs != NULL) + if (p->comp != NULL) return (compress_chunk(p, base, tmpbuf, len)); -#endif + /* * EFAULT is a non-fatal error that we can get, for example, * if the segment is backed by a file but extends beyond its @@ -1323,11 +1320,9 @@ locked = PROC_LOCKED(p->td->td_proc); if (locked) PROC_UNLOCK(p->td->td_proc); -#ifdef GZIO - if (p->gzs != NULL) - error = gzio_write(p->gzs, __DECONST(char *, data), len); + if (p->comp != NULL) + error = compressor_write(p->comp, __DECONST(char *, data), len); else -#endif error = core_write(p, __DECONST(void *, data), len, p->offset, UIO_SYSSPACE); if (locked) @@ -1362,11 +1357,7 @@ struct note_info *ninfo; void *hdr, *tmpbuf; size_t hdrsize, notesz, coresize; -#ifdef GZIO - boolean_t compress; - compress = (flags & IMGACT_CORE_COMPRESS) != 0; -#endif hdr = NULL; tmpbuf = NULL; TAILQ_INIT(¬elst); @@ -1391,7 +1382,7 @@ params.file_cred = NOCRED; params.td = td; params.vp = vp; - params.gzs = NULL; + params.comp = NULL; #ifdef RACCT if (racct_enable) { @@ -1409,18 +1400,17 @@ goto done; } -#ifdef GZIO /* Create a compression stream if necessary. */ - if (compress) { - params.gzs = gzio_init(core_gz_write, GZIO_DEFLATE, - CORE_BUF_SIZE, compress_user_cores_gzlevel, ¶ms); - if (params.gzs == NULL) { + if (compress_user_cores != 0) { + params.comp = compressor_init(core_compressed_write, + compress_user_cores, CORE_BUF_SIZE, + compress_user_cores_level, ¶ms); + if (params.comp == NULL) { error = EFAULT; goto done; } tmpbuf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO); } -#endif /* * Allocate memory for building the header, fill it up, @@ -1446,10 +1436,8 @@ offset += php->p_filesz; php++; } -#ifdef GZIO - if (error == 0 && compress) - error = gzio_flush(params.gzs); -#endif + if (error == 0 && params.comp != NULL) + error = compressor_flush(params.comp); } if (error) { log(LOG_WARNING, @@ -1458,13 +1446,9 @@ } done: -#ifdef GZIO - if (compress) { - free(tmpbuf, M_TEMP); - if (params.gzs != NULL) - gzio_fini(params.gzs); - } -#endif + free(tmpbuf, M_TEMP); + if (params.comp != NULL) + compressor_fini(params.comp); while ((ninfo = TAILQ_FIRST(¬elst)) != NULL) { TAILQ_REMOVE(¬elst, ninfo, link); free(ninfo, M_TEMP); Index: sys/kern/kern_shutdown.c =================================================================== --- sys/kern/kern_shutdown.c +++ sys/kern/kern_shutdown.c @@ -41,7 +41,6 @@ #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,10 +51,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -174,23 +173,21 @@ }; #endif -#ifdef GZIO -struct kerneldumpgz { - struct gzio_stream *kdgz_stream; - uint8_t *kdgz_buf; - size_t kdgz_resid; +struct kerneldumpcomp { + struct compressor *kdc_stream; + uint8_t *kdc_buf; + size_t kdc_resid; }; -static struct kerneldumpgz *kerneldumpgz_create(struct dumperinfo *di, +static struct kerneldumpcomp *kerneldumpcomp_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 void kerneldumpcomp_destroy(struct dumperinfo *di); +static int kerneldumpcomp_write_cb(void *base, 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 */ + "Kernel crash dump compression level"); /* * Variable panicstr contains argument to first call to panic; used as flag @@ -986,39 +983,37 @@ } #endif /* EKCD */ -#ifdef GZIO -static struct kerneldumpgz * -kerneldumpgz_create(struct dumperinfo *di, uint8_t compression) +static struct kerneldumpcomp * +kerneldumpcomp_create(struct dumperinfo *di, uint8_t compression) { - struct kerneldumpgz *kdgz; + struct kerneldumpcomp *kdcomp; 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); + kdcomp = malloc(sizeof(*kdcomp), M_DUMPER, M_WAITOK | M_ZERO); + kdcomp->kdc_stream = compressor_init(kerneldumpcomp_write_cb, + COMPRESS_GZIP, di->maxiosize, kerneldump_gzlevel, di); + if (kdcomp->kdc_stream == NULL) { + free(kdcomp, M_DUMPER); return (NULL); } - kdgz->kdgz_buf = malloc(di->maxiosize, M_DUMPER, M_WAITOK | M_NODUMP); - return (kdgz); + kdcomp->kdc_buf = malloc(di->maxiosize, M_DUMPER, M_WAITOK | M_NODUMP); + return (kdcomp); } static void -kerneldumpgz_destroy(struct dumperinfo *di) +kerneldumpcomp_destroy(struct dumperinfo *di) { - struct kerneldumpgz *kdgz; + struct kerneldumpcomp *kdcomp; - kdgz = di->kdgz; - if (kdgz == NULL) + kdcomp = di->kdcomp; + if (kdcomp == NULL) return; - gzio_fini(kdgz->kdgz_stream); - explicit_bzero(kdgz->kdgz_buf, di->maxiosize); - free(kdgz->kdgz_buf, M_DUMPER); - free(kdgz, M_DUMPER); + compressor_fini(kdcomp->kdc_stream); + explicit_bzero(kdcomp->kdc_buf, di->maxiosize); + free(kdcomp->kdc_buf, M_DUMPER); + free(kdcomp, M_DUMPER); } -#endif /* GZIO */ /* Registration of dumpers */ int @@ -1041,14 +1036,14 @@ return (EBUSY); dumper = *di; dumper.blockbuf = NULL; - dumper.kdc = NULL; - dumper.kdgz = NULL; + dumper.kdcrypto = NULL; + dumper.kdcomp = NULL; if (encryption != KERNELDUMP_ENC_NONE) { #ifdef EKCD - dumper.kdc = kerneldumpcrypto_create(di->blocksize, encryption, - key, encryptedkeysize, encryptedkey); - if (dumper.kdc == NULL) { + dumper.kdcrypto = kerneldumpcrypto_create(di->blocksize, + encryption, key, encryptedkeysize, encryptedkey); + if (dumper.kdcrypto == NULL) { error = EINVAL; goto cleanup; } @@ -1065,7 +1060,6 @@ } if (compression != KERNELDUMP_COMP_NONE) { -#ifdef GZIO /* * We currently can't support simultaneous encryption and * compression. @@ -1074,31 +1068,25 @@ error = EOPNOTSUPP; goto cleanup; } - dumper.kdgz = kerneldumpgz_create(&dumper, compression); - if (dumper.kdgz == NULL) { + dumper.kdcomp = kerneldumpcomp_create(&dumper, compression); + if (dumper.kdcomp == 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: #ifdef EKCD - if (dumper.kdc != NULL) { - explicit_bzero(dumper.kdc, sizeof(*dumper.kdc) + - dumper.kdc->kdc_dumpkeysize); - free(dumper.kdc, M_EKCD); + if (dumper.kdcrypto != NULL) { + explicit_bzero(dumper.kdcrypto, sizeof(*dumper.kdcrypto) + + dumper.kdcrypto->kdc_dumpkeysize); + free(dumper.kdcrypto, M_EKCD); } #endif -#ifdef GZIO - kerneldumpgz_destroy(&dumper); -#endif + kerneldumpcomp_destroy(&dumper); if (dumper.blockbuf != NULL) { explicit_bzero(dumper.blockbuf, dumper.blocksize); @@ -1168,7 +1156,7 @@ int error; size_t nbytes; - kdc = di->kdc; + kdc = di->kdcrypto; while (length > 0) { nbytes = MIN(length, sizeof(buf)); @@ -1194,7 +1182,7 @@ { struct kerneldumpcrypto *kdc; - kdc = di->kdc; + kdc = di->kdcrypto; if (kdc == NULL) return (0); return (dump_write(di, kdc->kdc_dumpkey, 0, offset, @@ -1202,9 +1190,8 @@ } #endif /* EKCD */ -#ifdef GZIO static int -kerneldumpgz_write_cb(void *base, size_t length, off_t offset, void *arg) +kerneldumpcomp_write_cb(void *base, size_t length, off_t offset, void *arg) { struct dumperinfo *di; size_t resid, rlength; @@ -1227,12 +1214,11 @@ } resid = length - rlength; memmove(di->blockbuf, (uint8_t *)base + rlength, resid); - di->kdgz->kdgz_resid = resid; + di->kdcomp->kdc_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 @@ -1290,10 +1276,10 @@ uint32_t keysize; #ifdef EKCD - int error = kerneldumpcrypto_init(di->kdc); + int error = kerneldumpcrypto_init(di->kdcrypto); if (error != 0) return (error); - keysize = kerneldumpcrypto_dumpkeysize(di->kdc); + keysize = kerneldumpcrypto_dumpkeysize(di->kdcrypto); #else keysize = 0; #endif @@ -1301,8 +1287,7 @@ dumpextent = dtoh64(kdh->dumpextent); if (di->mediasize < SIZEOF_METADATA + dumpextent + 2 * di->blocksize + keysize) { -#ifdef GZIO - if (di->kdgz != NULL) { + if (di->kdcomp != NULL) { /* * We don't yet know how much space the compressed dump * will occupy, so try to use the whole swap partition @@ -1315,7 +1300,6 @@ 2 * di->blocksize - keysize; kdh->dumpextent = htod64(dumpextent); } else -#endif return (E2BIG); } @@ -1333,7 +1317,7 @@ int error; #ifdef EKCD - if (di->kdc != NULL) + if (di->kdcrypto != NULL) error = dump_encrypted_write(di, virtual, physical, di->dumpoff, length); else @@ -1353,18 +1337,16 @@ 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 (di->kdcomp != NULL) { + /* Bounce through a buffer to avoid CRC errors. */ if (length > di->maxiosize) return (EINVAL); - buf = di->kdgz->kdgz_buf; + buf = di->kdcomp->kdc_buf; memmove(buf, virtual, length); - return (gzio_write(di->kdgz->kdgz_stream, buf, length)); + return (compressor_write(di->kdcomp->kdc_stream, buf, length)); } -#endif return (_dump_append(di, virtual, physical, length)); } @@ -1399,20 +1381,19 @@ extent = dtoh64(kdh->dumpextent); #ifdef EKCD - keysize = kerneldumpcrypto_dumpkeysize(di->kdc); + keysize = kerneldumpcrypto_dumpkeysize(di->kdcrypto); #else keysize = 0; #endif -#ifdef GZIO - if (di->kdgz != NULL) { - error = gzio_flush(di->kdgz->kdgz_stream); + if (di->kdcomp != NULL) { + error = compressor_flush(di->kdcomp->kdc_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; + di->dumpoff += di->kdcomp->kdc_resid; + di->kdcomp->kdc_resid = 0; } if (error != 0) return (error); @@ -1426,9 +1407,8 @@ kdh->parity = 0; kdh->parity = kerneldump_parity(kdh); - gzio_reset(di->kdgz->kdgz_stream); + compressor_reset(di->kdcomp->kdc_stream); } -#endif /* * Write kerneldump headers at the beginning and end of the dump extent. @@ -1471,7 +1451,7 @@ kdh->dumpextent = kdh->dumplength; kdh->dumptime = htod64(time_second); #ifdef EKCD - kdh->dumpkeysize = htod32(kerneldumpcrypto_dumpkeysize(di->kdc)); + kdh->dumpkeysize = htod32(kerneldumpcrypto_dumpkeysize(di->kdcrypto)); #else kdh->dumpkeysize = 0; #endif @@ -1482,10 +1462,8 @@ kdh->versionstring[dstsize - 2] = '\n'; if (panicstr != NULL) strlcpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); -#ifdef GZIO - if (di->kdgz != NULL) + if (di->kdcomp != NULL) kdh->compression = KERNELDUMP_COMP_GZIP; -#endif kdh->parity = kerneldump_parity(kdh); } Index: sys/kern/kern_sig.c =================================================================== --- sys/kern/kern_sig.c +++ sys/kern/kern_sig.c @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); #include "opt_compat.h" -#include "opt_gzio.h" #include "opt_ktrace.h" #include @@ -51,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -3255,17 +3255,30 @@ #define GZ_SUFFIX ".gz" -#ifdef GZIO -static int compress_user_cores = 1; -SYSCTL_INT(_kern, OID_AUTO, compress_user_cores, CTLFLAG_RWTUN, - &compress_user_cores, 0, "Compression of user corefiles"); +int compress_user_cores = 0; -int compress_user_cores_gzlevel = 6; -SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_gzlevel, CTLFLAG_RWTUN, - &compress_user_cores_gzlevel, 0, "Corefile gzip compression level"); -#else -static int compress_user_cores = 0; -#endif +static int +sysctl_compress_user_cores(SYSCTL_HANDLER_ARGS) +{ + int error, val; + + val = compress_user_cores; + error = sysctl_handle_int(oidp, &val, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + if (val != 0 && !compressor_avail(val)) + return (EINVAL); + compress_user_cores = val; + return (error); +} +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)"); + +int compress_user_cores_level = 6; +SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_level, CTLFLAG_RWTUN, + &compress_user_cores_level, 0, + "Corefile compression level"); /* * Protect the access to corefilename[] by allproc_lock. @@ -3363,7 +3376,7 @@ } sx_sunlock(&corefilename_lock); free(hostname, M_TEMP); - if (compress) + if (compress == COMPRESS_GZIP) sbuf_printf(&sb, GZ_SUFFIX); if (sbuf_error(&sb) != 0) { log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too " @@ -3529,8 +3542,7 @@ PROC_UNLOCK(p); if (p->p_sysent->sv_coredump != NULL) { - error = p->p_sysent->sv_coredump(td, vp, limit, - compress_user_cores ? IMGACT_CORE_COMPRESS : 0); + error = p->p_sysent->sv_coredump(td, vp, limit, 0); } else { error = ENOSYS; } Index: sys/kern/subr_compressor.c =================================================================== --- sys/kern/subr_compressor.c +++ sys/kern/subr_compressor.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2014 Mark Johnston + * Copyright (c) 2014, 2017 Mark Johnston * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -24,55 +24,87 @@ * SUCH DAMAGE. */ +/* + * Subroutines used for writing compressed user process and kernel core dumps. + */ + #include __FBSDID("$FreeBSD$"); +#include "opt_gzio.h" + #include -#include +#include #include +#include #include -#include -#define KERN_GZ_HDRLEN 10 /* gzip header length */ -#define KERN_GZ_TRAILERLEN 8 /* gzip trailer length */ -#define KERN_GZ_MAGIC1 0x1f /* first magic byte */ -#define KERN_GZ_MAGIC2 0x8b /* second magic byte */ +MALLOC_DEFINE(M_COMPRESS, "compressor", "kernel compression subroutines"); + +struct compressor_methods { + int format; + void *(* const init)(size_t, int); + void (* const reset)(void *); + int (* const write)(void *, void *, size_t, compressor_cb_t, void *); + void (* const fini)(void *); +}; + +struct compressor { + const struct compressor_methods *methods; + compressor_cb_t cb; + void *priv; + void *arg; +}; -MALLOC_DEFINE(M_GZIO, "gzio", "zlib state"); +SET_DECLARE(compressors, struct compressor_methods); -struct gzio_stream { - uint8_t * gz_buffer; /* output buffer */ - size_t gz_bufsz; /* total buffer size */ +#ifdef GZIO + +#include + +struct gz_stream { + uint8_t *gz_buffer; /* output buffer */ + size_t gz_bufsz; /* output buffer size */ off_t gz_off; /* offset into the output stream */ - enum gzio_mode gz_mode; /* stream mode */ uint32_t gz_crc; /* stream CRC32 */ - gzio_cb gz_cb; /* output callback */ - void * gz_arg; /* private callback arg */ z_stream gz_stream; /* zlib state */ }; -static void * gz_alloc(void *, u_int, u_int); -static void gz_free(void *, void *); -static int gz_write(struct gzio_stream *, void *, u_int, int); +static void *gz_init(size_t maxiosize, int level); +static void gz_reset(void *stream); +static int gz_write(void *stream, void *data, size_t len, compressor_cb_t, + void *); +static void gz_fini(void *stream); -struct gzio_stream * -gzio_init(gzio_cb cb, enum gzio_mode mode, size_t bufsz, int level, void *arg) +static void * +gz_alloc(void *arg __unused, u_int n, u_int sz) { - struct gzio_stream *s; - int error; - if (bufsz < KERN_GZ_HDRLEN) - return (NULL); - if (mode != GZIO_DEFLATE) - return (NULL); + /* + * Memory for zlib state is allocated using M_NODUMP since it may be + * used to compress a kernel dump, and we don't want zlib to attempt to + * compress its own state. + */ + return (malloc(n * sz, M_COMPRESS, M_WAITOK | M_ZERO | M_NODUMP)); +} - s = gz_alloc(NULL, 1, sizeof(*s)); - s->gz_bufsz = bufsz; - s->gz_buffer = gz_alloc(NULL, 1, s->gz_bufsz); - s->gz_mode = mode; - s->gz_cb = cb; - s->gz_arg = arg; +static void +gz_free(void *arg __unused, void *ptr) +{ + + free(ptr, M_COMPRESS); +} + +static void * +gz_init(size_t maxiosize, int level) +{ + struct gz_stream *s; + int error; + + s = gz_alloc(NULL, 1, roundup2(sizeof(*s), PAGE_SIZE)); + s->gz_buffer = gz_alloc(NULL, 1, maxiosize); + s->gz_bufsz = maxiosize; s->gz_stream.zalloc = gz_alloc; s->gz_stream.zfree = gz_free; @@ -85,98 +117,57 @@ if (error != 0) goto fail; - gzio_reset(s); + gz_reset(s); return (s); fail: - gz_free(NULL, s->gz_buffer); gz_free(NULL, s); return (NULL); } -void -gzio_reset(struct gzio_stream *s) +static void +gz_reset(void *stream) { + struct gz_stream *s; uint8_t *hdr; + const size_t hdrlen = 10; - (void)deflateReset(&s->gz_stream); - + s = stream; s->gz_off = 0; s->gz_crc = ~0U; + (void)deflateReset(&s->gz_stream); s->gz_stream.avail_out = s->gz_bufsz; s->gz_stream.next_out = s->gz_buffer; /* Write the gzip header to the output buffer. */ hdr = s->gz_buffer; - memset(hdr, 0, KERN_GZ_HDRLEN); - hdr[0] = KERN_GZ_MAGIC1; - hdr[1] = KERN_GZ_MAGIC2; + memset(hdr, 0, hdrlen); + hdr[0] = 0x1f; + hdr[1] = 0x8b; hdr[2] = Z_DEFLATED; hdr[9] = OS_CODE; - s->gz_stream.next_out += KERN_GZ_HDRLEN; - s->gz_stream.avail_out -= KERN_GZ_HDRLEN; -} - -int -gzio_write(struct gzio_stream *s, void *data, u_int len) -{ - - return (gz_write(s, data, len, Z_NO_FLUSH)); -} - -int -gzio_flush(struct gzio_stream *s) -{ - - return (gz_write(s, NULL, 0, Z_FINISH)); -} - -void -gzio_fini(struct gzio_stream *s) -{ - - (void)deflateEnd(&s->gz_stream); - gz_free(NULL, s->gz_buffer); - gz_free(NULL, s); -} - -static void * -gz_alloc(void *arg __unused, u_int n, u_int sz) -{ - - /* - * Memory for zlib state is allocated using M_NODUMP since it may be - * used to compress a kernel dump, and we don't want zlib to attempt to - * compress its own state. - */ - return (malloc(n * sz, M_GZIO, M_WAITOK | M_ZERO | M_NODUMP)); -} - -static void -gz_free(void *arg __unused, void *ptr) -{ - - free(ptr, M_GZIO); + s->gz_stream.next_out += hdrlen; + s->gz_stream.avail_out -= hdrlen; } static int -gz_write(struct gzio_stream *s, void *buf, u_int len, int zflag) +gz_write(void *stream, void *data, size_t len, compressor_cb_t cb, + void *arg) { - uint8_t trailer[KERN_GZ_TRAILERLEN]; + struct gz_stream *s; + uint8_t trailer[8]; size_t room; - int error, zerror; + int error, zerror, zflag; - KASSERT(zflag == Z_FINISH || zflag == Z_NO_FLUSH, - ("unexpected flag %d", zflag)); - KASSERT(s->gz_mode == GZIO_DEFLATE, - ("invalid stream mode %d", s->gz_mode)); + s = stream; + zflag = data == NULL ? Z_FINISH : Z_NO_FLUSH; if (len > 0) { s->gz_stream.avail_in = len; - s->gz_stream.next_in = buf; - s->gz_crc = crc32_raw(buf, len, s->gz_crc); + s->gz_stream.next_in = data; + s->gz_crc = crc32_raw(data, len, s->gz_crc); } else s->gz_crc ^= ~0U; @@ -202,14 +193,13 @@ ((uint32_t *)trailer)[0] = s->gz_crc; ((uint32_t *)trailer)[1] = s->gz_stream.total_in; - room = MIN(KERN_GZ_TRAILERLEN, + room = MIN(sizeof(trailer), s->gz_bufsz - len); memcpy(s->gz_buffer + len, trailer, room); len += room; } - error = s->gz_cb(s->gz_buffer, len, s->gz_off, - s->gz_arg); + error = cb(s->gz_buffer, len, s->gz_off, arg); if (error != 0) break; @@ -221,13 +211,103 @@ * If we couldn't pack the trailer into the output * buffer, write it out now. */ - if (zerror == Z_STREAM_END && room < KERN_GZ_TRAILERLEN) - error = s->gz_cb(trailer + room, - KERN_GZ_TRAILERLEN - room, s->gz_off, - s->gz_arg); + if (zerror == Z_STREAM_END && room < sizeof(trailer)) + error = cb(trailer + room, + sizeof(trailer) - room, s->gz_off, arg); } } while (zerror != Z_STREAM_END && (zflag == Z_FINISH || s->gz_stream.avail_in > 0)); return (error); } + +static void +gz_fini(void *stream) +{ + struct gz_stream *s; + + s = stream; + (void)deflateEnd(&s->gz_stream); + gz_free(NULL, s->gz_buffer); + gz_free(NULL, s); +} + +struct compressor_methods gzip_methods = { + .format = COMPRESS_GZIP, + .init = gz_init, + .reset = gz_reset, + .write = gz_write, + .fini = gz_fini, +}; +DATA_SET(compressors, gzip_methods); + +#endif /* GZIO */ + +bool +compressor_avail(int format) +{ + struct compressor_methods **iter; + + SET_FOREACH(iter, compressors) { + if ((*iter)->format == format) + return (true); + } + return (false); +} + +struct compressor * +compressor_init(compressor_cb_t cb, int format, size_t maxiosize, int level, + void *arg) +{ + struct compressor_methods **iter; + struct compressor *s; + void *priv; + + SET_FOREACH(iter, compressors) { + if ((*iter)->format == format) + break; + } + if (iter == NULL) + return (NULL); + + priv = (*iter)->init(maxiosize, level); + if (priv == NULL) + return (NULL); + + s = malloc(sizeof(*s), M_COMPRESS, M_WAITOK | M_ZERO); + s->methods = (*iter); + s->priv = priv; + s->cb = cb; + s->arg = arg; + return (s); +} + +void +compressor_reset(struct compressor *stream) +{ + + stream->methods->reset(stream->priv); +} + +int +compressor_write(struct compressor *stream, void *data, size_t len) +{ + + return (stream->methods->write(stream->priv, data, len, stream->cb, + stream->arg)); +} + +int +compressor_flush(struct compressor *stream) +{ + + return (stream->methods->write(stream->priv, NULL, 0, stream->cb, + stream->arg)); +} + +void +compressor_fini(struct compressor *stream) +{ + + stream->methods->fini(stream->priv); +} Index: sys/sys/compressor.h =================================================================== --- sys/sys/compressor.h +++ sys/sys/compressor.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2014 Mark Johnston + * Copyright (c) 2014, 2017 Mark Johnston * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,25 +28,26 @@ * $FreeBSD$ */ -#ifndef _SYS__GZIO_H_ -#define _SYS__GZIO_H_ +#ifndef _SYS__COMPRESSOR_H_ +#define _SYS__COMPRESSOR_H_ #ifdef _KERNEL -enum gzio_mode { - GZIO_DEFLATE, -}; +/* Supported formats. */ +#define COMPRESS_GZIP 1 -typedef int (*gzio_cb)(void *, size_t, off_t, void *); +typedef int (*compressor_cb_t)(void *, size_t, off_t, void *); -struct gzio_stream; +struct compressor; -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 *); +bool compressor_avail(int format); +struct compressor *compressor_init(compressor_cb_t cb, int format, + size_t maxiosize, int level, void *arg); +void compressor_reset(struct compressor *stream); +int compressor_write(struct compressor *stream, void *data, + size_t len); +int compressor_flush(struct compressor *stream); +void compressor_fini(struct compressor *stream); #endif /* _KERNEL */ - -#endif /* _SYS__GZIO_H_ */ +#endif /* _SYS__COMPRESSOR_H_ */ Index: sys/sys/conf.h =================================================================== --- sys/sys/conf.h +++ sys/sys/conf.h @@ -339,8 +339,8 @@ off_t mediasize; /* Space available in bytes. */ 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. */ + struct kerneldumpcrypto *kdcrypto; /* Kernel dump crypto. */ + struct kerneldumpcomp *kdcomp; /* Kernel dump compression. */ }; extern int dumping; /* system is dumping */ Index: sys/sys/imgact.h =================================================================== --- sys/sys/imgact.h +++ sys/sys/imgact.h @@ -96,8 +96,6 @@ struct thread; struct vmspace; -#define IMGACT_CORE_COMPRESS 0x01 - int exec_alloc_args(struct image_args *); int exec_check_permissions(struct image_params *); register_t *exec_copyout_strings(struct image_params *);