Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Chao Yu and committed by
Jaegeuk Kim
50cfa66f 23b1faaa

+190 -3
+2 -2
Documentation/filesystems/f2fs.txt
··· 235 235 hide up to all remaining free space. The actual space that 236 236 would be unusable can be viewed at /sys/fs/f2fs/<disk>/unusable 237 237 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. 240 240 compress_log_size=%u Support configuring compress cluster size, the size will 241 241 be 4KB * (1 << %u), 16KB is minimum size, also it's 242 242 default size.
+9
fs/f2fs/Kconfig
··· 118 118 default y 119 119 help 120 120 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.
+165
fs/f2fs/compress.c
··· 11 11 #include <linux/backing-dev.h> 12 12 #include <linux/lzo.h> 13 13 #include <linux/lz4.h> 14 + #include <linux/zstd.h> 14 15 15 16 #include "f2fs.h" 16 17 #include "node.h" ··· 292 291 }; 293 292 #endif 294 293 294 + #ifdef CONFIG_F2FS_FS_ZSTD 295 + #define F2FS_ZSTD_DEFAULT_CLEVEL 1 296 + 297 + static int zstd_init_compress_ctx(struct compress_ctx *cc) 298 + { 299 + ZSTD_parameters params; 300 + ZSTD_CStream *stream; 301 + void *workspace; 302 + unsigned int workspace_size; 303 + 304 + params = ZSTD_getParams(F2FS_ZSTD_DEFAULT_CLEVEL, cc->rlen, 0); 305 + workspace_size = ZSTD_CStreamWorkspaceBound(params.cParams); 306 + 307 + workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode), 308 + workspace_size, GFP_NOFS); 309 + if (!workspace) 310 + return -ENOMEM; 311 + 312 + stream = ZSTD_initCStream(params, 0, workspace, workspace_size); 313 + if (!stream) { 314 + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initCStream failed\n", 315 + KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 316 + __func__); 317 + kvfree(workspace); 318 + return -EIO; 319 + } 320 + 321 + cc->private = workspace; 322 + cc->private2 = stream; 323 + 324 + cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE; 325 + return 0; 326 + } 327 + 328 + static void zstd_destroy_compress_ctx(struct compress_ctx *cc) 329 + { 330 + kvfree(cc->private); 331 + cc->private = NULL; 332 + cc->private2 = NULL; 333 + } 334 + 335 + static int zstd_compress_pages(struct compress_ctx *cc) 336 + { 337 + ZSTD_CStream *stream = cc->private2; 338 + ZSTD_inBuffer inbuf; 339 + ZSTD_outBuffer outbuf; 340 + int src_size = cc->rlen; 341 + int dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE; 342 + int ret; 343 + 344 + inbuf.pos = 0; 345 + inbuf.src = cc->rbuf; 346 + inbuf.size = src_size; 347 + 348 + outbuf.pos = 0; 349 + outbuf.dst = cc->cbuf->cdata; 350 + outbuf.size = dst_size; 351 + 352 + ret = ZSTD_compressStream(stream, &outbuf, &inbuf); 353 + if (ZSTD_isError(ret)) { 354 + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n", 355 + KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 356 + __func__, ZSTD_getErrorCode(ret)); 357 + return -EIO; 358 + } 359 + 360 + ret = ZSTD_endStream(stream, &outbuf); 361 + if (ZSTD_isError(ret)) { 362 + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_endStream returned %d\n", 363 + KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 364 + __func__, ZSTD_getErrorCode(ret)); 365 + return -EIO; 366 + } 367 + 368 + cc->clen = outbuf.pos; 369 + return 0; 370 + } 371 + 372 + static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) 373 + { 374 + ZSTD_DStream *stream; 375 + void *workspace; 376 + unsigned int workspace_size; 377 + 378 + workspace_size = ZSTD_DStreamWorkspaceBound(MAX_COMPRESS_WINDOW_SIZE); 379 + 380 + workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode), 381 + workspace_size, GFP_NOFS); 382 + if (!workspace) 383 + return -ENOMEM; 384 + 385 + stream = ZSTD_initDStream(MAX_COMPRESS_WINDOW_SIZE, 386 + workspace, workspace_size); 387 + if (!stream) { 388 + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initDStream failed\n", 389 + KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, 390 + __func__); 391 + kvfree(workspace); 392 + return -EIO; 393 + } 394 + 395 + dic->private = workspace; 396 + dic->private2 = stream; 397 + 398 + return 0; 399 + } 400 + 401 + static void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic) 402 + { 403 + kvfree(dic->private); 404 + dic->private = NULL; 405 + dic->private2 = NULL; 406 + } 407 + 408 + static int zstd_decompress_pages(struct decompress_io_ctx *dic) 409 + { 410 + ZSTD_DStream *stream = dic->private2; 411 + ZSTD_inBuffer inbuf; 412 + ZSTD_outBuffer outbuf; 413 + int ret; 414 + 415 + inbuf.pos = 0; 416 + inbuf.src = dic->cbuf->cdata; 417 + inbuf.size = dic->clen; 418 + 419 + outbuf.pos = 0; 420 + outbuf.dst = dic->rbuf; 421 + outbuf.size = dic->rlen; 422 + 423 + ret = ZSTD_decompressStream(stream, &outbuf, &inbuf); 424 + if (ZSTD_isError(ret)) { 425 + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n", 426 + KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, 427 + __func__, ZSTD_getErrorCode(ret)); 428 + return -EIO; 429 + } 430 + 431 + if (dic->rlen != outbuf.pos) { 432 + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, " 433 + "expected:%lu\n", KERN_ERR, 434 + F2FS_I_SB(dic->inode)->sb->s_id, 435 + __func__, dic->rlen, 436 + PAGE_SIZE << dic->log_cluster_size); 437 + return -EIO; 438 + } 439 + 440 + return 0; 441 + } 442 + 443 + static const struct f2fs_compress_ops f2fs_zstd_ops = { 444 + .init_compress_ctx = zstd_init_compress_ctx, 445 + .destroy_compress_ctx = zstd_destroy_compress_ctx, 446 + .compress_pages = zstd_compress_pages, 447 + .init_decompress_ctx = zstd_init_decompress_ctx, 448 + .destroy_decompress_ctx = zstd_destroy_decompress_ctx, 449 + .decompress_pages = zstd_decompress_pages, 450 + }; 451 + #endif 452 + 295 453 static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = { 296 454 #ifdef CONFIG_F2FS_FS_LZO 297 455 &f2fs_lzo_ops, ··· 459 299 #endif 460 300 #ifdef CONFIG_F2FS_FS_LZ4 461 301 &f2fs_lz4_ops, 302 + #else 303 + NULL, 304 + #endif 305 + #ifdef CONFIG_F2FS_FS_ZSTD 306 + &f2fs_zstd_ops, 462 307 #else 463 308 NULL, 464 309 #endif
+5
fs/f2fs/f2fs.h
··· 1267 1267 enum compress_algorithm_type { 1268 1268 COMPRESS_LZO, 1269 1269 COMPRESS_LZ4, 1270 + COMPRESS_ZSTD, 1270 1271 COMPRESS_MAX, 1271 1272 }; 1272 1273 ··· 1297 1296 size_t rlen; /* valid data length in rbuf */ 1298 1297 size_t clen; /* valid data length in cbuf */ 1299 1298 void *private; /* payload buffer for specified compression algorithm */ 1299 + void *private2; /* extra payload buffer */ 1300 1300 }; 1301 1301 1302 1302 /* compress context for write IO path */ ··· 1327 1325 size_t clen; /* valid data length in cbuf */ 1328 1326 refcount_t ref; /* referrence count of compressed page */ 1329 1327 bool failed; /* indicate IO error during decompression */ 1328 + void *private; /* payload buffer for specified decompression algorithm */ 1329 + void *private2; /* extra payload buffer */ 1330 1330 }; 1331 1331 1332 1332 #define NULL_CLUSTER ((unsigned int)(~0)) 1333 1333 #define MIN_COMPRESS_LOG_SIZE 2 1334 1334 #define MAX_COMPRESS_LOG_SIZE 8 1335 + #define MAX_COMPRESS_WINDOW_SIZE ((PAGE_SIZE) << MAX_COMPRESS_LOG_SIZE) 1335 1336 1336 1337 struct f2fs_sb_info { 1337 1338 struct super_block *sb; /* pointer to VFS super block */
+7
fs/f2fs/super.c
··· 829 829 !strcmp(name, "lz4")) { 830 830 F2FS_OPTION(sbi).compress_algorithm = 831 831 COMPRESS_LZ4; 832 + } else if (strlen(name) == 4 && 833 + !strcmp(name, "zstd")) { 834 + F2FS_OPTION(sbi).compress_algorithm = 835 + COMPRESS_ZSTD; 832 836 } else { 833 837 kfree(name); 834 838 return -EINVAL; ··· 1422 1418 break; 1423 1419 case COMPRESS_LZ4: 1424 1420 algtype = "lz4"; 1421 + break; 1422 + case COMPRESS_ZSTD: 1423 + algtype = "zstd"; 1425 1424 break; 1426 1425 } 1427 1426 seq_printf(seq, ",compress_algorithm=%s", algtype);
+2 -1
include/trace/events/f2fs.h
··· 153 153 #define show_compress_algorithm(type) \ 154 154 __print_symbolic(type, \ 155 155 { COMPRESS_LZO, "LZO" }, \ 156 - { COMPRESS_LZ4, "LZ4" }) 156 + { COMPRESS_LZ4, "LZ4" }, \ 157 + { COMPRESS_ZSTD, "ZSTD" }) 157 158 158 159 struct f2fs_sb_info; 159 160 struct f2fs_io_info;