Skip to content

Commit 50cfa66

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: compress: support zstd compress algorithm
Add zstd compress algorithm support, use "compress_algorithm=zstd" mountoption to enable it. Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 23b1faa commit 50cfa66

File tree

6 files changed

+190
-3
lines changed

6 files changed

+190
-3
lines changed

Documentation/filesystems/f2fs.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ checkpoint=%s[:%u[%]] Set to "disable" to turn off checkpointing. Set to "en
235235
hide up to all remaining free space. The actual space that
236236
would be unusable can be viewed at /sys/fs/f2fs/<disk>/unusable
237237
This space is reclaimed once checkpoint=enable.
238-
compress_algorithm=%s Control compress algorithm, currently f2fs supports "lzo"
239-
and "lz4" algorithm.
238+
compress_algorithm=%s Control compress algorithm, currently f2fs supports "lzo",
239+
"lz4" and "zstd" algorithm.
240240
compress_log_size=%u Support configuring compress cluster size, the size will
241241
be 4KB * (1 << %u), 16KB is minimum size, also it's
242242
default size.

fs/f2fs/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,12 @@ config F2FS_FS_LZ4
118118
default y
119119
help
120120
Support LZ4 compress algorithm, if unsure, say Y.
121+
122+
config F2FS_FS_ZSTD
123+
bool "ZSTD compression support"
124+
depends on F2FS_FS_COMPRESSION
125+
select ZSTD_COMPRESS
126+
select ZSTD_DECOMPRESS
127+
default y
128+
help
129+
Support ZSTD compress algorithm, if unsure, say Y.

fs/f2fs/compress.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/backing-dev.h>
1212
#include <linux/lzo.h>
1313
#include <linux/lz4.h>
14+
#include <linux/zstd.h>
1415

1516
#include "f2fs.h"
1617
#include "node.h"
@@ -291,6 +292,165 @@ static const struct f2fs_compress_ops f2fs_lz4_ops = {
291292
};
292293
#endif
293294

295+
#ifdef CONFIG_F2FS_FS_ZSTD
296+
#define F2FS_ZSTD_DEFAULT_CLEVEL 1
297+
298+
static int zstd_init_compress_ctx(struct compress_ctx *cc)
299+
{
300+
ZSTD_parameters params;
301+
ZSTD_CStream *stream;
302+
void *workspace;
303+
unsigned int workspace_size;
304+
305+
params = ZSTD_getParams(F2FS_ZSTD_DEFAULT_CLEVEL, cc->rlen, 0);
306+
workspace_size = ZSTD_CStreamWorkspaceBound(params.cParams);
307+
308+
workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode),
309+
workspace_size, GFP_NOFS);
310+
if (!workspace)
311+
return -ENOMEM;
312+
313+
stream = ZSTD_initCStream(params, 0, workspace, workspace_size);
314+
if (!stream) {
315+
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initCStream failed\n",
316+
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
317+
__func__);
318+
kvfree(workspace);
319+
return -EIO;
320+
}
321+
322+
cc->private = workspace;
323+
cc->private2 = stream;
324+
325+
cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE;
326+
return 0;
327+
}
328+
329+
static void zstd_destroy_compress_ctx(struct compress_ctx *cc)
330+
{
331+
kvfree(cc->private);
332+
cc->private = NULL;
333+
cc->private2 = NULL;
334+
}
335+
336+
static int zstd_compress_pages(struct compress_ctx *cc)
337+
{
338+
ZSTD_CStream *stream = cc->private2;
339+
ZSTD_inBuffer inbuf;
340+
ZSTD_outBuffer outbuf;
341+
int src_size = cc->rlen;
342+
int dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE;
343+
int ret;
344+
345+
inbuf.pos = 0;
346+
inbuf.src = cc->rbuf;
347+
inbuf.size = src_size;
348+
349+
outbuf.pos = 0;
350+
outbuf.dst = cc->cbuf->cdata;
351+
outbuf.size = dst_size;
352+
353+
ret = ZSTD_compressStream(stream, &outbuf, &inbuf);
354+
if (ZSTD_isError(ret)) {
355+
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n",
356+
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
357+
__func__, ZSTD_getErrorCode(ret));
358+
return -EIO;
359+
}
360+
361+
ret = ZSTD_endStream(stream, &outbuf);
362+
if (ZSTD_isError(ret)) {
363+
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_endStream returned %d\n",
364+
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
365+
__func__, ZSTD_getErrorCode(ret));
366+
return -EIO;
367+
}
368+
369+
cc->clen = outbuf.pos;
370+
return 0;
371+
}
372+
373+
static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic)
374+
{
375+
ZSTD_DStream *stream;
376+
void *workspace;
377+
unsigned int workspace_size;
378+
379+
workspace_size = ZSTD_DStreamWorkspaceBound(MAX_COMPRESS_WINDOW_SIZE);
380+
381+
workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode),
382+
workspace_size, GFP_NOFS);
383+
if (!workspace)
384+
return -ENOMEM;
385+
386+
stream = ZSTD_initDStream(MAX_COMPRESS_WINDOW_SIZE,
387+
workspace, workspace_size);
388+
if (!stream) {
389+
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initDStream failed\n",
390+
KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id,
391+
__func__);
392+
kvfree(workspace);
393+
return -EIO;
394+
}
395+
396+
dic->private = workspace;
397+
dic->private2 = stream;
398+
399+
return 0;
400+
}
401+
402+
static void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic)
403+
{
404+
kvfree(dic->private);
405+
dic->private = NULL;
406+
dic->private2 = NULL;
407+
}
408+
409+
static int zstd_decompress_pages(struct decompress_io_ctx *dic)
410+
{
411+
ZSTD_DStream *stream = dic->private2;
412+
ZSTD_inBuffer inbuf;
413+
ZSTD_outBuffer outbuf;
414+
int ret;
415+
416+
inbuf.pos = 0;
417+
inbuf.src = dic->cbuf->cdata;
418+
inbuf.size = dic->clen;
419+
420+
outbuf.pos = 0;
421+
outbuf.dst = dic->rbuf;
422+
outbuf.size = dic->rlen;
423+
424+
ret = ZSTD_decompressStream(stream, &outbuf, &inbuf);
425+
if (ZSTD_isError(ret)) {
426+
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n",
427+
KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id,
428+
__func__, ZSTD_getErrorCode(ret));
429+
return -EIO;
430+
}
431+
432+
if (dic->rlen != outbuf.pos) {
433+
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, "
434+
"expected:%lu\n", KERN_ERR,
435+
F2FS_I_SB(dic->inode)->sb->s_id,
436+
__func__, dic->rlen,
437+
PAGE_SIZE << dic->log_cluster_size);
438+
return -EIO;
439+
}
440+
441+
return 0;
442+
}
443+
444+
static const struct f2fs_compress_ops f2fs_zstd_ops = {
445+
.init_compress_ctx = zstd_init_compress_ctx,
446+
.destroy_compress_ctx = zstd_destroy_compress_ctx,
447+
.compress_pages = zstd_compress_pages,
448+
.init_decompress_ctx = zstd_init_decompress_ctx,
449+
.destroy_decompress_ctx = zstd_destroy_decompress_ctx,
450+
.decompress_pages = zstd_decompress_pages,
451+
};
452+
#endif
453+
294454
static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = {
295455
#ifdef CONFIG_F2FS_FS_LZO
296456
&f2fs_lzo_ops,
@@ -302,6 +462,11 @@ static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = {
302462
#else
303463
NULL,
304464
#endif
465+
#ifdef CONFIG_F2FS_FS_ZSTD
466+
&f2fs_zstd_ops,
467+
#else
468+
NULL,
469+
#endif
305470
};
306471

307472
bool f2fs_is_compress_backend_ready(struct inode *inode)

fs/f2fs/f2fs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,7 @@ enum fsync_mode {
12671267
enum compress_algorithm_type {
12681268
COMPRESS_LZO,
12691269
COMPRESS_LZ4,
1270+
COMPRESS_ZSTD,
12701271
COMPRESS_MAX,
12711272
};
12721273

@@ -1296,6 +1297,7 @@ struct compress_ctx {
12961297
size_t rlen; /* valid data length in rbuf */
12971298
size_t clen; /* valid data length in cbuf */
12981299
void *private; /* payload buffer for specified compression algorithm */
1300+
void *private2; /* extra payload buffer */
12991301
};
13001302

13011303
/* compress context for write IO path */
@@ -1325,11 +1327,14 @@ struct decompress_io_ctx {
13251327
size_t clen; /* valid data length in cbuf */
13261328
refcount_t ref; /* referrence count of compressed page */
13271329
bool failed; /* indicate IO error during decompression */
1330+
void *private; /* payload buffer for specified decompression algorithm */
1331+
void *private2; /* extra payload buffer */
13281332
};
13291333

13301334
#define NULL_CLUSTER ((unsigned int)(~0))
13311335
#define MIN_COMPRESS_LOG_SIZE 2
13321336
#define MAX_COMPRESS_LOG_SIZE 8
1337+
#define MAX_COMPRESS_WINDOW_SIZE ((PAGE_SIZE) << MAX_COMPRESS_LOG_SIZE)
13331338

13341339
struct f2fs_sb_info {
13351340
struct super_block *sb; /* pointer to VFS super block */

fs/f2fs/super.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,10 @@ static int parse_options(struct super_block *sb, char *options)
829829
!strcmp(name, "lz4")) {
830830
F2FS_OPTION(sbi).compress_algorithm =
831831
COMPRESS_LZ4;
832+
} else if (strlen(name) == 4 &&
833+
!strcmp(name, "zstd")) {
834+
F2FS_OPTION(sbi).compress_algorithm =
835+
COMPRESS_ZSTD;
832836
} else {
833837
kfree(name);
834838
return -EINVAL;
@@ -1419,6 +1423,9 @@ static inline void f2fs_show_compress_options(struct seq_file *seq,
14191423
case COMPRESS_LZ4:
14201424
algtype = "lz4";
14211425
break;
1426+
case COMPRESS_ZSTD:
1427+
algtype = "zstd";
1428+
break;
14221429
}
14231430
seq_printf(seq, ",compress_algorithm=%s", algtype);
14241431

include/trace/events/f2fs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ TRACE_DEFINE_ENUM(CP_PAUSE);
153153
#define show_compress_algorithm(type) \
154154
__print_symbolic(type, \
155155
{ COMPRESS_LZO, "LZO" }, \
156-
{ COMPRESS_LZ4, "LZ4" })
156+
{ COMPRESS_LZ4, "LZ4" }, \
157+
{ COMPRESS_ZSTD, "ZSTD" })
157158

158159
struct f2fs_sb_info;
159160
struct f2fs_io_info;

0 commit comments

Comments
 (0)