mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-04-20 05:03:55 +00:00
f2fs: compress: support zstd compress algorithm
Add zstd compress algorithm support, use "compress_algorithm=zstd" mountoption to enable it. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
23b1faaade
commit
50cfa66f0d
6 changed files with 190 additions and 3 deletions
|
@ -235,8 +235,8 @@ checkpoint=%s[:%u[%]] Set to "disable" to turn off checkpointing. Set to "en
|
||||||
hide up to all remaining free space. The actual space that
|
hide up to all remaining free space. The actual space that
|
||||||
would be unusable can be viewed at /sys/fs/f2fs/<disk>/unusable
|
would be unusable can be viewed at /sys/fs/f2fs/<disk>/unusable
|
||||||
This space is reclaimed once checkpoint=enable.
|
This space is reclaimed once checkpoint=enable.
|
||||||
compress_algorithm=%s Control compress algorithm, currently f2fs supports "lzo"
|
compress_algorithm=%s Control compress algorithm, currently f2fs supports "lzo",
|
||||||
and "lz4" algorithm.
|
"lz4" and "zstd" algorithm.
|
||||||
compress_log_size=%u Support configuring compress cluster size, the size will
|
compress_log_size=%u Support configuring compress cluster size, the size will
|
||||||
be 4KB * (1 << %u), 16KB is minimum size, also it's
|
be 4KB * (1 << %u), 16KB is minimum size, also it's
|
||||||
default size.
|
default size.
|
||||||
|
|
|
@ -118,3 +118,12 @@ config F2FS_FS_LZ4
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Support LZ4 compress algorithm, if unsure, say Y.
|
Support LZ4 compress algorithm, if unsure, say Y.
|
||||||
|
|
||||||
|
config F2FS_FS_ZSTD
|
||||||
|
bool "ZSTD compression support"
|
||||||
|
depends on F2FS_FS_COMPRESSION
|
||||||
|
select ZSTD_COMPRESS
|
||||||
|
select ZSTD_DECOMPRESS
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Support ZSTD compress algorithm, if unsure, say Y.
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/backing-dev.h>
|
#include <linux/backing-dev.h>
|
||||||
#include <linux/lzo.h>
|
#include <linux/lzo.h>
|
||||||
#include <linux/lz4.h>
|
#include <linux/lz4.h>
|
||||||
|
#include <linux/zstd.h>
|
||||||
|
|
||||||
#include "f2fs.h"
|
#include "f2fs.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
@ -291,6 +292,165 @@ static const struct f2fs_compress_ops f2fs_lz4_ops = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_F2FS_FS_ZSTD
|
||||||
|
#define F2FS_ZSTD_DEFAULT_CLEVEL 1
|
||||||
|
|
||||||
|
static int zstd_init_compress_ctx(struct compress_ctx *cc)
|
||||||
|
{
|
||||||
|
ZSTD_parameters params;
|
||||||
|
ZSTD_CStream *stream;
|
||||||
|
void *workspace;
|
||||||
|
unsigned int workspace_size;
|
||||||
|
|
||||||
|
params = ZSTD_getParams(F2FS_ZSTD_DEFAULT_CLEVEL, cc->rlen, 0);
|
||||||
|
workspace_size = ZSTD_CStreamWorkspaceBound(params.cParams);
|
||||||
|
|
||||||
|
workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode),
|
||||||
|
workspace_size, GFP_NOFS);
|
||||||
|
if (!workspace)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
stream = ZSTD_initCStream(params, 0, workspace, workspace_size);
|
||||||
|
if (!stream) {
|
||||||
|
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initCStream failed\n",
|
||||||
|
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
|
||||||
|
__func__);
|
||||||
|
kvfree(workspace);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc->private = workspace;
|
||||||
|
cc->private2 = stream;
|
||||||
|
|
||||||
|
cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zstd_destroy_compress_ctx(struct compress_ctx *cc)
|
||||||
|
{
|
||||||
|
kvfree(cc->private);
|
||||||
|
cc->private = NULL;
|
||||||
|
cc->private2 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zstd_compress_pages(struct compress_ctx *cc)
|
||||||
|
{
|
||||||
|
ZSTD_CStream *stream = cc->private2;
|
||||||
|
ZSTD_inBuffer inbuf;
|
||||||
|
ZSTD_outBuffer outbuf;
|
||||||
|
int src_size = cc->rlen;
|
||||||
|
int dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
inbuf.pos = 0;
|
||||||
|
inbuf.src = cc->rbuf;
|
||||||
|
inbuf.size = src_size;
|
||||||
|
|
||||||
|
outbuf.pos = 0;
|
||||||
|
outbuf.dst = cc->cbuf->cdata;
|
||||||
|
outbuf.size = dst_size;
|
||||||
|
|
||||||
|
ret = ZSTD_compressStream(stream, &outbuf, &inbuf);
|
||||||
|
if (ZSTD_isError(ret)) {
|
||||||
|
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n",
|
||||||
|
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
|
||||||
|
__func__, ZSTD_getErrorCode(ret));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ZSTD_endStream(stream, &outbuf);
|
||||||
|
if (ZSTD_isError(ret)) {
|
||||||
|
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_endStream returned %d\n",
|
||||||
|
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
|
||||||
|
__func__, ZSTD_getErrorCode(ret));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc->clen = outbuf.pos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic)
|
||||||
|
{
|
||||||
|
ZSTD_DStream *stream;
|
||||||
|
void *workspace;
|
||||||
|
unsigned int workspace_size;
|
||||||
|
|
||||||
|
workspace_size = ZSTD_DStreamWorkspaceBound(MAX_COMPRESS_WINDOW_SIZE);
|
||||||
|
|
||||||
|
workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode),
|
||||||
|
workspace_size, GFP_NOFS);
|
||||||
|
if (!workspace)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
stream = ZSTD_initDStream(MAX_COMPRESS_WINDOW_SIZE,
|
||||||
|
workspace, workspace_size);
|
||||||
|
if (!stream) {
|
||||||
|
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initDStream failed\n",
|
||||||
|
KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id,
|
||||||
|
__func__);
|
||||||
|
kvfree(workspace);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
dic->private = workspace;
|
||||||
|
dic->private2 = stream;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic)
|
||||||
|
{
|
||||||
|
kvfree(dic->private);
|
||||||
|
dic->private = NULL;
|
||||||
|
dic->private2 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zstd_decompress_pages(struct decompress_io_ctx *dic)
|
||||||
|
{
|
||||||
|
ZSTD_DStream *stream = dic->private2;
|
||||||
|
ZSTD_inBuffer inbuf;
|
||||||
|
ZSTD_outBuffer outbuf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
inbuf.pos = 0;
|
||||||
|
inbuf.src = dic->cbuf->cdata;
|
||||||
|
inbuf.size = dic->clen;
|
||||||
|
|
||||||
|
outbuf.pos = 0;
|
||||||
|
outbuf.dst = dic->rbuf;
|
||||||
|
outbuf.size = dic->rlen;
|
||||||
|
|
||||||
|
ret = ZSTD_decompressStream(stream, &outbuf, &inbuf);
|
||||||
|
if (ZSTD_isError(ret)) {
|
||||||
|
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n",
|
||||||
|
KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id,
|
||||||
|
__func__, ZSTD_getErrorCode(ret));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dic->rlen != outbuf.pos) {
|
||||||
|
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, "
|
||||||
|
"expected:%lu\n", KERN_ERR,
|
||||||
|
F2FS_I_SB(dic->inode)->sb->s_id,
|
||||||
|
__func__, dic->rlen,
|
||||||
|
PAGE_SIZE << dic->log_cluster_size);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct f2fs_compress_ops f2fs_zstd_ops = {
|
||||||
|
.init_compress_ctx = zstd_init_compress_ctx,
|
||||||
|
.destroy_compress_ctx = zstd_destroy_compress_ctx,
|
||||||
|
.compress_pages = zstd_compress_pages,
|
||||||
|
.init_decompress_ctx = zstd_init_decompress_ctx,
|
||||||
|
.destroy_decompress_ctx = zstd_destroy_decompress_ctx,
|
||||||
|
.decompress_pages = zstd_decompress_pages,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = {
|
static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = {
|
||||||
#ifdef CONFIG_F2FS_FS_LZO
|
#ifdef CONFIG_F2FS_FS_LZO
|
||||||
&f2fs_lzo_ops,
|
&f2fs_lzo_ops,
|
||||||
|
@ -302,6 +462,11 @@ static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = {
|
||||||
#else
|
#else
|
||||||
NULL,
|
NULL,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_F2FS_FS_ZSTD
|
||||||
|
&f2fs_zstd_ops,
|
||||||
|
#else
|
||||||
|
NULL,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
bool f2fs_is_compress_backend_ready(struct inode *inode)
|
bool f2fs_is_compress_backend_ready(struct inode *inode)
|
||||||
|
|
|
@ -1267,6 +1267,7 @@ enum fsync_mode {
|
||||||
enum compress_algorithm_type {
|
enum compress_algorithm_type {
|
||||||
COMPRESS_LZO,
|
COMPRESS_LZO,
|
||||||
COMPRESS_LZ4,
|
COMPRESS_LZ4,
|
||||||
|
COMPRESS_ZSTD,
|
||||||
COMPRESS_MAX,
|
COMPRESS_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1296,6 +1297,7 @@ struct compress_ctx {
|
||||||
size_t rlen; /* valid data length in rbuf */
|
size_t rlen; /* valid data length in rbuf */
|
||||||
size_t clen; /* valid data length in cbuf */
|
size_t clen; /* valid data length in cbuf */
|
||||||
void *private; /* payload buffer for specified compression algorithm */
|
void *private; /* payload buffer for specified compression algorithm */
|
||||||
|
void *private2; /* extra payload buffer */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* compress context for write IO path */
|
/* compress context for write IO path */
|
||||||
|
@ -1325,11 +1327,14 @@ struct decompress_io_ctx {
|
||||||
size_t clen; /* valid data length in cbuf */
|
size_t clen; /* valid data length in cbuf */
|
||||||
refcount_t ref; /* referrence count of compressed page */
|
refcount_t ref; /* referrence count of compressed page */
|
||||||
bool failed; /* indicate IO error during decompression */
|
bool failed; /* indicate IO error during decompression */
|
||||||
|
void *private; /* payload buffer for specified decompression algorithm */
|
||||||
|
void *private2; /* extra payload buffer */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NULL_CLUSTER ((unsigned int)(~0))
|
#define NULL_CLUSTER ((unsigned int)(~0))
|
||||||
#define MIN_COMPRESS_LOG_SIZE 2
|
#define MIN_COMPRESS_LOG_SIZE 2
|
||||||
#define MAX_COMPRESS_LOG_SIZE 8
|
#define MAX_COMPRESS_LOG_SIZE 8
|
||||||
|
#define MAX_COMPRESS_WINDOW_SIZE ((PAGE_SIZE) << MAX_COMPRESS_LOG_SIZE)
|
||||||
|
|
||||||
struct f2fs_sb_info {
|
struct f2fs_sb_info {
|
||||||
struct super_block *sb; /* pointer to VFS super block */
|
struct super_block *sb; /* pointer to VFS super block */
|
||||||
|
|
|
@ -829,6 +829,10 @@ static int parse_options(struct super_block *sb, char *options)
|
||||||
!strcmp(name, "lz4")) {
|
!strcmp(name, "lz4")) {
|
||||||
F2FS_OPTION(sbi).compress_algorithm =
|
F2FS_OPTION(sbi).compress_algorithm =
|
||||||
COMPRESS_LZ4;
|
COMPRESS_LZ4;
|
||||||
|
} else if (strlen(name) == 4 &&
|
||||||
|
!strcmp(name, "zstd")) {
|
||||||
|
F2FS_OPTION(sbi).compress_algorithm =
|
||||||
|
COMPRESS_ZSTD;
|
||||||
} else {
|
} else {
|
||||||
kfree(name);
|
kfree(name);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1419,6 +1423,9 @@ static inline void f2fs_show_compress_options(struct seq_file *seq,
|
||||||
case COMPRESS_LZ4:
|
case COMPRESS_LZ4:
|
||||||
algtype = "lz4";
|
algtype = "lz4";
|
||||||
break;
|
break;
|
||||||
|
case COMPRESS_ZSTD:
|
||||||
|
algtype = "zstd";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
seq_printf(seq, ",compress_algorithm=%s", algtype);
|
seq_printf(seq, ",compress_algorithm=%s", algtype);
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,8 @@ TRACE_DEFINE_ENUM(CP_PAUSE);
|
||||||
#define show_compress_algorithm(type) \
|
#define show_compress_algorithm(type) \
|
||||||
__print_symbolic(type, \
|
__print_symbolic(type, \
|
||||||
{ COMPRESS_LZO, "LZO" }, \
|
{ COMPRESS_LZO, "LZO" }, \
|
||||||
{ COMPRESS_LZ4, "LZ4" })
|
{ COMPRESS_LZ4, "LZ4" }, \
|
||||||
|
{ COMPRESS_ZSTD, "ZSTD" })
|
||||||
|
|
||||||
struct f2fs_sb_info;
|
struct f2fs_sb_info;
|
||||||
struct f2fs_io_info;
|
struct f2fs_io_info;
|
||||||
|
|
Loading…
Add table
Reference in a new issue