1 // SPDX-License-Identifier: GPL-2.0-or-later
3 #include <linux/kernel.h>
4 #include <linux/slab.h>
5 #include <linux/vmalloc.h>
6 #include <linux/zstd.h>
8 #include "backend_zstd.h"
18 zstd_custom_mem custom_mem
;
25 * For C/D dictionaries we need to provide zstd with zstd_custom_mem,
26 * which zstd uses internally to allocate/free memory when needed.
28 * This means that allocator.customAlloc() can be called from zcomp_compress()
29 * under local-lock (per-CPU compression stream), in which case we must use
32 * Another complication here is that we can be configured as a swap device.
34 static void *zstd_custom_alloc(void *opaque
, size_t size
)
37 return kvzalloc(size
, GFP_ATOMIC
);
39 return kvzalloc(size
, __GFP_KSWAPD_RECLAIM
| __GFP_NOWARN
);
42 static void zstd_custom_free(void *opaque
, void *address
)
47 static void zstd_release_params(struct zcomp_params
*params
)
49 struct zstd_params
*zp
= params
->drv_data
;
51 params
->drv_data
= NULL
;
55 zstd_free_cdict(zp
->cdict
);
56 zstd_free_ddict(zp
->ddict
);
60 static int zstd_setup_params(struct zcomp_params
*params
)
62 zstd_compression_parameters prm
;
63 struct zstd_params
*zp
;
65 zp
= kzalloc(sizeof(*zp
), GFP_KERNEL
);
69 params
->drv_data
= zp
;
70 if (params
->level
== ZCOMP_PARAM_NO_LEVEL
)
71 params
->level
= zstd_default_clevel();
73 zp
->cprm
= zstd_get_params(params
->level
, PAGE_SIZE
);
75 zp
->custom_mem
.customAlloc
= zstd_custom_alloc
;
76 zp
->custom_mem
.customFree
= zstd_custom_free
;
78 prm
= zstd_get_cparams(params
->level
, PAGE_SIZE
,
81 zp
->cdict
= zstd_create_cdict_byreference(params
->dict
,
88 zp
->ddict
= zstd_create_ddict_byreference(params
->dict
,
97 zstd_release_params(params
);
101 static void zstd_destroy(struct zcomp_ctx
*ctx
)
103 struct zstd_ctx
*zctx
= ctx
->context
;
109 * If ->cctx_mem and ->dctx_mem were allocated then we didn't use
110 * C/D dictionary and ->cctx / ->dctx were "embedded" into these
113 * If otherwise then we need to explicitly release ->cctx / ->dctx.
116 vfree(zctx
->cctx_mem
);
118 zstd_free_cctx(zctx
->cctx
);
121 vfree(zctx
->dctx_mem
);
123 zstd_free_dctx(zctx
->dctx
);
128 static int zstd_create(struct zcomp_params
*params
, struct zcomp_ctx
*ctx
)
130 struct zstd_ctx
*zctx
;
134 zctx
= kzalloc(sizeof(*zctx
), GFP_KERNEL
);
139 if (params
->dict_sz
== 0) {
140 prm
= zstd_get_params(params
->level
, PAGE_SIZE
);
141 sz
= zstd_cctx_workspace_bound(&prm
.cParams
);
142 zctx
->cctx_mem
= vzalloc(sz
);
146 zctx
->cctx
= zstd_init_cctx(zctx
->cctx_mem
, sz
);
150 sz
= zstd_dctx_workspace_bound();
151 zctx
->dctx_mem
= vzalloc(sz
);
155 zctx
->dctx
= zstd_init_dctx(zctx
->dctx_mem
, sz
);
159 struct zstd_params
*zp
= params
->drv_data
;
161 zctx
->cctx
= zstd_create_cctx_advanced(zp
->custom_mem
);
165 zctx
->dctx
= zstd_create_dctx_advanced(zp
->custom_mem
);
173 zstd_release_params(params
);
178 static int zstd_compress(struct zcomp_params
*params
, struct zcomp_ctx
*ctx
,
179 struct zcomp_req
*req
)
181 struct zstd_params
*zp
= params
->drv_data
;
182 struct zstd_ctx
*zctx
= ctx
->context
;
185 if (params
->dict_sz
== 0)
186 ret
= zstd_compress_cctx(zctx
->cctx
, req
->dst
, req
->dst_len
,
187 req
->src
, req
->src_len
, &zp
->cprm
);
189 ret
= zstd_compress_using_cdict(zctx
->cctx
, req
->dst
,
190 req
->dst_len
, req
->src
,
193 if (zstd_is_error(ret
))
199 static int zstd_decompress(struct zcomp_params
*params
, struct zcomp_ctx
*ctx
,
200 struct zcomp_req
*req
)
202 struct zstd_params
*zp
= params
->drv_data
;
203 struct zstd_ctx
*zctx
= ctx
->context
;
206 if (params
->dict_sz
== 0)
207 ret
= zstd_decompress_dctx(zctx
->dctx
, req
->dst
, req
->dst_len
,
208 req
->src
, req
->src_len
);
210 ret
= zstd_decompress_using_ddict(zctx
->dctx
, req
->dst
,
211 req
->dst_len
, req
->src
,
212 req
->src_len
, zp
->ddict
);
213 if (zstd_is_error(ret
))
218 const struct zcomp_ops backend_zstd
= {
219 .compress
= zstd_compress
,
220 .decompress
= zstd_decompress
,
221 .create_ctx
= zstd_create
,
222 .destroy_ctx
= zstd_destroy
,
223 .setup_params
= zstd_setup_params
,
224 .release_params
= zstd_release_params
,