• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2 /*
3  * Copyright (C) 2018-2019 HUAWEI, Inc.
4  *             http://www.huawei.com/
5  * Created by Gao Xiang <gaoxiang25@huawei.com>
6  */
7 #include "erofs/internal.h"
8 #include "compressor.h"
9 #include "erofs/print.h"
10 
11 #define EROFS_CONFIG_COMPR_DEF_BOUNDARY		(128)
12 
13 static const struct erofs_algorithm {
14 	char *name;
15 	const struct erofs_compressor *c;
16 	unsigned int id;
17 
18 	/* its name won't be shown as a supported algorithm */
19 	bool optimisor;
20 } erofs_algs[] = {
21 	{ "lz4",
22 #if LZ4_ENABLED
23 		&erofs_compressor_lz4,
24 #else
25 		NULL,
26 #endif
27 	  Z_EROFS_COMPRESSION_LZ4, false },
28 
29 #if LZ4HC_ENABLED
30 	{ "lz4hc", &erofs_compressor_lz4hc,
31 	  Z_EROFS_COMPRESSION_LZ4, true },
32 #endif
33 
34 	{ "lzma",
35 #if HAVE_LIBLZMA
36 		&erofs_compressor_lzma,
37 #else
38 		NULL,
39 #endif
40 	  Z_EROFS_COMPRESSION_LZMA, false },
41 
42 	{ "deflate", &erofs_compressor_deflate,
43 	  Z_EROFS_COMPRESSION_DEFLATE, false },
44 
45 #if HAVE_LIBDEFLATE
46 	{ "libdeflate", &erofs_compressor_libdeflate,
47 	  Z_EROFS_COMPRESSION_DEFLATE, true },
48 #endif
49 };
50 
z_erofs_get_compress_algorithm_id(const struct erofs_compress * c)51 int z_erofs_get_compress_algorithm_id(const struct erofs_compress *c)
52 {
53 	DBG_BUGON(!c->alg);
54 	return c->alg->id;
55 }
56 
z_erofs_list_supported_algorithms(int i,unsigned int * mask)57 const char *z_erofs_list_supported_algorithms(int i, unsigned int *mask)
58 {
59 	if (i >= ARRAY_SIZE(erofs_algs))
60 		return NULL;
61 	if (!erofs_algs[i].optimisor && (*mask & (1 << erofs_algs[i].id))) {
62 		*mask ^= 1 << erofs_algs[i].id;
63 		return erofs_algs[i].name;
64 	}
65 	return "";
66 }
67 
z_erofs_list_available_compressors(int * i)68 const char *z_erofs_list_available_compressors(int *i)
69 {
70 	for (;*i < ARRAY_SIZE(erofs_algs); ++*i) {
71 		if (!erofs_algs[*i].c)
72 			continue;
73 		return erofs_algs[(*i)++].name;
74 	}
75 	return NULL;
76 }
77 
erofs_compress_destsize(const struct erofs_compress * c,const void * src,unsigned int * srcsize,void * dst,unsigned int dstsize,bool inblocks)78 int erofs_compress_destsize(const struct erofs_compress *c,
79 			    const void *src, unsigned int *srcsize,
80 			    void *dst, unsigned int dstsize, bool inblocks)
81 {
82 	unsigned int uncompressed_capacity, compressed_size;
83 	int ret;
84 
85 	DBG_BUGON(!c->alg);
86 	if (!c->alg->c->compress_destsize)
87 		return -ENOTSUP;
88 
89 	uncompressed_capacity = *srcsize;
90 	ret = c->alg->c->compress_destsize(c, src, srcsize, dst, dstsize);
91 	if (ret < 0)
92 		return ret;
93 
94 	/* XXX: ret >= destsize_alignsize is a temporary hack for ztailpacking */
95 	if (inblocks || ret >= c->destsize_alignsize ||
96 	    uncompressed_capacity != *srcsize)
97 		compressed_size = roundup(ret, c->destsize_alignsize);
98 	else
99 		compressed_size = ret;
100 	DBG_BUGON(c->compress_threshold < 100);
101 	/* check if there is enough gains to compress */
102 	if (*srcsize <= compressed_size * c->compress_threshold / 100)
103 		return -EAGAIN;
104 	return ret;
105 }
106 
erofs_compressor_setlevel(struct erofs_compress * c,int compression_level)107 int erofs_compressor_setlevel(struct erofs_compress *c, int compression_level)
108 {
109 	DBG_BUGON(!c->alg);
110 	if (c->alg->c->setlevel)
111 		return c->alg->c->setlevel(c, compression_level);
112 
113 	if (compression_level >= 0)
114 		return -EINVAL;
115 	c->compression_level = 0;
116 	return 0;
117 }
118 
erofs_compressor_init(struct erofs_sb_info * sbi,struct erofs_compress * c,char * alg_name)119 int erofs_compressor_init(struct erofs_sb_info *sbi,
120 			  struct erofs_compress *c, char *alg_name)
121 {
122 	int ret, i;
123 
124 	c->sbi = sbi;
125 
126 	/* should be written in "minimum compression ratio * 100" */
127 	c->compress_threshold = 100;
128 
129 	/* optimize for 4k size page */
130 	c->destsize_alignsize = erofs_blksiz(sbi);
131 	c->destsize_redzone_begin = erofs_blksiz(sbi) - 16;
132 	c->destsize_redzone_end = EROFS_CONFIG_COMPR_DEF_BOUNDARY;
133 
134 	if (!alg_name) {
135 		c->alg = NULL;
136 		return 0;
137 	}
138 
139 	ret = -EINVAL;
140 	for (i = 0; i < ARRAY_SIZE(erofs_algs); ++i) {
141 		if (alg_name && strcmp(alg_name, erofs_algs[i].name))
142 			continue;
143 
144 		if (!erofs_algs[i].c)
145 			continue;
146 
147 		ret = erofs_algs[i].c->init(c);
148 		if (!ret) {
149 			c->alg = &erofs_algs[i];
150 			return 0;
151 		}
152 	}
153 	erofs_err("Cannot find a valid compressor %s", alg_name);
154 	return ret;
155 }
156 
erofs_compressor_exit(struct erofs_compress * c)157 int erofs_compressor_exit(struct erofs_compress *c)
158 {
159 	if (c->alg && c->alg->c->exit)
160 		return c->alg->c->exit(c);
161 	return 0;
162 }
163