Commit 50cfa66f authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim

f2fs: compress: support zstd compress algorithm

Add zstd compress algorithm support, use "compress_algorithm=zstd"
mountoption to enable it.
Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 23b1faaa
...@@ -235,8 +235,8 @@ checkpoint=%s[:%u[%]] Set to "disable" to turn off checkpointing. Set to "en ...@@ -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 ...@@ -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 @@ ...@@ -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 = { ...@@ -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] = { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) ...@@ -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, ...@@ -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); ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment