Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
# SPDX-License-Identifier: GPL-2.0
config ZRAM
tristate "Compressed RAM block device support"
depends on BLOCK && SYSFS && MMU
select ZSMALLOC
help
Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
Pages written to these disks are compressed and stored in memory
itself. These disks allow very fast I/O and compression provides
good amounts of memory savings.
It has several use cases, for example: /tmp storage, use as swap
disks and maybe many more.
See Documentation/admin-guide/blockdev/zram.rst for more information.
config ZRAM_BACKEND_LZ4
bool "lz4 compression support"
depends on ZRAM
select LZ4_COMPRESS
select LZ4_DECOMPRESS
config ZRAM_BACKEND_LZ4HC
bool "lz4hc compression support"
depends on ZRAM
select LZ4HC_COMPRESS
select LZ4_DECOMPRESS
config ZRAM_BACKEND_ZSTD
bool "zstd compression support"
depends on ZRAM
select ZSTD_COMPRESS
select ZSTD_DECOMPRESS
config ZRAM_BACKEND_DEFLATE
bool "deflate compression support"
depends on ZRAM
select ZLIB_DEFLATE
select ZLIB_INFLATE
config ZRAM_BACKEND_842
bool "842 compression support"
depends on ZRAM
select 842_COMPRESS
select 842_DECOMPRESS
config ZRAM_BACKEND_FORCE_LZO
depends on ZRAM
def_bool !ZRAM_BACKEND_LZ4 && !ZRAM_BACKEND_LZ4HC && \
!ZRAM_BACKEND_ZSTD && !ZRAM_BACKEND_DEFLATE && \
!ZRAM_BACKEND_842
config ZRAM_BACKEND_LZO
bool "lzo and lzo-rle compression support" if !ZRAM_BACKEND_FORCE_LZO
depends on ZRAM
default ZRAM_BACKEND_FORCE_LZO
select LZO_COMPRESS
select LZO_DECOMPRESS
choice
prompt "Default zram compressor"
default ZRAM_DEF_COMP_LZORLE
depends on ZRAM
config ZRAM_DEF_COMP_LZORLE
bool "lzo-rle"
depends on ZRAM_BACKEND_LZO
config ZRAM_DEF_COMP_LZO
bool "lzo"
depends on ZRAM_BACKEND_LZO
config ZRAM_DEF_COMP_LZ4
bool "lz4"
depends on ZRAM_BACKEND_LZ4
config ZRAM_DEF_COMP_LZ4HC
bool "lz4hc"
depends on ZRAM_BACKEND_LZ4HC
config ZRAM_DEF_COMP_ZSTD
bool "zstd"
depends on ZRAM_BACKEND_ZSTD
config ZRAM_DEF_COMP_DEFLATE
bool "deflate"
depends on ZRAM_BACKEND_DEFLATE
config ZRAM_DEF_COMP_842
bool "842"
depends on ZRAM_BACKEND_842
endchoice
config ZRAM_DEF_COMP
string
depends on ZRAM
default "lzo-rle" if ZRAM_DEF_COMP_LZORLE
default "lzo" if ZRAM_DEF_COMP_LZO
default "lz4" if ZRAM_DEF_COMP_LZ4
default "lz4hc" if ZRAM_DEF_COMP_LZ4HC
default "zstd" if ZRAM_DEF_COMP_ZSTD
default "deflate" if ZRAM_DEF_COMP_DEFLATE
default "842" if ZRAM_DEF_COMP_842
default "unset-value"
config ZRAM_WRITEBACK
bool "Write back incompressible or idle page to backing device"
depends on ZRAM
help
This lets zram entries (incompressible or idle pages) be written
back to a backing device, helping save memory.
For this feature, admin should set up backing device via
/sys/block/zramX/backing_dev.
With /sys/block/zramX/{idle,writeback}, application could ask
idle page's writeback to the backing device to save in memory.
See Documentation/admin-guide/blockdev/zram.rst for more information.
config ZRAM_TRACK_ENTRY_ACTIME
bool "Track access time of zram entries"
depends on ZRAM
help
With this feature zram tracks access time of every stored
entry (page), which can be used for a more fine grained IDLE
pages writeback.
config ZRAM_MEMORY_TRACKING
bool "Track zRam block status"
depends on ZRAM && DEBUG_FS
select ZRAM_TRACK_ENTRY_ACTIME
help
With this feature, admin can track the state of allocated blocks
of zRAM. Admin could see the information via
/sys/kernel/debug/zram/zramX/block_state.
See Documentation/admin-guide/blockdev/zram.rst for more information.
config ZRAM_MULTI_COMP
bool "Enable multiple compression streams"
depends on ZRAM
help
This will enable multi-compression streams, so that ZRAM can
re-compress pages using a potentially slower but more effective
compression algorithm. Note, that IDLE page recompression
requires ZRAM_TRACK_ENTRY_ACTIME.
+12
View File
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
zram-y := zcomp.o zram_drv.o
zram-$(CONFIG_ZRAM_BACKEND_LZO) += backend_lzorle.o backend_lzo.o
zram-$(CONFIG_ZRAM_BACKEND_LZ4) += backend_lz4.o
zram-$(CONFIG_ZRAM_BACKEND_LZ4HC) += backend_lz4hc.o
zram-$(CONFIG_ZRAM_BACKEND_ZSTD) += backend_zstd.o
zram-$(CONFIG_ZRAM_BACKEND_DEFLATE) += backend_deflate.o
zram-$(CONFIG_ZRAM_BACKEND_842) += backend_842.o
obj-$(CONFIG_ZRAM) += zram.o
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sw842.h>
#include <linux/vmalloc.h>
#include "backend_842.h"
static void release_params_842(struct zcomp_params *params)
{
}
static int setup_params_842(struct zcomp_params *params)
{
return 0;
}
static void destroy_842(struct zcomp_ctx *ctx)
{
kfree(ctx->context);
}
static int create_842(struct zcomp_params *params, struct zcomp_ctx *ctx)
{
ctx->context = kmalloc(SW842_MEM_COMPRESS, GFP_KERNEL);
if (!ctx->context)
return -ENOMEM;
return 0;
}
static int compress_842(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
unsigned int dlen = req->dst_len;
int ret;
ret = sw842_compress(req->src, req->src_len, req->dst, &dlen,
ctx->context);
if (ret == 0)
req->dst_len = dlen;
return ret;
}
static int decompress_842(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
unsigned int dlen = req->dst_len;
return sw842_decompress(req->src, req->src_len, req->dst, &dlen);
}
const struct zcomp_ops backend_842 = {
.compress = compress_842,
.decompress = decompress_842,
.create_ctx = create_842,
.destroy_ctx = destroy_842,
.setup_params = setup_params_842,
.release_params = release_params_842,
.name = "842",
};
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef __BACKEND_842_H__
#define __BACKEND_842_H__
#include "zcomp.h"
extern const struct zcomp_ops backend_842;
#endif /* __BACKEND_842_H__ */
@@ -0,0 +1,148 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/zlib.h>
#include "backend_deflate.h"
/* Use the same value as crypto API */
#define DEFLATE_DEF_WINBITS (-11)
#define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL
struct deflate_ctx {
struct z_stream_s cctx;
struct z_stream_s dctx;
};
static void deflate_release_params(struct zcomp_params *params)
{
}
static int deflate_setup_params(struct zcomp_params *params)
{
if (params->level == ZCOMP_PARAM_NOT_SET)
params->level = Z_DEFAULT_COMPRESSION;
if (params->deflate.winbits == ZCOMP_PARAM_NOT_SET)
params->deflate.winbits = DEFLATE_DEF_WINBITS;
return 0;
}
static void deflate_destroy(struct zcomp_ctx *ctx)
{
struct deflate_ctx *zctx = ctx->context;
if (!zctx)
return;
if (zctx->cctx.workspace) {
zlib_deflateEnd(&zctx->cctx);
vfree(zctx->cctx.workspace);
}
if (zctx->dctx.workspace) {
zlib_inflateEnd(&zctx->dctx);
vfree(zctx->dctx.workspace);
}
kfree(zctx);
}
static int deflate_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
{
struct deflate_ctx *zctx;
size_t sz;
int ret;
zctx = kzalloc_obj(*zctx);
if (!zctx)
return -ENOMEM;
ctx->context = zctx;
sz = zlib_deflate_workspacesize(params->deflate.winbits, MAX_MEM_LEVEL);
zctx->cctx.workspace = vzalloc(sz);
if (!zctx->cctx.workspace)
goto error;
ret = zlib_deflateInit2(&zctx->cctx, params->level, Z_DEFLATED,
params->deflate.winbits, DEFLATE_DEF_MEMLEVEL,
Z_DEFAULT_STRATEGY);
if (ret != Z_OK)
goto error;
sz = zlib_inflate_workspacesize();
zctx->dctx.workspace = vzalloc(sz);
if (!zctx->dctx.workspace)
goto error;
ret = zlib_inflateInit2(&zctx->dctx, params->deflate.winbits);
if (ret != Z_OK)
goto error;
return 0;
error:
deflate_destroy(ctx);
return -EINVAL;
}
static int deflate_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
struct deflate_ctx *zctx = ctx->context;
struct z_stream_s *deflate;
int ret;
deflate = &zctx->cctx;
ret = zlib_deflateReset(deflate);
if (ret != Z_OK)
return -EINVAL;
deflate->next_in = (u8 *)req->src;
deflate->avail_in = req->src_len;
deflate->next_out = (u8 *)req->dst;
deflate->avail_out = req->dst_len;
ret = zlib_deflate(deflate, Z_FINISH);
if (ret != Z_STREAM_END)
return -EINVAL;
req->dst_len = deflate->total_out;
return 0;
}
static int deflate_decompress(struct zcomp_params *params,
struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
struct deflate_ctx *zctx = ctx->context;
struct z_stream_s *inflate;
int ret;
inflate = &zctx->dctx;
ret = zlib_inflateReset(inflate);
if (ret != Z_OK)
return -EINVAL;
inflate->next_in = (u8 *)req->src;
inflate->avail_in = req->src_len;
inflate->next_out = (u8 *)req->dst;
inflate->avail_out = req->dst_len;
ret = zlib_inflate(inflate, Z_SYNC_FLUSH);
if (ret != Z_STREAM_END)
return -EINVAL;
return 0;
}
const struct zcomp_ops backend_deflate = {
.compress = deflate_compress,
.decompress = deflate_decompress,
.create_ctx = deflate_create,
.destroy_ctx = deflate_destroy,
.setup_params = deflate_setup_params,
.release_params = deflate_release_params,
.name = "deflate",
};
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef __BACKEND_DEFLATE_H__
#define __BACKEND_DEFLATE_H__
#include "zcomp.h"
extern const struct zcomp_ops backend_deflate;
#endif /* __BACKEND_DEFLATE_H__ */
@@ -0,0 +1,150 @@
#include <linux/kernel.h>
#include <linux/lz4.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "backend_lz4.h"
struct lz4_ctx {
void *mem;
LZ4_streamDecode_t *dstrm;
LZ4_stream_t *cstrm;
};
static void lz4_release_params(struct zcomp_params *params)
{
LZ4_stream_t *dict_stream = params->drv_data;
params->drv_data = NULL;
if (!dict_stream)
return;
kfree(dict_stream);
}
static int lz4_setup_params(struct zcomp_params *params)
{
LZ4_stream_t *dict_stream;
int ret;
if (params->level == ZCOMP_PARAM_NOT_SET)
params->level = LZ4_ACCELERATION_DEFAULT;
if (!params->dict || !params->dict_sz)
return 0;
dict_stream = kzalloc_obj(*dict_stream, GFP_KERNEL);
if (!dict_stream)
return -ENOMEM;
ret = LZ4_loadDict(dict_stream,
params->dict, params->dict_sz);
if (ret != params->dict_sz) {
kfree(dict_stream);
return -EINVAL;
}
params->drv_data = dict_stream;
return 0;
}
static void lz4_destroy(struct zcomp_ctx *ctx)
{
struct lz4_ctx *zctx = ctx->context;
if (!zctx)
return;
vfree(zctx->mem);
kfree(zctx->dstrm);
kfree(zctx->cstrm);
kfree(zctx);
}
static int lz4_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
{
struct lz4_ctx *zctx;
zctx = kzalloc_obj(*zctx);
if (!zctx)
return -ENOMEM;
ctx->context = zctx;
if (params->dict_sz == 0) {
zctx->mem = vmalloc(LZ4_MEM_COMPRESS);
if (!zctx->mem)
goto error;
} else {
zctx->dstrm = kzalloc_obj(*zctx->dstrm);
if (!zctx->dstrm)
goto error;
zctx->cstrm = kzalloc_obj(*zctx->cstrm);
if (!zctx->cstrm)
goto error;
}
return 0;
error:
lz4_destroy(ctx);
return -ENOMEM;
}
static int lz4_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
struct lz4_ctx *zctx = ctx->context;
int ret;
if (!zctx->cstrm) {
ret = LZ4_compress_fast(req->src, req->dst, req->src_len,
req->dst_len, params->level,
zctx->mem);
} else {
/* Cstrm needs to be reset */
memcpy(zctx->cstrm, params->drv_data, sizeof(*zctx->cstrm));
ret = LZ4_compress_fast_continue(zctx->cstrm, req->src,
req->dst, req->src_len,
req->dst_len, params->level);
}
if (!ret)
return -EINVAL;
req->dst_len = ret;
return 0;
}
static int lz4_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
struct lz4_ctx *zctx = ctx->context;
int ret;
if (!zctx->dstrm) {
ret = LZ4_decompress_safe(req->src, req->dst, req->src_len,
req->dst_len);
} else {
/* Dstrm needs to be reset */
ret = LZ4_setStreamDecode(zctx->dstrm, params->dict,
params->dict_sz);
if (!ret)
return -EINVAL;
ret = LZ4_decompress_safe_continue(zctx->dstrm, req->src,
req->dst, req->src_len,
req->dst_len);
}
if (ret < 0)
return -EINVAL;
return 0;
}
const struct zcomp_ops backend_lz4 = {
.compress = lz4_compress,
.decompress = lz4_decompress,
.create_ctx = lz4_create,
.destroy_ctx = lz4_destroy,
.setup_params = lz4_setup_params,
.release_params = lz4_release_params,
.name = "lz4",
};
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef __BACKEND_LZ4_H__
#define __BACKEND_LZ4_H__
#include "zcomp.h"
extern const struct zcomp_ops backend_lz4;
#endif /* __BACKEND_LZ4_H__ */
@@ -0,0 +1,128 @@
#include <linux/kernel.h>
#include <linux/lz4.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "backend_lz4hc.h"
struct lz4hc_ctx {
void *mem;
LZ4_streamDecode_t *dstrm;
LZ4_streamHC_t *cstrm;
};
static void lz4hc_release_params(struct zcomp_params *params)
{
}
static int lz4hc_setup_params(struct zcomp_params *params)
{
if (params->level == ZCOMP_PARAM_NOT_SET)
params->level = LZ4HC_DEFAULT_CLEVEL;
return 0;
}
static void lz4hc_destroy(struct zcomp_ctx *ctx)
{
struct lz4hc_ctx *zctx = ctx->context;
if (!zctx)
return;
kfree(zctx->dstrm);
kfree(zctx->cstrm);
vfree(zctx->mem);
kfree(zctx);
}
static int lz4hc_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
{
struct lz4hc_ctx *zctx;
zctx = kzalloc_obj(*zctx);
if (!zctx)
return -ENOMEM;
ctx->context = zctx;
if (params->dict_sz == 0) {
zctx->mem = vmalloc(LZ4HC_MEM_COMPRESS);
if (!zctx->mem)
goto error;
} else {
zctx->dstrm = kzalloc_obj(*zctx->dstrm);
if (!zctx->dstrm)
goto error;
zctx->cstrm = kzalloc_obj(*zctx->cstrm);
if (!zctx->cstrm)
goto error;
}
return 0;
error:
lz4hc_destroy(ctx);
return -EINVAL;
}
static int lz4hc_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
struct lz4hc_ctx *zctx = ctx->context;
int ret;
if (!zctx->cstrm) {
ret = LZ4_compress_HC(req->src, req->dst, req->src_len,
req->dst_len, params->level,
zctx->mem);
} else {
/* Cstrm needs to be reset */
LZ4_resetStreamHC(zctx->cstrm, params->level);
ret = LZ4_loadDictHC(zctx->cstrm, params->dict,
params->dict_sz);
if (ret != params->dict_sz)
return -EINVAL;
ret = LZ4_compress_HC_continue(zctx->cstrm, req->src, req->dst,
req->src_len, req->dst_len);
}
if (!ret)
return -EINVAL;
req->dst_len = ret;
return 0;
}
static int lz4hc_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
struct lz4hc_ctx *zctx = ctx->context;
int ret;
if (!zctx->dstrm) {
ret = LZ4_decompress_safe(req->src, req->dst, req->src_len,
req->dst_len);
} else {
/* Dstrm needs to be reset */
ret = LZ4_setStreamDecode(zctx->dstrm, params->dict,
params->dict_sz);
if (!ret)
return -EINVAL;
ret = LZ4_decompress_safe_continue(zctx->dstrm, req->src,
req->dst, req->src_len,
req->dst_len);
}
if (ret < 0)
return -EINVAL;
return 0;
}
const struct zcomp_ops backend_lz4hc = {
.compress = lz4hc_compress,
.decompress = lz4hc_decompress,
.create_ctx = lz4hc_create,
.destroy_ctx = lz4hc_destroy,
.setup_params = lz4hc_setup_params,
.release_params = lz4hc_release_params,
.name = "lz4hc",
};
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef __BACKEND_LZ4HC_H__
#define __BACKEND_LZ4HC_H__
#include "zcomp.h"
extern const struct zcomp_ops backend_lz4hc;
#endif /* __BACKEND_LZ4HC_H__ */
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/lzo.h>
#include "backend_lzo.h"
static void lzo_release_params(struct zcomp_params *params)
{
}
static int lzo_setup_params(struct zcomp_params *params)
{
return 0;
}
static int lzo_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
{
ctx->context = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
if (!ctx->context)
return -ENOMEM;
return 0;
}
static void lzo_destroy(struct zcomp_ctx *ctx)
{
kfree(ctx->context);
}
static int lzo_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
int ret;
ret = lzo1x_1_compress(req->src, req->src_len, req->dst,
&req->dst_len, ctx->context);
return ret == LZO_E_OK ? 0 : ret;
}
static int lzo_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
int ret;
ret = lzo1x_decompress_safe(req->src, req->src_len,
req->dst, &req->dst_len);
return ret == LZO_E_OK ? 0 : ret;
}
const struct zcomp_ops backend_lzo = {
.compress = lzo_compress,
.decompress = lzo_decompress,
.create_ctx = lzo_create,
.destroy_ctx = lzo_destroy,
.setup_params = lzo_setup_params,
.release_params = lzo_release_params,
.name = "lzo",
};
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef __BACKEND_LZO_H__
#define __BACKEND_LZO_H__
#include "zcomp.h"
extern const struct zcomp_ops backend_lzo;
#endif /* __BACKEND_LZO_H__ */
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/lzo.h>
#include "backend_lzorle.h"
static void lzorle_release_params(struct zcomp_params *params)
{
}
static int lzorle_setup_params(struct zcomp_params *params)
{
return 0;
}
static int lzorle_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
{
ctx->context = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
if (!ctx->context)
return -ENOMEM;
return 0;
}
static void lzorle_destroy(struct zcomp_ctx *ctx)
{
kfree(ctx->context);
}
static int lzorle_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
int ret;
ret = lzorle1x_1_compress(req->src, req->src_len, req->dst,
&req->dst_len, ctx->context);
return ret == LZO_E_OK ? 0 : ret;
}
static int lzorle_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
int ret;
ret = lzo1x_decompress_safe(req->src, req->src_len,
req->dst, &req->dst_len);
return ret == LZO_E_OK ? 0 : ret;
}
const struct zcomp_ops backend_lzorle = {
.compress = lzorle_compress,
.decompress = lzorle_decompress,
.create_ctx = lzorle_create,
.destroy_ctx = lzorle_destroy,
.setup_params = lzorle_setup_params,
.release_params = lzorle_release_params,
.name = "lzo-rle",
};
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef __BACKEND_LZORLE_H__
#define __BACKEND_LZORLE_H__
#include "zcomp.h"
extern const struct zcomp_ops backend_lzorle;
#endif /* __BACKEND_LZORLE_H__ */
@@ -0,0 +1,217 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/zstd.h>
#include "backend_zstd.h"
struct zstd_ctx {
zstd_cctx *cctx;
zstd_dctx *dctx;
void *cctx_mem;
void *dctx_mem;
};
struct zstd_params {
zstd_custom_mem custom_mem;
zstd_cdict *cdict;
zstd_ddict *ddict;
zstd_parameters cprm;
};
/*
* For C/D dictionaries we need to provide zstd with zstd_custom_mem,
* which zstd uses internally to allocate/free memory when needed.
*/
static void *zstd_custom_alloc(void *opaque, size_t size)
{
return kvzalloc(size, GFP_NOIO | __GFP_NOWARN);
}
static void zstd_custom_free(void *opaque, void *address)
{
kvfree(address);
}
static void zstd_release_params(struct zcomp_params *params)
{
struct zstd_params *zp = params->drv_data;
params->drv_data = NULL;
if (!zp)
return;
zstd_free_cdict(zp->cdict);
zstd_free_ddict(zp->ddict);
kfree(zp);
}
static int zstd_setup_params(struct zcomp_params *params)
{
zstd_compression_parameters prm;
struct zstd_params *zp;
zp = kzalloc_obj(*zp);
if (!zp)
return -ENOMEM;
params->drv_data = zp;
if (params->level == ZCOMP_PARAM_NOT_SET)
params->level = zstd_default_clevel();
zp->cprm = zstd_get_params(params->level, PAGE_SIZE);
zp->custom_mem.customAlloc = zstd_custom_alloc;
zp->custom_mem.customFree = zstd_custom_free;
prm = zstd_get_cparams(params->level, PAGE_SIZE,
params->dict_sz);
zp->cdict = zstd_create_cdict_byreference(params->dict,
params->dict_sz,
prm,
zp->custom_mem);
if (!zp->cdict)
goto error;
zp->ddict = zstd_create_ddict_byreference(params->dict,
params->dict_sz,
zp->custom_mem);
if (!zp->ddict)
goto error;
return 0;
error:
zstd_release_params(params);
return -EINVAL;
}
static void zstd_destroy(struct zcomp_ctx *ctx)
{
struct zstd_ctx *zctx = ctx->context;
if (!zctx)
return;
/*
* If ->cctx_mem and ->dctx_mem were allocated then we didn't use
* C/D dictionary and ->cctx / ->dctx were "embedded" into these
* buffers.
*
* If otherwise then we need to explicitly release ->cctx / ->dctx.
*/
if (zctx->cctx_mem)
vfree(zctx->cctx_mem);
else
zstd_free_cctx(zctx->cctx);
if (zctx->dctx_mem)
vfree(zctx->dctx_mem);
else
zstd_free_dctx(zctx->dctx);
kfree(zctx);
}
static int zstd_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
{
struct zstd_ctx *zctx;
zstd_parameters prm;
size_t sz;
zctx = kzalloc_obj(*zctx);
if (!zctx)
return -ENOMEM;
ctx->context = zctx;
if (params->dict_sz == 0) {
prm = zstd_get_params(params->level, PAGE_SIZE);
sz = zstd_cctx_workspace_bound(&prm.cParams);
zctx->cctx_mem = vzalloc(sz);
if (!zctx->cctx_mem)
goto error;
zctx->cctx = zstd_init_cctx(zctx->cctx_mem, sz);
if (!zctx->cctx)
goto error;
sz = zstd_dctx_workspace_bound();
zctx->dctx_mem = vzalloc(sz);
if (!zctx->dctx_mem)
goto error;
zctx->dctx = zstd_init_dctx(zctx->dctx_mem, sz);
if (!zctx->dctx)
goto error;
} else {
struct zstd_params *zp = params->drv_data;
zctx->cctx = zstd_create_cctx_advanced(zp->custom_mem);
if (!zctx->cctx)
goto error;
zctx->dctx = zstd_create_dctx_advanced(zp->custom_mem);
if (!zctx->dctx)
goto error;
}
return 0;
error:
zstd_release_params(params);
zstd_destroy(ctx);
return -EINVAL;
}
static int zstd_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
struct zstd_params *zp = params->drv_data;
struct zstd_ctx *zctx = ctx->context;
size_t ret;
if (params->dict_sz == 0)
ret = zstd_compress_cctx(zctx->cctx, req->dst, req->dst_len,
req->src, req->src_len, &zp->cprm);
else
ret = zstd_compress_using_cdict(zctx->cctx, req->dst,
req->dst_len, req->src,
req->src_len,
zp->cdict);
if (zstd_is_error(ret))
return -EINVAL;
req->dst_len = ret;
return 0;
}
static int zstd_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req)
{
struct zstd_params *zp = params->drv_data;
struct zstd_ctx *zctx = ctx->context;
size_t ret;
if (params->dict_sz == 0)
ret = zstd_decompress_dctx(zctx->dctx, req->dst, req->dst_len,
req->src, req->src_len);
else
ret = zstd_decompress_using_ddict(zctx->dctx, req->dst,
req->dst_len, req->src,
req->src_len, zp->ddict);
if (zstd_is_error(ret))
return -EINVAL;
return 0;
}
const struct zcomp_ops backend_zstd = {
.compress = zstd_compress,
.decompress = zstd_decompress,
.create_ctx = zstd_create,
.destroy_ctx = zstd_destroy,
.setup_params = zstd_setup_params,
.release_params = zstd_release_params,
.name = "zstd",
};
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef __BACKEND_ZSTD_H__
#define __BACKEND_ZSTD_H__
#include "zcomp.h"
extern const struct zcomp_ops backend_zstd;
#endif /* __BACKEND_ZSTD_H__ */
+262
View File
@@ -0,0 +1,262 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cpuhotplug.h>
#include <linux/vmalloc.h>
#include <linux/sysfs.h>
#include "zcomp.h"
#include "backend_lzo.h"
#include "backend_lzorle.h"
#include "backend_lz4.h"
#include "backend_lz4hc.h"
#include "backend_zstd.h"
#include "backend_deflate.h"
#include "backend_842.h"
static const struct zcomp_ops *backends[] = {
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZO)
&backend_lzorle,
&backend_lzo,
#endif
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZ4)
&backend_lz4,
#endif
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZ4HC)
&backend_lz4hc,
#endif
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_ZSTD)
&backend_zstd,
#endif
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_DEFLATE)
&backend_deflate,
#endif
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_842)
&backend_842,
#endif
NULL
};
static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
{
comp->ops->destroy_ctx(&zstrm->ctx);
vfree(zstrm->local_copy);
vfree(zstrm->buffer);
zstrm->buffer = NULL;
}
static int zcomp_strm_init(struct zcomp *comp, struct zcomp_strm *zstrm)
{
int ret;
ret = comp->ops->create_ctx(comp->params, &zstrm->ctx);
if (ret)
return ret;
zstrm->local_copy = vzalloc(PAGE_SIZE);
/*
* allocate 2 pages. 1 for compressed data, plus 1 extra for the
* case when compressed size is larger than the original one
*/
zstrm->buffer = vzalloc(2 * PAGE_SIZE);
if (!zstrm->buffer || !zstrm->local_copy) {
zcomp_strm_free(comp, zstrm);
return -ENOMEM;
}
return 0;
}
static const struct zcomp_ops *lookup_backend_ops(const char *comp)
{
int i = 0;
while (backends[i]) {
if (sysfs_streq(comp, backends[i]->name))
break;
i++;
}
return backends[i];
}
const char *zcomp_lookup_backend_name(const char *comp)
{
const struct zcomp_ops *backend = lookup_backend_ops(comp);
if (backend)
return backend->name;
return NULL;
}
/* show available compressors */
ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at)
{
int i;
for (i = 0; i < ARRAY_SIZE(backends) - 1; i++) {
if (!strcmp(comp, backends[i]->name)) {
at += sysfs_emit_at(buf, at, "[%s] ",
backends[i]->name);
} else {
at += sysfs_emit_at(buf, at, "%s ", backends[i]->name);
}
}
at += sysfs_emit_at(buf, at, "\n");
return at;
}
struct zcomp_strm *zcomp_stream_get(struct zcomp *comp)
{
for (;;) {
struct zcomp_strm *zstrm = raw_cpu_ptr(comp->stream);
/*
* Inspired by zswap
*
* stream is returned with ->mutex locked which prevents
* cpu_dead() from releasing this stream under us, however
* there is still a race window between raw_cpu_ptr() and
* mutex_lock(), during which we could have been migrated
* from a CPU that has already destroyed its stream. If
* so then unlock and re-try on the current CPU.
*/
mutex_lock(&zstrm->lock);
if (likely(zstrm->buffer))
return zstrm;
mutex_unlock(&zstrm->lock);
}
}
void zcomp_stream_put(struct zcomp_strm *zstrm)
{
mutex_unlock(&zstrm->lock);
}
int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
const void *src, unsigned int *dst_len)
{
struct zcomp_req req = {
.src = src,
.dst = zstrm->buffer,
.src_len = PAGE_SIZE,
.dst_len = 2 * PAGE_SIZE,
};
int ret;
might_sleep();
ret = comp->ops->compress(comp->params, &zstrm->ctx, &req);
if (!ret)
*dst_len = req.dst_len;
return ret;
}
int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
const void *src, unsigned int src_len, void *dst)
{
struct zcomp_req req = {
.src = src,
.dst = dst,
.src_len = src_len,
.dst_len = PAGE_SIZE,
};
might_sleep();
return comp->ops->decompress(comp->params, &zstrm->ctx, &req);
}
int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node)
{
struct zcomp *comp = hlist_entry(node, struct zcomp, node);
struct zcomp_strm *zstrm = per_cpu_ptr(comp->stream, cpu);
int ret;
ret = zcomp_strm_init(comp, zstrm);
if (ret)
pr_err("Can't allocate a compression stream\n");
return ret;
}
int zcomp_cpu_dead(unsigned int cpu, struct hlist_node *node)
{
struct zcomp *comp = hlist_entry(node, struct zcomp, node);
struct zcomp_strm *zstrm = per_cpu_ptr(comp->stream, cpu);
mutex_lock(&zstrm->lock);
zcomp_strm_free(comp, zstrm);
mutex_unlock(&zstrm->lock);
return 0;
}
static int zcomp_init(struct zcomp *comp, struct zcomp_params *params)
{
int ret, cpu;
comp->stream = alloc_percpu(struct zcomp_strm);
if (!comp->stream)
return -ENOMEM;
comp->params = params;
ret = comp->ops->setup_params(comp->params);
if (ret)
goto cleanup;
for_each_possible_cpu(cpu)
mutex_init(&per_cpu_ptr(comp->stream, cpu)->lock);
ret = cpuhp_state_add_instance(CPUHP_ZCOMP_PREPARE, &comp->node);
if (ret < 0)
goto cleanup;
return 0;
cleanup:
comp->ops->release_params(comp->params);
free_percpu(comp->stream);
return ret;
}
void zcomp_destroy(struct zcomp *comp)
{
cpuhp_state_remove_instance(CPUHP_ZCOMP_PREPARE, &comp->node);
comp->ops->release_params(comp->params);
free_percpu(comp->stream);
kfree(comp);
}
struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params)
{
struct zcomp *comp;
int error;
/*
* The backends array has a sentinel NULL value, so the minimum
* size is 1. In order to be valid the array, apart from the
* sentinel NULL element, should have at least one compression
* backend selected.
*/
BUILD_BUG_ON(ARRAY_SIZE(backends) <= 1);
comp = kzalloc_obj(struct zcomp);
if (!comp)
return ERR_PTR(-ENOMEM);
comp->ops = lookup_backend_ops(alg);
if (!comp->ops) {
kfree(comp);
return ERR_PTR(-EINVAL);
}
error = zcomp_init(comp, params);
if (error) {
kfree(comp);
return ERR_PTR(error);
}
return comp;
}
+96
View File
@@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _ZCOMP_H_
#define _ZCOMP_H_
#include <linux/mutex.h>
#define ZCOMP_PARAM_NOT_SET INT_MIN
struct deflate_params {
s32 winbits;
};
/*
* Immutable driver (backend) parameters. The driver may attach private
* data to it (e.g. driver representation of the dictionary, etc.).
*
* This data is kept per-comp and is shared among execution contexts.
*/
struct zcomp_params {
void *dict;
size_t dict_sz;
s32 level;
union {
struct deflate_params deflate;
};
void *drv_data;
};
/*
* Run-time driver context - scratch buffers, etc. It is modified during
* request execution (compression/decompression), cannot be shared, so
* it's in per-CPU area.
*/
struct zcomp_ctx {
void *context;
};
struct zcomp_strm {
struct mutex lock;
/* compression buffer */
void *buffer;
/* local copy of handle memory */
void *local_copy;
struct zcomp_ctx ctx;
};
struct zcomp_req {
const unsigned char *src;
const size_t src_len;
unsigned char *dst;
size_t dst_len;
};
struct zcomp_ops {
int (*compress)(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req);
int (*decompress)(struct zcomp_params *params, struct zcomp_ctx *ctx,
struct zcomp_req *req);
int (*create_ctx)(struct zcomp_params *params, struct zcomp_ctx *ctx);
void (*destroy_ctx)(struct zcomp_ctx *ctx);
int (*setup_params)(struct zcomp_params *params);
void (*release_params)(struct zcomp_params *params);
const char *name;
};
/* dynamic per-device compression frontend */
struct zcomp {
struct zcomp_strm __percpu *stream;
const struct zcomp_ops *ops;
struct zcomp_params *params;
struct hlist_node node;
};
int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node);
int zcomp_cpu_dead(unsigned int cpu, struct hlist_node *node);
ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at);
const char *zcomp_lookup_backend_name(const char *comp);
struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params);
void zcomp_destroy(struct zcomp *comp);
struct zcomp_strm *zcomp_stream_get(struct zcomp *comp);
void zcomp_stream_put(struct zcomp_strm *zstrm);
int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
const void *src, unsigned int *dst_len);
int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
const void *src, unsigned int src_len, void *dst);
#endif /* _ZCOMP_H_ */
File diff suppressed because it is too large Load Diff
+146
View File
@@ -0,0 +1,146 @@
/*
* Compressed RAM block device
*
* Copyright (C) 2008, 2009, 2010 Nitin Gupta
* 2012, 2013 Minchan Kim
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
*
* Released under the terms of 3-clause BSD License
* Released under the terms of GNU General Public License Version 2.0
*
*/
#ifndef _ZRAM_DRV_H_
#define _ZRAM_DRV_H_
#include <linux/rwsem.h>
#include <linux/zsmalloc.h>
#include "zcomp.h"
#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT)
#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT)
#define ZRAM_LOGICAL_BLOCK_SHIFT 12
#define ZRAM_LOGICAL_BLOCK_SIZE (1 << ZRAM_LOGICAL_BLOCK_SHIFT)
#define ZRAM_SECTOR_PER_LOGICAL_BLOCK \
(1 << (ZRAM_LOGICAL_BLOCK_SHIFT - SECTOR_SHIFT))
/*
* ZRAM is mainly used for memory efficiency so we want to keep memory
* footprint small and thus squeeze size and zram pageflags into a flags
* member. The lower ZRAM_FLAG_SHIFT bits is for object size (excluding
* header), which cannot be larger than PAGE_SIZE (requiring PAGE_SHIFT
* bits), the higher bits are for zram_pageflags.
*
* We use BUILD_BUG_ON() to make sure that zram pageflags don't overflow.
*/
#define ZRAM_FLAG_SHIFT (PAGE_SHIFT + 1)
/* Only 2 bits are allowed for comp priority index */
#define ZRAM_COMP_PRIORITY_MASK 0x3
/* Flags for zram pages (table[page_no].flags) */
enum zram_pageflags {
ZRAM_SAME = ZRAM_FLAG_SHIFT, /* Page consists the same element */
ZRAM_ENTRY_LOCK, /* entry access lock bit */
ZRAM_WB, /* page is stored on backing_device */
ZRAM_PP_SLOT, /* Selected for post-processing */
ZRAM_HUGE, /* Incompressible page */
ZRAM_IDLE, /* not accessed page since last idle marking */
ZRAM_INCOMPRESSIBLE, /* none of the algorithms could compress it */
ZRAM_COMP_PRIORITY_BIT1, /* First bit of comp priority index */
ZRAM_COMP_PRIORITY_BIT2, /* Second bit of comp priority index */
__NR_ZRAM_PAGEFLAGS,
};
/*
* Allocated for each disk page. We use bit-lock (ZRAM_ENTRY_LOCK bit
* of flags) to save memory. There can be plenty of entries and standard
* locking primitives (e.g. mutex) will significantly increase sizeof()
* of each entry and hence of the meta table.
*/
struct zram_table_entry {
unsigned long handle;
union {
unsigned long __lock;
struct attr {
u32 flags;
#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
u32 ac_time;
#endif
} attr;
};
struct lockdep_map dep_map;
};
struct zram_stats {
atomic64_t compr_data_size; /* compressed size of pages stored */
atomic64_t failed_reads; /* can happen when memory is too low */
atomic64_t failed_writes; /* can happen when memory is too low */
atomic64_t notify_free; /* no. of swap slot free notifications */
atomic64_t same_pages; /* no. of same element filled pages */
atomic64_t huge_pages; /* no. of huge pages */
atomic64_t huge_pages_since; /* no. of huge pages since zram set up */
atomic64_t pages_stored; /* no. of pages currently stored */
atomic_long_t max_used_pages; /* no. of maximum pages stored */
atomic64_t miss_free; /* no. of missed free */
#ifdef CONFIG_ZRAM_WRITEBACK
atomic64_t bd_count; /* no. of pages in backing device */
atomic64_t bd_reads; /* no. of reads from backing device */
atomic64_t bd_writes; /* no. of writes from backing device */
#endif
};
#ifdef CONFIG_ZRAM_MULTI_COMP
#define ZRAM_PRIMARY_COMP 0U
#define ZRAM_SECONDARY_COMP 1U
#define ZRAM_MAX_COMPS 4U
#else
#define ZRAM_PRIMARY_COMP 0U
#define ZRAM_SECONDARY_COMP 0U
#define ZRAM_MAX_COMPS 1U
#endif
struct zram {
struct zram_table_entry *table;
struct zs_pool *mem_pool;
struct zcomp *comps[ZRAM_MAX_COMPS];
struct zcomp_params params[ZRAM_MAX_COMPS];
struct gendisk *disk;
/* Locks the device either in exclusive or in shared mode */
struct rw_semaphore dev_lock;
/*
* the number of pages zram can consume for storing compressed data
*/
unsigned long limit_pages;
struct zram_stats stats;
/*
* This is the limit on amount of *uncompressed* worth of data
* we can store in a disk.
*/
u64 disksize; /* bytes */
const char *comp_algs[ZRAM_MAX_COMPS];
/*
* zram is claimed so open request will be failed
*/
bool claim; /* Protected by disk->open_mutex */
#ifdef CONFIG_ZRAM_WRITEBACK
struct file *backing_dev;
bool wb_limit_enable;
bool compressed_wb;
u32 wb_batch_size;
u64 bd_wb_limit;
struct block_device *bdev;
unsigned long *bitmap;
unsigned long nr_pages;
#endif
#ifdef CONFIG_ZRAM_MEMORY_TRACKING
struct dentry *debugfs_dir;
#endif
};
#endif