Path: blob/main/sys/contrib/openzfs/module/os/linux/spl/spl-zlib.c
48775 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.3* Copyright (C) 2007 The Regents of the University of California.4* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).5* Written by Brian Behlendorf <[email protected]>.6* UCRL-CODE-2351977*8* This file is part of the SPL, Solaris Porting Layer.9*10* The SPL is free software; you can redistribute it and/or modify it11* under the terms of the GNU General Public License as published by the12* Free Software Foundation; either version 2 of the License, or (at your13* option) any later version.14*15* The SPL is distributed in the hope that it will be useful, but WITHOUT16* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or17* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License18* for more details.19*20* You should have received a copy of the GNU General Public License along21* with the SPL. If not, see <http://www.gnu.org/licenses/>.22*23*24* z_compress_level/z_uncompress are nearly identical copies of the25* compress2/uncompress functions provided by the official zlib package26* available at http://zlib.net/. The only changes made we to slightly27* adapt the functions called to match the linux kernel implementation28* of zlib. The full zlib license follows:29*30* zlib.h -- interface of the 'zlib' general purpose compression library31* version 1.2.5, April 19th, 201032*33* Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler34*35* This software is provided 'as-is', without any express or implied36* warranty. In no event will the authors be held liable for any damages37* arising from the use of this software.38*39* Permission is granted to anyone to use this software for any purpose,40* including commercial applications, and to alter it and redistribute it41* freely, subject to the following restrictions:42*43* 1. The origin of this software must not be misrepresented; you must not44* claim that you wrote the original software. If you use this software45* in a product, an acknowledgment in the product documentation would be46* appreciated but is not required.47* 2. Altered source versions must be plainly marked as such, and must not be48* misrepresented as being the original software.49* 3. This notice may not be removed or altered from any source distribution.50*51* Jean-loup Gailly52* Mark Adler53*/545556#include <sys/kmem.h>57#include <sys/kmem_cache.h>58#include <sys/zmod.h>5960static spl_kmem_cache_t *zlib_workspace_cache;6162/*63* A kmem_cache is used for the zlib workspaces to avoid having to vmalloc64* and vfree for every call. Using a kmem_cache also has the advantage65* that improves the odds that the memory used will be local to this cpu.66* To further improve things it might be wise to create a dedicated per-cpu67* workspace for use. This would take some additional care because we then68* must disable preemption around the critical section, and verify that69* zlib_deflate* and zlib_inflate* never internally call schedule().70*/71static void *72zlib_workspace_alloc(int flags)73{74return (kmem_cache_alloc(zlib_workspace_cache, flags & ~(__GFP_FS)));75}7677static void78zlib_workspace_free(void *workspace)79{80kmem_cache_free(zlib_workspace_cache, workspace);81}8283/*84* Compresses the source buffer into the destination buffer. The level85* parameter has the same meaning as in deflateInit. sourceLen is the byte86* length of the source buffer. Upon entry, destLen is the total size of the87* destination buffer, which must be at least 0.1% larger than sourceLen plus88* 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.89*90* compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough91* memory, Z_BUF_ERROR if there was not enough room in the output buffer,92* Z_STREAM_ERROR if the level parameter is invalid.93*/94int95z_compress_level(void *dest, size_t *destLen, const void *source,96size_t sourceLen, int level)97{98z_stream stream;99int err;100101stream.next_in = (Byte *)source;102stream.avail_in = (uInt)sourceLen;103stream.next_out = dest;104stream.avail_out = (uInt)*destLen;105106if ((size_t)stream.avail_out != *destLen)107return (Z_BUF_ERROR);108109stream.workspace = zlib_workspace_alloc(KM_SLEEP);110if (!stream.workspace)111return (Z_MEM_ERROR);112113err = zlib_deflateInit(&stream, level);114if (err != Z_OK) {115zlib_workspace_free(stream.workspace);116return (err);117}118119err = zlib_deflate(&stream, Z_FINISH);120if (err != Z_STREAM_END) {121zlib_deflateEnd(&stream);122zlib_workspace_free(stream.workspace);123return (err == Z_OK ? Z_BUF_ERROR : err);124}125*destLen = stream.total_out;126127err = zlib_deflateEnd(&stream);128zlib_workspace_free(stream.workspace);129130return (err);131}132EXPORT_SYMBOL(z_compress_level);133134/*135* Decompresses the source buffer into the destination buffer. sourceLen is136* the byte length of the source buffer. Upon entry, destLen is the total137* size of the destination buffer, which must be large enough to hold the138* entire uncompressed data. (The size of the uncompressed data must have139* been saved previously by the compressor and transmitted to the decompressor140* by some mechanism outside the scope of this compression library.)141* Upon exit, destLen is the actual size of the compressed buffer.142* This function can be used to decompress a whole file at once if the143* input file is mmap'ed.144*145* uncompress returns Z_OK if success, Z_MEM_ERROR if there was not146* enough memory, Z_BUF_ERROR if there was not enough room in the output147* buffer, or Z_DATA_ERROR if the input data was corrupted.148*/149int150z_uncompress(void *dest, size_t *destLen, const void *source, size_t sourceLen)151{152z_stream stream;153int err;154155stream.next_in = (Byte *)source;156stream.avail_in = (uInt)sourceLen;157stream.next_out = dest;158stream.avail_out = (uInt)*destLen;159160if ((size_t)stream.avail_out != *destLen)161return (Z_BUF_ERROR);162163stream.workspace = zlib_workspace_alloc(KM_SLEEP);164if (!stream.workspace)165return (Z_MEM_ERROR);166167err = zlib_inflateInit(&stream);168if (err != Z_OK) {169zlib_workspace_free(stream.workspace);170return (err);171}172173err = zlib_inflate(&stream, Z_FINISH);174if (err != Z_STREAM_END) {175zlib_inflateEnd(&stream);176zlib_workspace_free(stream.workspace);177178if (err == Z_NEED_DICT ||179(err == Z_BUF_ERROR && stream.avail_in == 0))180return (Z_DATA_ERROR);181182return (err);183}184*destLen = stream.total_out;185186err = zlib_inflateEnd(&stream);187zlib_workspace_free(stream.workspace);188189return (err);190}191EXPORT_SYMBOL(z_uncompress);192193int194spl_zlib_init(void)195{196int size;197198size = MAX(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),199zlib_inflate_workspacesize());200201zlib_workspace_cache = kmem_cache_create(202"spl_zlib_workspace_cache",203size, 0, NULL, NULL, NULL, NULL, NULL,204KMC_KVMEM | KMC_RECLAIMABLE);205if (!zlib_workspace_cache)206return (-ENOMEM);207208return (0);209}210211void212spl_zlib_fini(void)213{214kmem_cache_destroy(zlib_workspace_cache);215zlib_workspace_cache = NULL;216}217218219