btrfs-progs: Add zstd support

Adds zstd support to the btrfs program. An optional dependency on libzstd
>= 1.0.0 is added. Autoconf accepts `--enable-zstd' or `--disable-zstd' and
defaults to detecting if libzstd is present using `pkg-config'.

The patch is also available in my fork of btrfs-progs [1], which passes
Travis-CI with the new tests. The prebuilt binary is available there.

I haven't updated Android.mk.

[1] https://github.com/terrelln/btrfs-progs/tree/devel

Signed-off-by: Nick Terrell <terrelln@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Nick Terrell 2017-09-08 13:29:23 -07:00 committed by David Sterba
parent 86529862e1
commit 717a8b1e5d
13 changed files with 112 additions and 36 deletions

View File

@ -112,7 +112,7 @@ KiB, MiB, GiB, TiB, PiB, or EiB, respectively (case does not matter).
be verbose, print file names as they're submitted for defragmentation
-c[<algo>]::::
compress file contents while defragmenting. Optional argument selects the compression
algorithm, 'zlib' (default) or 'lzo'. Currently it's not possible to select no
algorithm, 'zlib' (default), 'lzo' or 'zstd'. Currently it's not possible to select no
compression. See also section 'EXAMPLES'.
-r::::
defragment files recursively in given directories

View File

@ -118,7 +118,7 @@ but a warning is printed if it's more than 300 seconds (5 minutes).
(default: off)
+
Control BTRFS file data compression. Type may be specified as 'zlib',
'lzo' or 'no' (for no compression, used for remounting). If no type
'lzo', 'zstd' or 'no' (for no compression, used for remounting). If no type
is specified, 'zlib' is used. If 'compress-force' is specified,
the compression will allways be attempted, but the data may end up uncompressed
if the compression would make them larger.
@ -472,6 +472,12 @@ page size
the 'lzo' compression has been used on the filesystem, either as a mount option
or via *btrfs filesystem defrag*.
*compress_zstd*::
(since: 4.14)
+
the 'zstd' compression has been used on the filesystem, either as a mount option
or via *btrfs filesystem defrag*.
*default_subvol*::
(since: 2.6.34)
+

View File

@ -43,7 +43,7 @@ read-only flag of subvolume: true or false
label::::
label of device
compression::::
compression setting for an inode: lzo, zlib, or "" (empty string)
compression setting for an inode: lzo, zlib, zstd, or "" (empty string)
*list* [-t <type>] <object>::
Lists available properties with their descriptions for the given object.

View File

@ -7,6 +7,7 @@ The Btrfs utility programs require the following libraries/tools to build:
- libblkid - block device id library
- liblzo2 - LZO data compression library
- zlib - ZLIB data compression library
- libzstd - ZSTD data compression library version >= 1.0.0 (optional)
For the btrfs-convert utility:

View File

@ -209,6 +209,7 @@ btrfs_fragments_libs = -lgd -lpng -ljpeg -lfreetype
btrfs_debug_tree_objects = cmds-inspect-dump-tree.o
btrfs_show_super_objects = cmds-inspect-dump-super.o
btrfs_calc_size_objects = cmds-inspect-tree-stats.o
cmds_restore_cflags = -DBTRFSRESTORE_ZSTD=$(BTRFSRESTORE_ZSTD)
# collect values of the variables above
standalone_deps = $(foreach dep,$(patsubst %,%_objects,$(subst -,_,$(filter btrfs-%, $(progs)))),$($(dep)))

View File

@ -13,14 +13,15 @@ DISABLE_DOCUMENTATION = @DISABLE_DOCUMENTATION@
DISABLE_BTRFSCONVERT = @DISABLE_BTRFSCONVERT@
BTRFSCONVERT_EXT2 = @BTRFSCONVERT_EXT2@
BTRFSCONVERT_REISERFS = @BTRFSCONVERT_REISERFS@
BTRFSRESTORE_ZSTD = @BTRFSRESTORE_ZSTD@
SUBST_CFLAGS = @CFLAGS@
SUBST_LDFLAGS = @LDFLAGS@
LIBS_BASE = @UUID_LIBS@ @BLKID_LIBS@ -L. -pthread
LIBS_COMP = @ZLIB_LIBS@ @LZO2_LIBS@
LIBS_COMP = @ZLIB_LIBS@ @LZO2_LIBS@ @ZSTD_LIBS@
STATIC_LIBS_BASE = @UUID_LIBS_STATIC@ @BLKID_LIBS_STATIC@ -L. -pthread
STATIC_LIBS_COMP = @ZLIB_LIBS_STATIC@ @LZO2_LIBS_STATIC@
STATIC_LIBS_COMP = @ZLIB_LIBS_STATIC@ @LZO2_LIBS_STATIC@ @ZSTD_LIBS_STATIC@
prefix ?= @prefix@
exec_prefix = @exec_prefix@

View File

@ -952,6 +952,8 @@ static int parse_compress_type(char *s)
return BTRFS_COMPRESS_ZLIB;
else if (strcmp(optarg, "lzo") == 0)
return BTRFS_COMPRESS_LZO;
else if (strcmp(optarg, "zstd") == 0)
return BTRFS_COMPRESS_ZSTD;
else {
error("unknown compression type %s", s);
exit(1);
@ -962,13 +964,13 @@ static const char * const cmd_filesystem_defrag_usage[] = {
"btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
"Defragment a file or a directory",
"",
"-v be verbose",
"-r defragment files recursively",
"-c[zlib,lzo] compress the file while defragmenting",
"-f flush data to disk immediately after defragmenting",
"-s start defragment only from byte onward",
"-l len defragment only up to len bytes",
"-t size target extent size hint (default: 32M)",
"-v be verbose",
"-r defragment files recursively",
"-c[zlib,lzo,zstd] compress the file while defragmenting",
"-f flush data to disk immediately after defragmenting",
"-s start defragment only from byte onward",
"-l len defragment only up to len bytes",
"-t size target extent size hint (default: 32M)",
NULL
};

View File

@ -223,7 +223,7 @@ static struct readable_flag_entry incompat_flags_array[] = {
DEF_INCOMPAT_FLAG_ENTRY(DEFAULT_SUBVOL),
DEF_INCOMPAT_FLAG_ENTRY(MIXED_GROUPS),
DEF_INCOMPAT_FLAG_ENTRY(COMPRESS_LZO),
DEF_INCOMPAT_FLAG_ENTRY(COMPRESS_LZOv2),
DEF_INCOMPAT_FLAG_ENTRY(COMPRESS_ZSTD),
DEF_INCOMPAT_FLAG_ENTRY(BIG_METADATA),
DEF_INCOMPAT_FLAG_ENTRY(EXTENDED_IREF),
DEF_INCOMPAT_FLAG_ENTRY(RAID56),

View File

@ -29,6 +29,9 @@
#include <lzo/lzoconf.h>
#include <lzo/lzo1x.h>
#include <zlib.h>
#if BTRFSRESTORE_ZSTD
#include <zstd.h>
#endif
#include <regex.h>
#include <getopt.h>
#include <sys/types.h>
@ -156,6 +159,50 @@ static int decompress_lzo(struct btrfs_root *root, unsigned char *inbuf,
return 0;
}
static int decompress_zstd(const char *inbuf, char *outbuf, u64 compress_len,
u64 decompress_len)
{
#if !BTRFSRESTORE_ZSTD
error("btrfs not compiled with zstd support");
return -1;
#else
ZSTD_DStream *strm;
size_t zret;
int ret = 0;
ZSTD_inBuffer in = {inbuf, compress_len, 0};
ZSTD_outBuffer out = {outbuf, decompress_len, 0};
strm = ZSTD_createDStream();
if (!strm) {
error("zstd create failed");
return -1;
}
zret = ZSTD_initDStream(strm);
if (ZSTD_isError(zret)) {
error("zstd init failed: %s", ZSTD_getErrorName(zret));
ret = -1;
goto out;
}
zret = ZSTD_decompressStream(strm, &out, &in);
if (ZSTD_isError(zret)) {
error("zstd decompress failed %s\n", ZSTD_getErrorName(zret));
ret = -1;
goto out;
}
if (zret != 0) {
error("zstd frame incomplete");
ret = -1;
goto out;
}
out:
ZSTD_freeDStream(strm);
return ret;
#endif
}
static int decompress(struct btrfs_root *root, char *inbuf, char *outbuf,
u64 compress_len, u64 *decompress_len, int compress)
{
@ -166,6 +213,9 @@ static int decompress(struct btrfs_root *root, char *inbuf, char *outbuf,
case BTRFS_COMPRESS_LZO:
return decompress_lzo(root, (unsigned char *)inbuf, outbuf,
compress_len, decompress_len);
case BTRFS_COMPRESS_ZSTD:
return decompress_zstd(inbuf, outbuf, compress_len,
*decompress_len);
default:
break;
}

View File

@ -182,6 +182,23 @@ PKG_STATIC(UUID_LIBS_STATIC, [uuid])
PKG_CHECK_MODULES(ZLIB, [zlib])
PKG_STATIC(ZLIB_LIBS_STATIC, [zlib])
AC_ARG_ENABLE([zstd],
AS_HELP_STRING([--enable-zstd@<:@=auto@:>@], [build with zstd support (default: auto)]),
[], [enable_zstd=auto]
)
if test "x$enable_zstd" = xauto; then
PKG_CHECK_EXISTS([libzstd >= 1.0.0], [enable_zstd=yes], [enable_zstd=no])
fi
if test "x$enable_zstd" = xyes; then
PKG_CHECK_MODULES(ZSTD, [libzstd >= 1.0.0])
PKG_STATIC(ZSTD_LIBS_STATIC, [libzstd])
fi
AS_IF([test "x$enable_zstd" = xyes], [BTRFSRESTORE_ZSTD=1], [BTRFSRESTORE_ZSTD=0])
AC_SUBST(BTRFSRESTORE_ZSTD)
# udev v190 introduced the btrfs builtin and a udev rule to use it.
# Our udev rule gives us the friendly dm names but isn't required (or valid)
# on earlier releases.
@ -221,21 +238,21 @@ AC_OUTPUT
AC_MSG_RESULT([
${PACKAGE_NAME} ${PACKAGE_VERSION}
prefix: ${prefix}
exec prefix: ${exec_prefix}
prefix: ${prefix}
exec prefix: ${exec_prefix}
bindir: ${bindir}
libdir: ${libdir}
includedir: ${includedir}
bindir: ${bindir}
libdir: ${libdir}
includedir: ${includedir}
compiler: ${CC}
cflags: ${CFLAGS}
ldflags: ${LDFLAGS}
compiler: ${CC}
cflags: ${CFLAGS}
ldflags: ${LDFLAGS}
documentation: ${enable_documentation}
backtrace support: ${enable_backtrace}
btrfs-convert: ${enable_convert} ${convertfs:+($convertfs)}
documentation: ${enable_documentation}
backtrace support: ${enable_backtrace}
btrfs-convert: ${enable_convert} ${convertfs:+($convertfs)}
btrfs-restore zstd: ${enable_zstd}
Type 'make' to compile.
])

15
ctree.h
View File

@ -484,14 +484,7 @@ struct btrfs_super_block {
#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1)
#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2)
#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3)
/*
* some patches floated around with a second compression method
* lets save that incompat here for when they do get in
* Note we don't actually support it, we're just reserving the
* number
*/
#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2 (1ULL << 4)
#define BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD (1ULL << 4)
/*
* older kernels tried to do bigger metadata blocks, but the
@ -516,6 +509,7 @@ struct btrfs_super_block {
(BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD | \
BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \
BTRFS_FEATURE_INCOMPAT_RAID56 | \
@ -677,8 +671,9 @@ typedef enum {
BTRFS_COMPRESS_NONE = 0,
BTRFS_COMPRESS_ZLIB = 1,
BTRFS_COMPRESS_LZO = 2,
BTRFS_COMPRESS_TYPES = 2,
BTRFS_COMPRESS_LAST = 3,
BTRFS_COMPRESS_ZSTD = 3,
BTRFS_COMPRESS_TYPES = 3,
BTRFS_COMPRESS_LAST = 4,
} btrfs_compression_type;
/* we don't understand any encryption methods right now */

View File

@ -31,7 +31,7 @@
(BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF \
| BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL \
| BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO \
| BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2 \
| BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD \
| BTRFS_FEATURE_INCOMPAT_BIG_METADATA \
| BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF \
| BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA \

View File

@ -323,6 +323,9 @@ static void compress_type_to_str(u8 compress_type, char *ret)
case BTRFS_COMPRESS_LZO:
strcpy(ret, "lzo");
break;
case BTRFS_COMPRESS_ZSTD:
strcpy(ret, "zstd");
break;
default:
sprintf(ret, "UNKNOWN.%d", compress_type);
}