subr_compressor.c (c79126f2e4b31976a54d1c30961d8c7b0f740a3c) | subr_compressor.c (6026dcd7ca888f3433f4df34ede69a77c1eb7701) |
---|---|
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2014, 2017 Mark Johnston <markj@FreeBSD.org> | 1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2014, 2017 Mark Johnston <markj@FreeBSD.org> |
5 * Copyright (c) 2017 Conrad Meyer <cem@FreeBSD.org> |
|
5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in --- 16 unchanged lines hidden (view full) --- 29/* 30 * Subroutines used for writing compressed user process and kernel core dumps. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD$"); 35 36#include "opt_gzio.h" | 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in --- 16 unchanged lines hidden (view full) --- 30/* 31 * Subroutines used for writing compressed user process and kernel core dumps. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD$"); 36 37#include "opt_gzio.h" |
38#include "opt_zstdio.h" |
|
37 38#include <sys/param.h> | 39 40#include <sys/param.h> |
41#include <sys/systm.h> |
|
39 40#include <sys/compressor.h> 41#include <sys/kernel.h> 42#include <sys/linker_set.h> 43#include <sys/malloc.h> 44 45MALLOC_DEFINE(M_COMPRESS, "compressor", "kernel compression subroutines"); 46 --- 193 unchanged lines hidden (view full) --- 240 .reset = gz_reset, 241 .write = gz_write, 242 .fini = gz_fini, 243}; 244DATA_SET(compressors, gzip_methods); 245 246#endif /* GZIO */ 247 | 42 43#include <sys/compressor.h> 44#include <sys/kernel.h> 45#include <sys/linker_set.h> 46#include <sys/malloc.h> 47 48MALLOC_DEFINE(M_COMPRESS, "compressor", "kernel compression subroutines"); 49 --- 193 unchanged lines hidden (view full) --- 243 .reset = gz_reset, 244 .write = gz_write, 245 .fini = gz_fini, 246}; 247DATA_SET(compressors, gzip_methods); 248 249#endif /* GZIO */ 250 |
251#ifdef ZSTDIO 252 253#define ZSTD_STATIC_LINKING_ONLY 254#include <contrib/zstd/lib/zstd.h> 255 256struct zstdio_stream { 257 ZSTD_CCtx *zst_stream; 258 ZSTD_inBuffer zst_inbuffer; 259 ZSTD_outBuffer zst_outbuffer; 260 uint8_t * zst_buffer; /* output buffer */ 261 size_t zst_maxiosz; /* Max output IO size */ 262 off_t zst_off; /* offset into the output stream */ 263 void * zst_static_wkspc; 264}; 265 266static void *zstdio_init(size_t maxiosize, int level); 267static void zstdio_reset(void *stream); 268static int zstdio_write(void *stream, void *data, size_t len, 269 compressor_cb_t, void *); 270static void zstdio_fini(void *stream); 271 272static void * 273zstdio_init(size_t maxiosize, int level) 274{ 275 ZSTD_CCtx *dump_compressor; 276 struct zstdio_stream *s; 277 void *wkspc, *owkspc, *buffer; 278 size_t wkspc_size, buf_size; 279 280 wkspc_size = ZSTD_estimateCStreamSize(level); 281 owkspc = wkspc = malloc(wkspc_size + 8, M_COMPRESS, 282 M_WAITOK | M_NODUMP); 283 /* Zstd API requires 8-byte alignment. */ 284 if ((uintptr_t)wkspc % 8 != 0) 285 wkspc = (void *)roundup2((uintptr_t)wkspc, 8); 286 287 dump_compressor = ZSTD_initStaticCCtx(wkspc, wkspc_size); 288 if (dump_compressor == NULL) { 289 free(owkspc, M_COMPRESS); 290 printf("%s: workspace too small.\n", __func__); 291 return (NULL); 292 } 293 294 (void)ZSTD_CCtx_setParameter(dump_compressor, ZSTD_p_checksumFlag, 1); 295 296 buf_size = ZSTD_CStreamOutSize() * 2; 297 buffer = malloc(buf_size, M_COMPRESS, M_WAITOK | M_NODUMP); 298 299 s = malloc(sizeof(*s), M_COMPRESS, M_NODUMP | M_WAITOK); 300 s->zst_buffer = buffer; 301 s->zst_outbuffer.dst = buffer; 302 s->zst_outbuffer.size = buf_size; 303 s->zst_maxiosz = maxiosize; 304 s->zst_stream = dump_compressor; 305 s->zst_static_wkspc = owkspc; 306 307 zstdio_reset(s); 308 309 return (s); 310} 311 312static void 313zstdio_reset(void *stream) 314{ 315 struct zstdio_stream *s; 316 size_t res; 317 318 s = stream; 319 res = ZSTD_resetCStream(s->zst_stream, 0); 320 if (ZSTD_isError(res)) 321 panic("%s: could not reset stream %p: %s\n", __func__, s, 322 ZSTD_getErrorName(res)); 323 324 s->zst_off = 0; 325 s->zst_inbuffer.src = NULL; 326 s->zst_inbuffer.size = 0; 327 s->zst_inbuffer.pos = 0; 328 s->zst_outbuffer.pos = 0; 329} 330 331static int 332zst_flush_intermediate(struct zstdio_stream *s, compressor_cb_t cb, void *arg) 333{ 334 size_t bytes_to_dump; 335 int error; 336 337 /* Flush as many full output blocks as possible. */ 338 /* XXX: 4096 is arbitrary safe HDD block size for kernel dumps */ 339 while (s->zst_outbuffer.pos >= 4096) { 340 bytes_to_dump = rounddown(s->zst_outbuffer.pos, 4096); 341 342 if (bytes_to_dump > s->zst_maxiosz) 343 bytes_to_dump = s->zst_maxiosz; 344 345 error = cb(s->zst_buffer, bytes_to_dump, s->zst_off, arg); 346 if (error != 0) 347 return (error); 348 349 /* 350 * Shift any non-full blocks up to the front of the output 351 * buffer. 352 */ 353 s->zst_outbuffer.pos -= bytes_to_dump; 354 memmove(s->zst_outbuffer.dst, 355 (char *)s->zst_outbuffer.dst + bytes_to_dump, 356 s->zst_outbuffer.pos); 357 s->zst_off += bytes_to_dump; 358 } 359 return (0); 360} 361 362static int 363zstdio_flush(struct zstdio_stream *s, compressor_cb_t cb, void *arg) 364{ 365 size_t rc, lastpos; 366 int error; 367 368 /* 369 * Positive return indicates unflushed data remaining; need to call 370 * endStream again after clearing out room in output buffer. 371 */ 372 rc = 1; 373 lastpos = s->zst_outbuffer.pos; 374 while (rc > 0) { 375 rc = ZSTD_endStream(s->zst_stream, &s->zst_outbuffer); 376 if (ZSTD_isError(rc)) { 377 printf("%s: ZSTD_endStream failed (%s)\n", __func__, 378 ZSTD_getErrorName(rc)); 379 return (EIO); 380 } 381 if (lastpos == s->zst_outbuffer.pos) { 382 printf("%s: did not make forward progress endStream %zu\n", 383 __func__, lastpos); 384 return (EIO); 385 } 386 387 error = zst_flush_intermediate(s, cb, arg); 388 if (error != 0) 389 return (error); 390 391 lastpos = s->zst_outbuffer.pos; 392 } 393 394 /* 395 * We've already done an intermediate flush, so all full blocks have 396 * been written. Only a partial block remains. Padding happens in a 397 * higher layer. 398 */ 399 if (s->zst_outbuffer.pos != 0) { 400 error = cb(s->zst_buffer, s->zst_outbuffer.pos, s->zst_off, 401 arg); 402 if (error != 0) 403 return (error); 404 } 405 406 return (0); 407} 408 409static int 410zstdio_write(void *stream, void *data, size_t len, compressor_cb_t cb, 411 void *arg) 412{ 413 struct zstdio_stream *s; 414 size_t lastpos, rc; 415 int error; 416 417 s = stream; 418 if (data == NULL) 419 return (zstdio_flush(s, cb, arg)); 420 421 s->zst_inbuffer.src = data; 422 s->zst_inbuffer.size = len; 423 s->zst_inbuffer.pos = 0; 424 lastpos = 0; 425 426 while (s->zst_inbuffer.pos < s->zst_inbuffer.size) { 427 rc = ZSTD_compressStream(s->zst_stream, &s->zst_outbuffer, 428 &s->zst_inbuffer); 429 if (ZSTD_isError(rc)) { 430 printf("%s: Compress failed on %p! (%s)\n", 431 __func__, data, ZSTD_getErrorName(rc)); 432 return (EIO); 433 } 434 435 if (lastpos == s->zst_inbuffer.pos) { 436 /* 437 * XXX: May need flushStream to make forward progress 438 */ 439 printf("ZSTD: did not make forward progress @pos %zu\n", 440 lastpos); 441 return (EIO); 442 } 443 lastpos = s->zst_inbuffer.pos; 444 445 error = zst_flush_intermediate(s, cb, arg); 446 if (error != 0) 447 return (error); 448 } 449 return (0); 450} 451 452static void 453zstdio_fini(void *stream) 454{ 455 struct zstdio_stream *s; 456 457 s = stream; 458 if (s->zst_static_wkspc != NULL) 459 free(s->zst_static_wkspc, M_COMPRESS); 460 else 461 ZSTD_freeCCtx(s->zst_stream); 462 free(s->zst_buffer, M_COMPRESS); 463 free(s, M_COMPRESS); 464} 465 466static struct compressor_methods zstd_methods = { 467 .format = COMPRESS_ZSTD, 468 .init = zstdio_init, 469 .reset = zstdio_reset, 470 .write = zstdio_write, 471 .fini = zstdio_fini, 472}; 473DATA_SET(compressors, zstd_methods); 474 475#endif /* ZSTDIO */ 476 |
|
248bool 249compressor_avail(int format) 250{ 251 struct compressor_methods **iter; 252 253 SET_FOREACH(iter, compressors) { 254 if ((*iter)->format == format) 255 return (true); --- 60 unchanged lines hidden --- | 477bool 478compressor_avail(int format) 479{ 480 struct compressor_methods **iter; 481 482 SET_FOREACH(iter, compressors) { 483 if ((*iter)->format == format) 484 return (true); --- 60 unchanged lines hidden --- |