compress.c 6.6 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * This file is part of UBIFS.
 *
 * Copyright (C) 2006-2008 Nokia Corporation.
 * Copyright (C) 2006, 2007 University of Szeged, Hungary
 *
 * Authors: Adrian Hunter
 *          Artem Bityutskiy (Битюцкий Артём)
 *          Zoltan Sogor
 */

/*
 * This file provides a single place to access to compression and
 * decompression.
 */

#include <linux/crypto.h>
#include "ubifs.h"

/* Fake description object for the "none" compressor */
static struct ubifs_compressor none_compr = {
	.compr_type = UBIFS_COMPR_NONE,
24
	.name = "none",
25 26 27 28 29 30 31 32 33
	.capi_name = "",
};

#ifdef CONFIG_UBIFS_FS_LZO
static DEFINE_MUTEX(lzo_mutex);

static struct ubifs_compressor lzo_compr = {
	.compr_type = UBIFS_COMPR_LZO,
	.comp_mutex = &lzo_mutex,
34
	.name = "lzo",
35 36 37 38 39
	.capi_name = "lzo",
};
#else
static struct ubifs_compressor lzo_compr = {
	.compr_type = UBIFS_COMPR_LZO,
40
	.name = "lzo",
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
};
#endif

#ifdef CONFIG_UBIFS_FS_ZLIB
static DEFINE_MUTEX(deflate_mutex);
static DEFINE_MUTEX(inflate_mutex);

static struct ubifs_compressor zlib_compr = {
	.compr_type = UBIFS_COMPR_ZLIB,
	.comp_mutex = &deflate_mutex,
	.decomp_mutex = &inflate_mutex,
	.name = "zlib",
	.capi_name = "deflate",
};
#else
static struct ubifs_compressor zlib_compr = {
	.compr_type = UBIFS_COMPR_ZLIB,
	.name = "zlib",
};
#endif

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#ifdef CONFIG_UBIFS_FS_ZSTD
static DEFINE_MUTEX(zstd_enc_mutex);
static DEFINE_MUTEX(zstd_dec_mutex);

static struct ubifs_compressor zstd_compr = {
	.compr_type = UBIFS_COMPR_ZSTD,
	.comp_mutex = &zstd_enc_mutex,
	.decomp_mutex = &zstd_dec_mutex,
	.name = "zstd",
	.capi_name = "zstd",
};
#else
static struct ubifs_compressor zstd_compr = {
	.compr_type = UBIFS_COMPR_ZSTD,
	.name = "zstd",
};
#endif

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
/* All UBIFS compressors */
struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];

/**
 * ubifs_compress - compress data.
 * @in_buf: data to compress
 * @in_len: length of the data to compress
 * @out_buf: output buffer where compressed data should be stored
 * @out_len: output buffer length is returned here
 * @compr_type: type of compression to use on enter, actually used compression
 *              type on exit
 *
 * This function compresses input buffer @in_buf of length @in_len and stores
 * the result in the output buffer @out_buf and the resulting length in
 * @out_len. If the input buffer does not compress, it is just copied to the
 * @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE or if
 * compression error occurred.
 *
 * Note, if the input buffer was not compressed, it is copied to the output
 * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
 */
101 102
void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
		    int in_len, void *out_buf, int *out_len, int *compr_type)
103 104 105 106 107 108 109 110 111 112 113 114 115 116
{
	int err;
	struct ubifs_compressor *compr = ubifs_compressors[*compr_type];

	if (*compr_type == UBIFS_COMPR_NONE)
		goto no_compr;

	/* If the input data is small, do not even try to compress it */
	if (in_len < UBIFS_MIN_COMPR_LEN)
		goto no_compr;

	if (compr->comp_mutex)
		mutex_lock(compr->comp_mutex);
	err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf,
A
Artem Bityutskiy 已提交
117
				   (unsigned int *)out_len);
118 119 120
	if (compr->comp_mutex)
		mutex_unlock(compr->comp_mutex);
	if (unlikely(err)) {
121
		ubifs_warn(c, "cannot compress %d bytes, compressor %s, error %d, leave data uncompressed",
122
			   in_len, compr->name, err);
123
		goto no_compr;
124 125 126
	}

	/*
127 128
	 * If the data compressed only slightly, it is better to leave it
	 * uncompressed to improve read speed.
129
	 */
130
	if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
		goto no_compr;

	return;

no_compr:
	memcpy(out_buf, in_buf, in_len);
	*out_len = in_len;
	*compr_type = UBIFS_COMPR_NONE;
}

/**
 * ubifs_decompress - decompress data.
 * @in_buf: data to decompress
 * @in_len: length of the data to decompress
 * @out_buf: output buffer where decompressed data should
 * @out_len: output length is returned here
 * @compr_type: type of compression
 *
 * This function decompresses data from buffer @in_buf into buffer @out_buf.
 * The length of the uncompressed data is returned in @out_len. This functions
 * returns %0 on success or a negative error code on failure.
 */
153 154
int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
		     int in_len, void *out_buf, int *out_len, int compr_type)
155 156 157 158 159
{
	int err;
	struct ubifs_compressor *compr;

	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
160
		ubifs_err(c, "invalid compression type %d", compr_type);
161 162 163 164 165 166
		return -EINVAL;
	}

	compr = ubifs_compressors[compr_type];

	if (unlikely(!compr->capi_name)) {
167
		ubifs_err(c, "%s compression is not compiled in", compr->name);
168 169 170 171 172 173 174 175 176 177 178 179
		return -EINVAL;
	}

	if (compr_type == UBIFS_COMPR_NONE) {
		memcpy(out_buf, in_buf, in_len);
		*out_len = in_len;
		return 0;
	}

	if (compr->decomp_mutex)
		mutex_lock(compr->decomp_mutex);
	err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf,
A
Artem Bityutskiy 已提交
180
				     (unsigned int *)out_len);
181 182 183
	if (compr->decomp_mutex)
		mutex_unlock(compr->decomp_mutex);
	if (err)
184
		ubifs_err(c, "cannot decompress %d bytes, compressor %s, error %d",
185
			  in_len, compr->name, err);
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

	return err;
}

/**
 * compr_init - initialize a compressor.
 * @compr: compressor description object
 *
 * This function initializes the requested compressor and returns zero in case
 * of success or a negative error code in case of failure.
 */
static int __init compr_init(struct ubifs_compressor *compr)
{
	if (compr->capi_name) {
		compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
		if (IS_ERR(compr->cc)) {
202 203
			pr_err("UBIFS error (pid %d): cannot initialize compressor %s, error %ld",
			       current->pid, compr->name, PTR_ERR(compr->cc));
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
			return PTR_ERR(compr->cc);
		}
	}

	ubifs_compressors[compr->compr_type] = compr;
	return 0;
}

/**
 * compr_exit - de-initialize a compressor.
 * @compr: compressor description object
 */
static void compr_exit(struct ubifs_compressor *compr)
{
	if (compr->capi_name)
		crypto_free_comp(compr->cc);
	return;
}

/**
 * ubifs_compressors_init - initialize UBIFS compressors.
 *
 * This function initializes the compressor which were compiled in. Returns
 * zero in case of success and a negative error code in case of failure.
 */
int __init ubifs_compressors_init(void)
{
	int err;

	err = compr_init(&lzo_compr);
	if (err)
		return err;

237
	err = compr_init(&zstd_compr);
238 239 240
	if (err)
		goto out_lzo;

241 242 243 244
	err = compr_init(&zlib_compr);
	if (err)
		goto out_zstd;

245 246 247
	ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr;
	return 0;

248 249
out_zstd:
	compr_exit(&zstd_compr);
250 251 252 253 254 255 256 257
out_lzo:
	compr_exit(&lzo_compr);
	return err;
}

/**
 * ubifs_compressors_exit - de-initialize UBIFS compressors.
 */
A
Alexey Dobriyan 已提交
258
void ubifs_compressors_exit(void)
259 260 261
{
	compr_exit(&lzo_compr);
	compr_exit(&zlib_compr);
262
	compr_exit(&zstd_compr);
263
}