Skip to content

Commit 225ecd1

Browse files
maharmstoneadam900710
authored andcommitted
btrfs-progs: mkfs: add zstd to --compress option
Allow --compress to work with zstd, when compiled in. Signed-off-by: Mark Harmstone <[email protected]>
1 parent 140b568 commit 225ecd1

File tree

3 files changed

+214
-3
lines changed

3 files changed

+214
-3
lines changed

Diff for: Documentation/mkfs.btrfs.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ OPTIONS
214214
215215
--compress <algo>[:<level>]
216216
Try to compress files when using *--rootdir*. Supported values for *algo* are
217-
*no* (the default) and *zlib*. The optional value *level* is a
218-
compression level, from 1 to 9 for ZLIB.
217+
*no* (the default), *zlib*, and *zstd*. The optional value *level* is a
218+
compression level, from 1 to 9 for ZLIB and from 1 to 15 for ZSTD.
219219

220220
As with the kernel, :command:`mkfs.btrfs` won't write compressed extents when
221221
they would be larger than the uncompressed versions, and will mark a file as

Diff for: mkfs/main.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ static const char * const mkfs_usage[] = {
443443
OPTLINE("-u|--subvol TYPE:SUBDIR", "create SUBDIR as subvolume rather than normal directory, can be specified multiple times"),
444444
OPTLINE("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
445445
OPTLINE("-K|--nodiscard", "do not perform whole device TRIM"),
446-
OPTLINE("--compress ALGO[:LEVEL]", "compression algorithm and level to use; ALGO can be no (default), zlib"),
446+
OPTLINE("--compress ALGO[:LEVEL]", "compression algorithm and level to use; ALGO can be no (default), zlib, zstd"),
447447
OPTLINE("-f|--force", "force overwrite of existing filesystem"),
448448
"General:",
449449
OPTLINE("-q|--quiet", "no messages except errors"),
@@ -1296,6 +1296,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
12961296

12971297
if (!strncmp(optarg, "zlib", type_size)) {
12981298
compression = BTRFS_COMPRESS_ZLIB;
1299+
} else if (!strncmp(optarg, "zstd", type_size)) {
1300+
compression = BTRFS_COMPRESS_ZSTD;
12991301
} else {
13001302
error("unrecognized compression type %s",
13011303
optarg);

Diff for: mkfs/rootdir.c

+209
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#include <limits.h>
2828
#include <stdlib.h>
2929
#include <string.h>
30+
#if COMPRESSION_ZSTD
31+
#include <zstd.h>
32+
#include <zstd_errors.h>
33+
#endif
3034
#include <zlib.h>
3135
#include "kernel-lib/sizes.h"
3236
#include "kernel-shared/accessors.h"
@@ -50,6 +54,9 @@
5054
#define ZLIB_BTRFS_DEFAULT_LEVEL 3
5155
#define ZLIB_BTRFS_MAX_LEVEL 9
5256

57+
#define ZSTD_BTRFS_DEFAULT_LEVEL 3
58+
#define ZSTD_BTRFS_MAX_LEVEL 15
59+
5360
static u32 fs_block_size;
5461

5562
/*
@@ -519,6 +526,97 @@ static ssize_t zlib_compress_extent(bool first_sector, u32 sectorsize,
519526
return -E2BIG;
520527
}
521528

529+
#if COMPRESSION_ZSTD
530+
/*
531+
* Returns the size of the compressed data if successful, -E2BIG if it is
532+
* incompressible, or an error code.
533+
*/
534+
static ssize_t zstd_compress_extent(bool first_sector, u32 sectorsize,
535+
const void *in_buf, size_t in_size,
536+
void *out_buf)
537+
{
538+
ZSTD_CCtx *zstd_ctx;
539+
ZSTD_inBuffer input;
540+
ZSTD_outBuffer output;
541+
size_t zstd_ret;
542+
ssize_t ret;
543+
544+
zstd_ctx = ZSTD_createCCtx();
545+
if (!zstd_ctx) {
546+
error_msg(ERROR_MSG_MEMORY, NULL);
547+
return -ENOMEM;
548+
}
549+
550+
zstd_ret = ZSTD_CCtx_setParameter(zstd_ctx, ZSTD_c_compressionLevel,
551+
g_compression_level);
552+
if (ZSTD_isError(zstd_ret)) {
553+
error("ZSTD_CCtx_setParameter failed: %s",
554+
ZSTD_getErrorName(zstd_ret));
555+
ret = -EINVAL;
556+
goto out;
557+
}
558+
559+
zstd_ret = ZSTD_CCtx_setPledgedSrcSize(zstd_ctx, in_size);
560+
if (ZSTD_isError(zstd_ret)) {
561+
error("ZSTD_CCtx_setPledgedSrcSize failed: %s",
562+
ZSTD_getErrorName(zstd_ret));
563+
ret = -EINVAL;
564+
goto out;
565+
}
566+
567+
output.dst = out_buf;
568+
output.size = BTRFS_MAX_COMPRESSED;
569+
output.pos = 0;
570+
571+
input.src = in_buf;
572+
input.pos = 0;
573+
574+
/*
575+
* Try to compress the first sector - if it would be larger, return
576+
* -E2BIG so that it gets marked as nocompress.
577+
*/
578+
if (first_sector) {
579+
input.size = sectorsize;
580+
581+
zstd_ret = ZSTD_compressStream2(zstd_ctx, &output, &input,
582+
ZSTD_e_flush);
583+
584+
if (ZSTD_isError(zstd_ret)) {
585+
error("ZSTD_compressStream2 failed: %s",
586+
ZSTD_getErrorName(zstd_ret));
587+
ret = -EINVAL;
588+
goto out;
589+
}
590+
591+
if (zstd_ret != 0 || output.pos > sectorsize) {
592+
ret = -E2BIG;
593+
goto out;
594+
}
595+
}
596+
597+
input.size = in_size;
598+
599+
zstd_ret = ZSTD_compressStream2(zstd_ctx, &output, &input, ZSTD_e_end);
600+
601+
if (ZSTD_isError(zstd_ret)) {
602+
error("ZSTD_compressStream2 failed: %s",
603+
ZSTD_getErrorName(zstd_ret));
604+
ret = -EINVAL;
605+
goto out;
606+
}
607+
608+
if (zstd_ret == 0 && output.pos <= in_size - sectorsize)
609+
ret = output.pos;
610+
else
611+
ret = -E2BIG;
612+
613+
out:
614+
ZSTD_freeCCtx(zstd_ctx);
615+
616+
return ret;
617+
}
618+
#endif
619+
522620
/*
523621
* keep our extent size at 1MB max, this makes it easier to work
524622
* inside the tiny block groups created during mkfs
@@ -586,6 +684,13 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
586684
source->buf, bytes_read,
587685
source->comp_buf);
588686
break;
687+
#if COMPRESSION_ZSTD
688+
case BTRFS_COMPRESS_ZSTD:
689+
comp_ret = zstd_compress_extent(first_sector, sectorsize,
690+
source->buf, bytes_read,
691+
source->comp_buf);
692+
break;
693+
#endif
589694
default:
590695
comp_ret = -EINVAL;
591696
break;
@@ -629,12 +734,21 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
629734
}
630735

631736
if (do_comp) {
737+
u64 features;
738+
632739
to_write = round_up(comp_ret, sectorsize);
633740
write_buf = source->comp_buf;
634741
memset(write_buf + comp_ret, 0, to_write - comp_ret);
635742

636743
flags |= BTRFS_INODE_COMPRESS;
637744
btrfs_set_stack_inode_flags(btrfs_inode, flags);
745+
746+
if (g_compression == BTRFS_COMPRESS_ZSTD) {
747+
features = btrfs_super_incompat_flags(trans->fs_info->super_copy);
748+
features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD;
749+
btrfs_set_super_incompat_flags(trans->fs_info->super_copy,
750+
features);
751+
}
638752
} else {
639753
to_write = round_up(to_read, sectorsize);
640754
write_buf = source->buf;
@@ -735,6 +849,84 @@ static ssize_t zlib_compress_inline_extent(char *buf, u64 size, char **comp_buf)
735849
return ret;
736850
}
737851

852+
#if COMPRESSION_ZSTD
853+
/*
854+
* Returns the size of the compressed data if successful, -E2BIG if it is
855+
* incompressible, or an error code.
856+
*/
857+
static ssize_t zstd_compress_inline_extent(char *buf, u64 size, char **comp_buf)
858+
{
859+
ZSTD_CCtx *zstd_ctx;
860+
ZSTD_inBuffer input;
861+
ZSTD_outBuffer output;
862+
size_t zstd_ret;
863+
ssize_t ret;
864+
char *out = NULL;
865+
866+
zstd_ctx = ZSTD_createCCtx();
867+
if (!zstd_ctx) {
868+
error_msg(ERROR_MSG_MEMORY, NULL);
869+
return -ENOMEM;
870+
}
871+
872+
zstd_ret = ZSTD_CCtx_setParameter(zstd_ctx, ZSTD_c_compressionLevel,
873+
g_compression_level);
874+
if (ZSTD_isError(zstd_ret)) {
875+
error("ZSTD_CCtx_setParameter failed: %s",
876+
ZSTD_getErrorName(zstd_ret));
877+
ret = -EINVAL;
878+
goto out;
879+
}
880+
881+
zstd_ret = ZSTD_CCtx_setPledgedSrcSize(zstd_ctx, size);
882+
if (ZSTD_isError(zstd_ret)) {
883+
error("ZSTD_CCtx_setPledgedSrcSize failed: %s",
884+
ZSTD_getErrorName(zstd_ret));
885+
ret = -EINVAL;
886+
goto out;
887+
}
888+
889+
out = malloc(size);
890+
if (!out) {
891+
error_msg(ERROR_MSG_MEMORY, NULL);
892+
ret = -ENOMEM;
893+
goto out;
894+
}
895+
896+
output.dst = out;
897+
output.size = size;
898+
output.pos = 0;
899+
900+
input.src = buf;
901+
input.pos = 0;
902+
input.size = size;
903+
904+
zstd_ret = ZSTD_compressStream2(zstd_ctx, &output, &input, ZSTD_e_end);
905+
906+
if (ZSTD_isError(zstd_ret)) {
907+
error("ZSTD_compressStream2 failed: %s",
908+
ZSTD_getErrorName(zstd_ret));
909+
ret = -EINVAL;
910+
goto out;
911+
}
912+
913+
if (zstd_ret == 0 && output.pos < size) {
914+
ret = output.pos;
915+
*comp_buf = out;
916+
} else {
917+
ret = -E2BIG;
918+
}
919+
920+
out:
921+
if (ret < 0)
922+
free(out);
923+
924+
ZSTD_freeCCtx(zstd_ctx);
925+
926+
return ret;
927+
}
928+
#endif
929+
738930
static int add_file_items(struct btrfs_trans_handle *trans,
739931
struct btrfs_root *root,
740932
struct btrfs_inode_item *btrfs_inode, u64 objectid,
@@ -780,6 +972,12 @@ static int add_file_items(struct btrfs_trans_handle *trans,
780972
ret = zlib_compress_inline_extent(buffer, st->st_size,
781973
&comp_buf);
782974
break;
975+
#if COMPRESSION_ZSTD
976+
case BTRFS_COMPRESS_ZSTD:
977+
ret = zstd_compress_inline_extent(buffer, st->st_size,
978+
&comp_buf);
979+
break;
980+
#endif
783981
default:
784982
ret = -E2BIG;
785983
break;
@@ -1260,6 +1458,17 @@ int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir
12601458
else if (compression_level == 0)
12611459
compression_level = ZLIB_BTRFS_DEFAULT_LEVEL;
12621460
break;
1461+
case BTRFS_COMPRESS_ZSTD:
1462+
#if !COMPRESSION_ZSTD
1463+
error("zstd support not compiled in");
1464+
return -EINVAL;
1465+
#else
1466+
if (compression_level > ZSTD_BTRFS_MAX_LEVEL)
1467+
compression_level = ZSTD_BTRFS_MAX_LEVEL;
1468+
else if (compression_level == 0)
1469+
compression_level = ZSTD_BTRFS_DEFAULT_LEVEL;
1470+
break;
1471+
#endif
12631472
default:
12641473
error("unsupported compression type");
12651474
return -EINVAL;

0 commit comments

Comments
 (0)