38#include "opt_zstdio.h"
43#include <sys/compressor.h>
44#include <sys/endian.h>
45#include <sys/kernel.h>
46#include <sys/linker_set.h>
47#include <sys/malloc.h>
49MALLOC_DEFINE(M_COMPRESS,
"compressor",
"kernel compression subroutines");
53 void *(*
const init)(
size_t,
int);
55 int (*
const write)(
void *,
void *, size_t, compressor_cb_t,
void *);
56 void (*
const fini)(
void *);
70#include <contrib/zlib/zutil.h>
80static void *gz_init(
size_t maxiosize,
int level);
81static void gz_reset(
void *stream);
82static int gz_write(
void *stream,
void *
data,
size_t len, compressor_cb_t,
84static void gz_fini(
void *stream);
87gz_alloc(
void *arg __unused, u_int n, u_int sz)
95 return (
malloc(n * sz, M_COMPRESS, M_WAITOK | M_ZERO | M_NODUMP));
99gz_free(
void *arg __unused,
void *ptr)
102 free(ptr, M_COMPRESS);
106gz_init(
size_t maxiosize,
int level)
111 s = gz_alloc(NULL, 1, roundup2(
sizeof(*s), PAGE_SIZE));
112 s->gz_buffer = gz_alloc(NULL, 1, maxiosize);
113 s->gz_bufsz = maxiosize;
115 s->gz_stream.zalloc = gz_alloc;
116 s->gz_stream.zfree = gz_free;
117 s->gz_stream.opaque = NULL;
118 s->gz_stream.next_in = Z_NULL;
119 s->gz_stream.avail_in = 0;
121 if (
level != Z_DEFAULT_COMPRESSION) {
122 if (
level < Z_BEST_SPEED)
123 level = Z_BEST_SPEED;
124 else if (
level > Z_BEST_COMPRESSION)
125 level = Z_BEST_COMPRESSION;
128 error = deflateInit2(&s->gz_stream,
level, Z_DEFLATED, -MAX_WBITS,
129 DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
143gz_reset(
void *stream)
147 const size_t hdrlen = 10;
151 s->gz_crc = crc32(0L, Z_NULL, 0);
153 (void)deflateReset(&s->gz_stream);
154 s->gz_stream.avail_out = s->gz_bufsz;
155 s->gz_stream.next_out = s->gz_buffer;
159 memset(hdr, 0, hdrlen);
164 s->gz_stream.next_out += hdrlen;
165 s->gz_stream.avail_out -= hdrlen;
169gz_write(
void *stream,
void *
data,
size_t len, compressor_cb_t cb,
175 int error, zerror, zflag;
178 zflag =
data == NULL ? Z_FINISH : Z_NO_FLUSH;
181 s->gz_stream.avail_in = len;
182 s->gz_stream.next_in =
data;
183 s->gz_crc = crc32(s->gz_crc,
data, len);
188 zerror = deflate(&s->gz_stream, zflag);
189 if (zerror != Z_OK && zerror != Z_STREAM_END) {
194 if (s->gz_stream.avail_out == 0 || zerror == Z_STREAM_END) {
199 len = s->gz_bufsz - s->gz_stream.avail_out;
200 if (zerror == Z_STREAM_END) {
205 ((uint32_t *)trailer)[0] = htole32(s->gz_crc);
206 ((uint32_t *)trailer)[1] =
207 htole32(s->gz_stream.total_in);
208 room = MIN(
sizeof(trailer),
210 memcpy(s->gz_buffer + len, trailer, room);
214 error = cb(s->gz_buffer, len, s->gz_off, arg);
219 s->gz_stream.next_out = s->gz_buffer;
220 s->gz_stream.avail_out = s->gz_bufsz;
226 if (zerror == Z_STREAM_END && room <
sizeof(trailer))
227 error = cb(trailer + room,
228 sizeof(trailer) - room, s->gz_off, arg);
230 }
while (zerror != Z_STREAM_END &&
231 (zflag == Z_FINISH || s->gz_stream.avail_in > 0));
242 (void)deflateEnd(&s->gz_stream);
243 gz_free(NULL, s->gz_buffer);
254DATA_SET(compressors, gzip_methods);
260#define ZSTD_STATIC_LINKING_ONLY
261#include <contrib/zstd/lib/zstd.h>
263struct zstdio_stream {
264 ZSTD_CCtx *zst_stream;
265 ZSTD_inBuffer zst_inbuffer;
266 ZSTD_outBuffer zst_outbuffer;
267 uint8_t * zst_buffer;
270 void * zst_static_wkspc;
273static void *zstdio_init(
size_t maxiosize,
int level);
274static void zstdio_reset(
void *stream);
275static int zstdio_write(
void *stream,
void *
data,
size_t len,
276 compressor_cb_t,
void *);
277static void zstdio_fini(
void *stream);
280zstdio_init(
size_t maxiosize,
int level)
282 ZSTD_CCtx *dump_compressor;
283 struct zstdio_stream *s;
284 void *wkspc, *owkspc, *buffer;
285 size_t wkspc_size, buf_size, rc;
288 wkspc_size = ZSTD_estimateCStreamSize(
level);
289 owkspc = wkspc =
malloc(wkspc_size + 8, M_COMPRESS,
290 M_WAITOK | M_NODUMP);
292 if ((uintptr_t)wkspc % 8 != 0)
293 wkspc = (
void *)roundup2((uintptr_t)wkspc, 8);
295 dump_compressor = ZSTD_initStaticCCtx(wkspc, wkspc_size);
296 if (dump_compressor == NULL) {
297 printf(
"%s: workspace too small.\n", __func__);
301 rc = ZSTD_CCtx_setParameter(dump_compressor, ZSTD_c_checksumFlag, 1);
302 if (ZSTD_isError(rc)) {
303 printf(
"%s: error setting checksumFlag: %s\n", __func__,
304 ZSTD_getErrorName(rc));
307 rc = ZSTD_CCtx_setParameter(dump_compressor, ZSTD_c_compressionLevel,
309 if (ZSTD_isError(rc)) {
310 printf(
"%s: error setting compressLevel: %s\n", __func__,
311 ZSTD_getErrorName(rc));
315 buf_size = ZSTD_CStreamOutSize() * 2;
316 buffer =
malloc(buf_size, M_COMPRESS, M_WAITOK | M_NODUMP);
318 s =
malloc(
sizeof(*s), M_COMPRESS, M_NODUMP | M_WAITOK);
319 s->zst_buffer = buffer;
320 s->zst_outbuffer.dst = buffer;
321 s->zst_outbuffer.size = buf_size;
322 s->zst_maxiosz = maxiosize;
323 s->zst_stream = dump_compressor;
324 s->zst_static_wkspc = owkspc;
330 free(owkspc, M_COMPRESS);
335zstdio_reset(
void *stream)
337 struct zstdio_stream *s;
341 res = ZSTD_resetCStream(s->zst_stream, 0);
342 if (ZSTD_isError(
res))
343 panic(
"%s: could not reset stream %p: %s\n", __func__, s,
344 ZSTD_getErrorName(
res));
347 s->zst_inbuffer.src = NULL;
348 s->zst_inbuffer.size = 0;
349 s->zst_inbuffer.pos = 0;
350 s->zst_outbuffer.pos = 0;
354zst_flush_intermediate(
struct zstdio_stream *s, compressor_cb_t cb,
void *arg)
356 size_t bytes_to_dump;
361 while (s->zst_outbuffer.pos >= 4096) {
362 bytes_to_dump = rounddown(s->zst_outbuffer.pos, 4096);
364 if (bytes_to_dump > s->zst_maxiosz)
365 bytes_to_dump = s->zst_maxiosz;
367 error = cb(s->zst_buffer, bytes_to_dump, s->zst_off, arg);
375 s->zst_outbuffer.pos -= bytes_to_dump;
376 memmove(s->zst_outbuffer.dst,
377 (
char *)s->zst_outbuffer.dst + bytes_to_dump,
378 s->zst_outbuffer.pos);
379 s->zst_off += bytes_to_dump;
385zstdio_flush(
struct zstdio_stream *s, compressor_cb_t cb,
void *arg)
395 lastpos = s->zst_outbuffer.pos;
397 rc = ZSTD_endStream(s->zst_stream, &s->zst_outbuffer);
398 if (ZSTD_isError(rc)) {
399 printf(
"%s: ZSTD_endStream failed (%s)\n", __func__,
400 ZSTD_getErrorName(rc));
403 if (lastpos == s->zst_outbuffer.pos) {
404 printf(
"%s: did not make forward progress endStream %zu\n",
409 error = zst_flush_intermediate(s, cb, arg);
413 lastpos = s->zst_outbuffer.pos;
421 if (s->zst_outbuffer.pos != 0) {
422 error = cb(s->zst_buffer, s->zst_outbuffer.pos, s->zst_off,
432zstdio_write(
void *stream,
void *
data,
size_t len, compressor_cb_t cb,
435 struct zstdio_stream *s;
441 return (zstdio_flush(s, cb, arg));
443 s->zst_inbuffer.src =
data;
444 s->zst_inbuffer.size = len;
445 s->zst_inbuffer.pos = 0;
448 while (s->zst_inbuffer.pos < s->zst_inbuffer.size) {
449 rc = ZSTD_compressStream(s->zst_stream, &s->zst_outbuffer,
451 if (ZSTD_isError(rc)) {
452 printf(
"%s: Compress failed on %p! (%s)\n",
453 __func__,
data, ZSTD_getErrorName(rc));
457 if (lastpos == s->zst_inbuffer.pos) {
461 printf(
"ZSTD: did not make forward progress @pos %zu\n",
465 lastpos = s->zst_inbuffer.pos;
467 error = zst_flush_intermediate(s, cb, arg);
475zstdio_fini(
void *stream)
477 struct zstdio_stream *s;
480 if (s->zst_static_wkspc != NULL)
481 free(s->zst_static_wkspc, M_COMPRESS);
483 ZSTD_freeCCtx(s->zst_stream);
484 free(s->zst_buffer, M_COMPRESS);
491 .reset = zstdio_reset,
492 .write = zstdio_write,
495DATA_SET(compressors, zstd_methods);
504 SET_FOREACH(iter, compressors) {
505 if ((*iter)->format ==
format)
519 SET_FOREACH(iter, compressors) {
520 if ((*iter)->format == format)
523 if (iter == SET_LIMIT(compressors))
530 s =
malloc(
sizeof(*s), M_COMPRESS, M_WAITOK | M_ZERO);
const struct cf_level * level
void *() malloc(size_t size, struct malloc_type *mtp, int flags)
void free(void *addr, struct malloc_type *mtp)
void panic(const char *fmt,...)
void(*const fini)(void *)
int(*const write)(void *, void *, size_t, compressor_cb_t, void *)
void *(*const init)(size_t, int)
void(*const reset)(void *)
const struct compressor_methods * methods
int compressor_flush(struct compressor *stream)
MALLOC_DEFINE(M_COMPRESS, "compressor", "kernel compression subroutines")
SET_DECLARE(compressors, struct compressor_methods)
void compressor_reset(struct compressor *stream)
void compressor_fini(struct compressor *stream)
int compressor_write(struct compressor *stream, void *data, size_t len)
bool compressor_avail(int format)
struct compressor * compressor_init(compressor_cb_t cb, int format, size_t maxiosize, int level, void *arg)
int printf(const char *fmt,...)