1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #include <linux/kernel.h> 4 #include <linux/slab.h> 5 #include <linux/vmalloc.h> 6 #include <linux/zlib.h> 7 8 #include "backend_deflate.h" 9 10 /* Use the same value as crypto API */ 11 #define DEFLATE_DEF_WINBITS 11 12 #define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL 13 14 struct deflate_ctx { 15 struct z_stream_s cctx; 16 struct z_stream_s dctx; 17 }; 18 19 static void deflate_release_params(struct zcomp_params *params) 20 { 21 } 22 23 static int deflate_setup_params(struct zcomp_params *params) 24 { 25 if (params->level == ZCOMP_PARAM_NO_LEVEL) 26 params->level = Z_DEFAULT_COMPRESSION; 27 28 return 0; 29 } 30 31 static void deflate_destroy(struct zcomp_ctx *ctx) 32 { 33 struct deflate_ctx *zctx = ctx->context; 34 35 if (!zctx) 36 return; 37 38 if (zctx->cctx.workspace) { 39 zlib_deflateEnd(&zctx->cctx); 40 vfree(zctx->cctx.workspace); 41 } 42 if (zctx->dctx.workspace) { 43 zlib_inflateEnd(&zctx->dctx); 44 vfree(zctx->dctx.workspace); 45 } 46 kfree(zctx); 47 } 48 49 static int deflate_create(struct zcomp_params *params, struct zcomp_ctx *ctx) 50 { 51 struct deflate_ctx *zctx; 52 size_t sz; 53 int ret; 54 55 zctx = kzalloc(sizeof(*zctx), GFP_KERNEL); 56 if (!zctx) 57 return -ENOMEM; 58 59 ctx->context = zctx; 60 sz = zlib_deflate_workspacesize(-DEFLATE_DEF_WINBITS, MAX_MEM_LEVEL); 61 zctx->cctx.workspace = vzalloc(sz); 62 if (!zctx->cctx.workspace) 63 goto error; 64 65 ret = zlib_deflateInit2(&zctx->cctx, params->level, Z_DEFLATED, 66 -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL, 67 Z_DEFAULT_STRATEGY); 68 if (ret != Z_OK) 69 goto error; 70 71 sz = zlib_inflate_workspacesize(); 72 zctx->dctx.workspace = vzalloc(sz); 73 if (!zctx->dctx.workspace) 74 goto error; 75 76 ret = zlib_inflateInit2(&zctx->dctx, -DEFLATE_DEF_WINBITS); 77 if (ret != Z_OK) 78 goto error; 79 80 return 0; 81 82 error: 83 deflate_destroy(ctx); 84 return -EINVAL; 85 } 86 87 static int deflate_compress(struct zcomp_params *params, struct zcomp_ctx *ctx, 88 struct zcomp_req *req) 89 { 90 struct deflate_ctx *zctx = ctx->context; 91 struct z_stream_s *deflate; 92 int ret; 93 94 deflate = &zctx->cctx; 95 ret = zlib_deflateReset(deflate); 96 if (ret != Z_OK) 97 return -EINVAL; 98 99 deflate->next_in = (u8 *)req->src; 100 deflate->avail_in = req->src_len; 101 deflate->next_out = (u8 *)req->dst; 102 deflate->avail_out = req->dst_len; 103 104 ret = zlib_deflate(deflate, Z_FINISH); 105 if (ret != Z_STREAM_END) 106 return -EINVAL; 107 108 req->dst_len = deflate->total_out; 109 return 0; 110 } 111 112 static int deflate_decompress(struct zcomp_params *params, 113 struct zcomp_ctx *ctx, 114 struct zcomp_req *req) 115 { 116 struct deflate_ctx *zctx = ctx->context; 117 struct z_stream_s *inflate; 118 int ret; 119 120 inflate = &zctx->dctx; 121 122 ret = zlib_inflateReset(inflate); 123 if (ret != Z_OK) 124 return -EINVAL; 125 126 inflate->next_in = (u8 *)req->src; 127 inflate->avail_in = req->src_len; 128 inflate->next_out = (u8 *)req->dst; 129 inflate->avail_out = req->dst_len; 130 131 ret = zlib_inflate(inflate, Z_SYNC_FLUSH); 132 if (ret != Z_STREAM_END) 133 return -EINVAL; 134 135 return 0; 136 } 137 138 const struct zcomp_ops backend_deflate = { 139 .compress = deflate_compress, 140 .decompress = deflate_decompress, 141 .create_ctx = deflate_create, 142 .destroy_ctx = deflate_destroy, 143 .setup_params = deflate_setup_params, 144 .release_params = deflate_release_params, 145 .name = "deflate", 146 }; 147