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