mirror of
https://github.com/kdave/btrfs-progs
synced 2025-05-01 15:37:56 +00:00
btrfs-progs: mkfs: add --compress option
Add an option --compress to mkfs.btrfs, to allow creating files using zlib when using --rootdir. Signed-off-by: Mark Harmstone <maharmstone@fb.com>
This commit is contained in:
parent
0966aa21b3
commit
0134e755c1
@ -212,6 +212,15 @@ OPTIONS
|
|||||||
|
|
||||||
$ mkfs.btrfs -O list-all
|
$ mkfs.btrfs -O list-all
|
||||||
|
|
||||||
|
--compress <algo>[:<level>]
|
||||||
|
Try to compress files when using *--rootdir*. Supported values for *algo* are
|
||||||
|
*no* (the default) and *zlib*. The optional value *level* is a
|
||||||
|
compression level, from 1 to 9 for ZLIB.
|
||||||
|
|
||||||
|
As with the kernel, :command:`mkfs.btrfs` won't write compressed extents when
|
||||||
|
they would be larger than the uncompressed versions, and will mark a file as
|
||||||
|
`nocompress` if its beginning is found to be incompressible.
|
||||||
|
|
||||||
-f|--force
|
-f|--force
|
||||||
Forcibly overwrite the block devices when an existing filesystem is detected.
|
Forcibly overwrite the block devices when an existing filesystem is detected.
|
||||||
By default, :command:`mkfs.btrfs` will utilize *libblkid* to check for any known
|
By default, :command:`mkfs.btrfs` will utilize *libblkid* to check for any known
|
||||||
|
4
Makefile
4
Makefile
@ -740,11 +740,11 @@ btrfsck.static: btrfs.static
|
|||||||
|
|
||||||
mkfs.btrfs: $(mkfs_objects) $(objects) libbtrfsutil.a
|
mkfs.btrfs: $(mkfs_objects) $(objects) libbtrfsutil.a
|
||||||
@echo " [LD] $@"
|
@echo " [LD] $@"
|
||||||
$(Q)$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
|
$(Q)$(CC) -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_COMP)
|
||||||
|
|
||||||
mkfs.btrfs.static: $(static_mkfs_objects) $(static_objects) $(static_libbtrfs_objects)
|
mkfs.btrfs.static: $(static_mkfs_objects) $(static_objects) $(static_libbtrfs_objects)
|
||||||
@echo " [LD] $@"
|
@echo " [LD] $@"
|
||||||
$(Q)$(CC) -o $@ $^ $(STATIC_LDFLAGS) $(STATIC_LIBS)
|
$(Q)$(CC) -o $@ $^ $(STATIC_LDFLAGS) $(STATIC_LIBS) $(STATIC_LIBS_COMP)
|
||||||
|
|
||||||
btrfstune: $(tune_objects) $(objects) libbtrfsutil.a
|
btrfstune: $(tune_objects) $(objects) libbtrfsutil.a
|
||||||
@echo " [LD] $@"
|
@echo " [LD] $@"
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "kernel-shared/uapi/btrfs_tree.h"
|
#include "kernel-shared/uapi/btrfs_tree.h"
|
||||||
#include "kernel-shared/ctree.h"
|
#include "kernel-shared/ctree.h"
|
||||||
#include "kernel-shared/disk-io.h"
|
#include "kernel-shared/disk-io.h"
|
||||||
|
#include "kernel-shared/free-space-tree.h"
|
||||||
#include "kernel-shared/transaction.h"
|
#include "kernel-shared/transaction.h"
|
||||||
#include "common/extent-tree-utils.h"
|
#include "common/extent-tree-utils.h"
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "kerncompat.h"
|
#include "kerncompat.h"
|
||||||
#include "kernel-lib/bitops.h"
|
#include "kernel-lib/bitops.h"
|
||||||
|
#include "kernel-shared/compression.h"
|
||||||
|
|
||||||
struct btrfs_inode_item;
|
struct btrfs_inode_item;
|
||||||
struct btrfs_path;
|
struct btrfs_path;
|
||||||
|
@ -457,7 +457,9 @@ static int ext2_create_file_extents(struct btrfs_trans_handle *trans,
|
|||||||
if (num_bytes > inode_size)
|
if (num_bytes > inode_size)
|
||||||
num_bytes = inode_size;
|
num_bytes = inode_size;
|
||||||
ret = btrfs_insert_inline_extent(trans, root, objectid,
|
ret = btrfs_insert_inline_extent(trans, root, objectid,
|
||||||
0, buffer, num_bytes);
|
0, buffer, num_bytes,
|
||||||
|
BTRFS_COMPRESS_NONE,
|
||||||
|
num_bytes);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
nbytes = btrfs_stack_inode_nbytes(btrfs_inode) + num_bytes;
|
nbytes = btrfs_stack_inode_nbytes(btrfs_inode) + num_bytes;
|
||||||
@ -506,7 +508,8 @@ static int ext2_create_symlink(struct btrfs_trans_handle *trans,
|
|||||||
pathname = (char *)&(ext2_inode->i_block[0]);
|
pathname = (char *)&(ext2_inode->i_block[0]);
|
||||||
BUG_ON(pathname[inode_size] != 0);
|
BUG_ON(pathname[inode_size] != 0);
|
||||||
ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
|
ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
|
||||||
pathname, inode_size);
|
pathname, inode_size,
|
||||||
|
BTRFS_COMPRESS_NONE, inode_size);
|
||||||
btrfs_set_stack_inode_nbytes(btrfs_inode, inode_size);
|
btrfs_set_stack_inode_nbytes(btrfs_inode, inode_size);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +384,8 @@ static int reiserfs_convert_tail(struct btrfs_trans_handle *trans,
|
|||||||
length, offset, convert_flags);
|
length, offset, convert_flags);
|
||||||
|
|
||||||
ret = btrfs_insert_inline_extent(trans, root, objectid,
|
ret = btrfs_insert_inline_extent(trans, root, objectid,
|
||||||
offset, body, length);
|
offset, body, length,
|
||||||
|
BTRFS_COMPRESS_NONE, length);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -544,7 +545,8 @@ static int reiserfs_copy_symlink(struct btrfs_trans_handle *trans,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
|
ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
|
||||||
symlink, len);
|
symlink, len, BTRFS_COMPRESS_NONE,
|
||||||
|
len);
|
||||||
btrfs_set_stack_inode_nbytes(btrfs_inode, len);
|
btrfs_set_stack_inode_nbytes(btrfs_inode, len);
|
||||||
fail:
|
fail:
|
||||||
pathrelse(&path);
|
pathrelse(&path);
|
||||||
|
@ -63,7 +63,9 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
|
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, u64 objectid,
|
struct btrfs_root *root, u64 objectid,
|
||||||
u64 offset, const char *buffer, size_t size)
|
u64 offset, const char *buffer, size_t size,
|
||||||
|
enum btrfs_compression_type comp,
|
||||||
|
u64 ram_bytes)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
@ -99,8 +101,8 @@ int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
|
|||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
btrfs_set_file_extent_generation(leaf, ei, trans->transid);
|
btrfs_set_file_extent_generation(leaf, ei, trans->transid);
|
||||||
btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
|
btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
|
||||||
btrfs_set_file_extent_ram_bytes(leaf, ei, size);
|
btrfs_set_file_extent_ram_bytes(leaf, ei, ram_bytes);
|
||||||
btrfs_set_file_extent_compression(leaf, ei, 0);
|
btrfs_set_file_extent_compression(leaf, ei, comp);
|
||||||
btrfs_set_file_extent_encryption(leaf, ei, 0);
|
btrfs_set_file_extent_encryption(leaf, ei, 0);
|
||||||
btrfs_set_file_extent_other_encoding(leaf, ei, 0);
|
btrfs_set_file_extent_other_encoding(leaf, ei, 0);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "kernel-shared/ctree.h"
|
#include "kernel-shared/ctree.h"
|
||||||
#include "kernel-shared/uapi/btrfs_tree.h"
|
#include "kernel-shared/uapi/btrfs_tree.h"
|
||||||
#include "kernel-shared/accessors.h"
|
#include "kernel-shared/accessors.h"
|
||||||
|
#include "kernel-shared/compression.h"
|
||||||
|
|
||||||
struct bio;
|
struct bio;
|
||||||
struct inode;
|
struct inode;
|
||||||
@ -91,7 +92,8 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 logical,
|
|||||||
u64 csum_objectid, u32 csum_type, const char *data);
|
u64 csum_objectid, u32 csum_type, const char *data);
|
||||||
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
|
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, u64 objectid,
|
struct btrfs_root *root, u64 objectid,
|
||||||
u64 offset, const char *buffer, size_t size);
|
u64 offset, const char *buffer, size_t size,
|
||||||
|
enum btrfs_compression_type comp, u64 ram_bytes);
|
||||||
/*
|
/*
|
||||||
* For symlink we allow up to PATH_MAX - 1 (PATH_MAX includes the terminating NUL,
|
* For symlink we allow up to PATH_MAX - 1 (PATH_MAX includes the terminating NUL,
|
||||||
* but fs doesn't store that terminating NUL).
|
* but fs doesn't store that terminating NUL).
|
||||||
|
41
mkfs/main.c
41
mkfs/main.c
@ -443,6 +443,7 @@ static const char * const mkfs_usage[] = {
|
|||||||
OPTLINE("-u|--subvol TYPE:SUBDIR", "create SUBDIR as subvolume rather than normal directory, can be specified multiple times"),
|
OPTLINE("-u|--subvol TYPE:SUBDIR", "create SUBDIR as subvolume rather than normal directory, can be specified multiple times"),
|
||||||
OPTLINE("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
|
OPTLINE("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
|
||||||
OPTLINE("-K|--nodiscard", "do not perform whole device TRIM"),
|
OPTLINE("-K|--nodiscard", "do not perform whole device TRIM"),
|
||||||
|
OPTLINE("--compress ALGO[:LEVEL]", "compression algorithm and level to use; ALGO can be no (default), zlib"),
|
||||||
OPTLINE("-f|--force", "force overwrite of existing filesystem"),
|
OPTLINE("-f|--force", "force overwrite of existing filesystem"),
|
||||||
"General:",
|
"General:",
|
||||||
OPTLINE("-q|--quiet", "no messages except errors"),
|
OPTLINE("-q|--quiet", "no messages except errors"),
|
||||||
@ -1058,6 +1059,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
|
|||||||
char *source_dir = NULL;
|
char *source_dir = NULL;
|
||||||
struct rootdir_subvol *rds;
|
struct rootdir_subvol *rds;
|
||||||
bool has_default_subvol = false;
|
bool has_default_subvol = false;
|
||||||
|
enum btrfs_compression_type compression = BTRFS_COMPRESS_NONE;
|
||||||
|
u64 compression_level = 0;
|
||||||
LIST_HEAD(subvols);
|
LIST_HEAD(subvols);
|
||||||
|
|
||||||
cpu_detect_flags();
|
cpu_detect_flags();
|
||||||
@ -1072,6 +1075,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
|
|||||||
GETOPT_VAL_CHECKSUM,
|
GETOPT_VAL_CHECKSUM,
|
||||||
GETOPT_VAL_GLOBAL_ROOTS,
|
GETOPT_VAL_GLOBAL_ROOTS,
|
||||||
GETOPT_VAL_DEVICE_UUID,
|
GETOPT_VAL_DEVICE_UUID,
|
||||||
|
GETOPT_VAL_COMPRESS,
|
||||||
};
|
};
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
{ "byte-count", required_argument, NULL, 'b' },
|
{ "byte-count", required_argument, NULL, 'b' },
|
||||||
@ -1099,6 +1103,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
|
|||||||
{ "quiet", 0, NULL, 'q' },
|
{ "quiet", 0, NULL, 'q' },
|
||||||
{ "verbose", 0, NULL, 'v' },
|
{ "verbose", 0, NULL, 'v' },
|
||||||
{ "shrink", no_argument, NULL, GETOPT_VAL_SHRINK },
|
{ "shrink", no_argument, NULL, GETOPT_VAL_SHRINK },
|
||||||
|
{ "compress", required_argument, NULL,
|
||||||
|
GETOPT_VAL_COMPRESS },
|
||||||
#if EXPERIMENTAL
|
#if EXPERIMENTAL
|
||||||
{ "param", required_argument, NULL, GETOPT_VAL_PARAM },
|
{ "param", required_argument, NULL, GETOPT_VAL_PARAM },
|
||||||
{ "num-global-roots", required_argument, NULL, GETOPT_VAL_GLOBAL_ROOTS },
|
{ "num-global-roots", required_argument, NULL, GETOPT_VAL_GLOBAL_ROOTS },
|
||||||
@ -1272,6 +1278,38 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
|
|||||||
case 'q':
|
case 'q':
|
||||||
bconf_be_quiet();
|
bconf_be_quiet();
|
||||||
break;
|
break;
|
||||||
|
case GETOPT_VAL_COMPRESS: {
|
||||||
|
char *colon;
|
||||||
|
size_t type_size;
|
||||||
|
|
||||||
|
if (!strcmp(optarg, "no")) {
|
||||||
|
compression = BTRFS_COMPRESS_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
colon = strstr(optarg, ":");
|
||||||
|
|
||||||
|
if (colon)
|
||||||
|
type_size = colon - optarg;
|
||||||
|
else
|
||||||
|
type_size = strlen(optarg);
|
||||||
|
|
||||||
|
if (!strncmp(optarg, "zlib", type_size)) {
|
||||||
|
compression = BTRFS_COMPRESS_ZLIB;
|
||||||
|
} else {
|
||||||
|
error("unrecognized compression type %s",
|
||||||
|
optarg);
|
||||||
|
ret = 1;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colon)
|
||||||
|
compression_level = arg_strtou64(colon + 1);
|
||||||
|
else
|
||||||
|
compression_level = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GETOPT_VAL_DEVICE_UUID:
|
case GETOPT_VAL_DEVICE_UUID:
|
||||||
strncpy_null(dev_uuid, optarg, BTRFS_UUID_UNPARSED_SIZE);
|
strncpy_null(dev_uuid, optarg, BTRFS_UUID_UNPARSED_SIZE);
|
||||||
break;
|
break;
|
||||||
@ -1953,7 +1991,8 @@ raid_groups:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_mkfs_fill_dir(trans, source_dir, root,
|
ret = btrfs_mkfs_fill_dir(trans, source_dir, root,
|
||||||
&subvols);
|
&subvols, compression,
|
||||||
|
compression_level);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error("error while filling filesystem: %d", ret);
|
error("error while filling filesystem: %d", ret);
|
||||||
btrfs_abort_transaction(trans, ret);
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
280
mkfs/rootdir.c
280
mkfs/rootdir.c
@ -27,6 +27,7 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <zlib.h>
|
||||||
#include "kernel-lib/sizes.h"
|
#include "kernel-lib/sizes.h"
|
||||||
#include "kernel-shared/accessors.h"
|
#include "kernel-shared/accessors.h"
|
||||||
#include "kernel-shared/uapi/btrfs_tree.h"
|
#include "kernel-shared/uapi/btrfs_tree.h"
|
||||||
@ -46,6 +47,9 @@
|
|||||||
#include "common/rbtree-utils.h"
|
#include "common/rbtree-utils.h"
|
||||||
#include "mkfs/rootdir.h"
|
#include "mkfs/rootdir.h"
|
||||||
|
|
||||||
|
#define ZLIB_BTRFS_DEFAULT_LEVEL 3
|
||||||
|
#define ZLIB_BTRFS_MAX_LEVEL 9
|
||||||
|
|
||||||
static u32 fs_block_size;
|
static u32 fs_block_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -145,6 +149,8 @@ static struct btrfs_trans_handle *g_trans = NULL;
|
|||||||
static struct list_head *g_subvols;
|
static struct list_head *g_subvols;
|
||||||
static u64 next_subvol_id = BTRFS_FIRST_FREE_OBJECTID;
|
static u64 next_subvol_id = BTRFS_FIRST_FREE_OBJECTID;
|
||||||
static u64 default_subvol_id;
|
static u64 default_subvol_id;
|
||||||
|
static enum btrfs_compression_type g_compression;
|
||||||
|
static u64 g_compression_level;
|
||||||
|
|
||||||
static inline struct inode_entry *rootdir_path_last(struct rootdir_path *path)
|
static inline struct inode_entry *rootdir_path_last(struct rootdir_path *path)
|
||||||
{
|
{
|
||||||
@ -352,7 +358,8 @@ static int add_symbolic_link(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
buf[ret] = '\0'; /* readlink does not do it for us */
|
buf[ret] = '\0'; /* readlink does not do it for us */
|
||||||
nbytes = ret + 1;
|
nbytes = ret + 1;
|
||||||
ret = btrfs_insert_inline_extent(trans, root, objectid, 0, buf, nbytes);
|
ret = btrfs_insert_inline_extent(trans, root, objectid, 0, buf, nbytes,
|
||||||
|
BTRFS_COMPRESS_NONE, nbytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
errno = -ret;
|
errno = -ret;
|
||||||
error("failed to insert inline extent for %s: %m", path_name);
|
error("failed to insert inline extent for %s: %m", path_name);
|
||||||
@ -404,7 +411,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
ins_key.objectid = disk_bytenr;
|
ins_key.objectid = disk_bytenr;
|
||||||
ins_key.type = BTRFS_EXTENT_ITEM_KEY;
|
ins_key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||||
ins_key.offset = num_bytes;
|
ins_key.offset = disk_num_bytes;
|
||||||
|
|
||||||
/* Update extent tree. */
|
/* Update extent tree. */
|
||||||
ret = btrfs_insert_empty_item(trans, extent_root, path,
|
ret = btrfs_insert_empty_item(trans, extent_root, path,
|
||||||
@ -421,7 +428,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
|
|||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
|
||||||
ret = btrfs_update_block_group(trans, disk_bytenr,
|
ret = btrfs_update_block_group(trans, disk_bytenr,
|
||||||
num_bytes, 1, 0);
|
disk_num_bytes, 1, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (ret != -EEXIST) {
|
} else if (ret != -EEXIST) {
|
||||||
@ -429,22 +436,19 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
ret = remove_from_free_space_tree(trans, disk_bytenr, num_bytes);
|
ret = remove_from_free_space_tree(trans, disk_bytenr, disk_num_bytes);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
btrfs_run_delayed_refs(trans, -1);
|
btrfs_run_delayed_refs(trans, -1);
|
||||||
|
|
||||||
ins_key.objectid = ino;
|
|
||||||
ins_key.type = BTRFS_EXTENT_DATA_KEY;
|
|
||||||
ins_key.offset = file_pos;
|
|
||||||
ret = btrfs_insert_file_extent(trans, root, ino, file_pos, stack_fi);
|
ret = btrfs_insert_file_extent(trans, root, ino, file_pos, stack_fi);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
btrfs_set_stack_inode_nbytes(inode,
|
btrfs_set_stack_inode_nbytes(inode,
|
||||||
btrfs_stack_inode_nbytes(inode) + num_bytes);
|
btrfs_stack_inode_nbytes(inode) + num_bytes);
|
||||||
|
|
||||||
ret = btrfs_inc_extent_ref(trans, disk_bytenr, num_bytes,
|
ret = btrfs_inc_extent_ref(trans, disk_bytenr, disk_num_bytes,
|
||||||
0, root->root_key.objectid, ino,
|
0, root->root_key.objectid, ino,
|
||||||
file_pos);
|
file_pos);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -455,6 +459,66 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the size of the compressed data if successful, -E2BIG if it is
|
||||||
|
* incompressible, or an error code.
|
||||||
|
*/
|
||||||
|
static ssize_t zlib_compress_extent(bool first_sector, u32 sectorsize,
|
||||||
|
const void *in_buf, size_t in_size,
|
||||||
|
void *out_buf)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
z_stream strm;
|
||||||
|
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
ret = deflateInit(&strm, g_compression_level);
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
error("deflateInit failed: %s", strm.msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strm.next_out = out_buf;
|
||||||
|
strm.avail_out = BTRFS_MAX_COMPRESSED;
|
||||||
|
strm.next_in = (void *)in_buf;
|
||||||
|
strm.avail_in = in_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to compress the first sector - if it would be larger,
|
||||||
|
* return -E2BIG.
|
||||||
|
*/
|
||||||
|
if (first_sector) {
|
||||||
|
strm.avail_in = sectorsize;
|
||||||
|
|
||||||
|
ret = deflate(&strm, Z_SYNC_FLUSH);
|
||||||
|
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
error("deflate failed: %s", strm.msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strm.avail_out < BTRFS_MAX_COMPRESSED - sectorsize)
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
strm.avail_in += in_size - sectorsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = deflate(&strm, Z_FINISH);
|
||||||
|
|
||||||
|
if (ret == Z_OK) {
|
||||||
|
return -E2BIG;
|
||||||
|
} else if (ret != Z_STREAM_END) {
|
||||||
|
error("deflate failed: %s", strm.msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_buf + BTRFS_MAX_COMPRESSED - (void *)strm.next_out > sectorsize)
|
||||||
|
return (void *)strm.next_out - out_buf;
|
||||||
|
|
||||||
|
return -E2BIG;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* keep our extent size at 1MB max, this makes it easier to work
|
* keep our extent size at 1MB max, this makes it easier to work
|
||||||
* inside the tiny block groups created during mkfs
|
* inside the tiny block groups created during mkfs
|
||||||
@ -466,6 +530,7 @@ struct source_descriptor {
|
|||||||
char *buf;
|
char *buf;
|
||||||
u64 size;
|
u64 size;
|
||||||
const char *path_name;
|
const char *path_name;
|
||||||
|
char *comp_buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int add_file_item_extent(struct btrfs_trans_handle *trans,
|
static int add_file_item_extent(struct btrfs_trans_handle *trans,
|
||||||
@ -480,8 +545,17 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
|
|||||||
u64 bytes_read, first_block, to_read, to_write;
|
u64 bytes_read, first_block, to_read, to_write;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_file_extent_item stack_fi = { 0 };
|
struct btrfs_file_extent_item stack_fi = { 0 };
|
||||||
|
u64 buf_size;
|
||||||
|
char *write_buf;
|
||||||
|
bool do_comp = g_compression != BTRFS_COMPRESS_NONE;
|
||||||
|
ssize_t comp_ret;
|
||||||
|
u64 flags = btrfs_stack_inode_flags(btrfs_inode);
|
||||||
|
|
||||||
to_read = min(file_pos + MAX_EXTENT_SIZE, source->size) - file_pos;
|
if (flags & BTRFS_INODE_NOCOMPRESS)
|
||||||
|
do_comp = false;
|
||||||
|
|
||||||
|
buf_size = do_comp ? BTRFS_MAX_COMPRESSED : MAX_EXTENT_SIZE;
|
||||||
|
to_read = min(file_pos + buf_size, source->size) - file_pos;
|
||||||
|
|
||||||
bytes_read = 0;
|
bytes_read = 0;
|
||||||
|
|
||||||
@ -500,8 +574,72 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
|
|||||||
bytes_read += ret_read;
|
bytes_read += ret_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bytes_read <= sectorsize)
|
||||||
|
do_comp = false;
|
||||||
|
|
||||||
|
if (do_comp) {
|
||||||
|
bool first_sector = !(flags & BTRFS_INODE_COMPRESS);
|
||||||
|
|
||||||
|
switch (g_compression) {
|
||||||
|
case BTRFS_COMPRESS_ZLIB:
|
||||||
|
comp_ret = zlib_compress_extent(first_sector, sectorsize,
|
||||||
|
source->buf, bytes_read,
|
||||||
|
source->comp_buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
comp_ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the function returned -E2BIG, the extent is incompressible.
|
||||||
|
* If this is the first sector, add the nocompress flag,
|
||||||
|
* increase the buffer size, and read the rest of the extent.
|
||||||
|
*/
|
||||||
|
if (comp_ret == -E2BIG)
|
||||||
|
do_comp = false;
|
||||||
|
else if (comp_ret < 0)
|
||||||
|
return comp_ret;
|
||||||
|
|
||||||
|
if (comp_ret == -E2BIG && first_sector) {
|
||||||
|
flags |= BTRFS_INODE_NOCOMPRESS;
|
||||||
|
btrfs_set_stack_inode_flags(btrfs_inode, flags);
|
||||||
|
|
||||||
|
buf_size = MAX_EXTENT_SIZE;
|
||||||
|
to_read = min(file_pos + buf_size, source->size) - file_pos;
|
||||||
|
|
||||||
|
while (bytes_read < to_read) {
|
||||||
|
ssize_t ret_read;
|
||||||
|
|
||||||
|
ret_read = pread(source->fd,
|
||||||
|
source->buf + bytes_read,
|
||||||
|
to_read - bytes_read,
|
||||||
|
file_pos + bytes_read);
|
||||||
|
if (ret_read < 0) {
|
||||||
|
error("cannot read %s at offset %llu length %llu: %m",
|
||||||
|
source->path_name,
|
||||||
|
file_pos + bytes_read,
|
||||||
|
to_read - bytes_read);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_read += ret_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_comp) {
|
||||||
|
to_write = round_up(comp_ret, sectorsize);
|
||||||
|
write_buf = source->comp_buf;
|
||||||
|
memset(write_buf + comp_ret, 0, to_write - comp_ret);
|
||||||
|
|
||||||
|
flags |= BTRFS_INODE_COMPRESS;
|
||||||
|
btrfs_set_stack_inode_flags(btrfs_inode, flags);
|
||||||
|
} else {
|
||||||
to_write = round_up(to_read, sectorsize);
|
to_write = round_up(to_read, sectorsize);
|
||||||
memset(source->buf + to_read, 0, to_write - to_read);
|
write_buf = source->buf;
|
||||||
|
memset(write_buf + to_read, 0, to_write - to_read);
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_reserve_extent(trans, root, to_write, 0, 0,
|
ret = btrfs_reserve_extent(trans, root, to_write, 0, 0,
|
||||||
(u64)-1, &key, 1);
|
(u64)-1, &key, 1);
|
||||||
@ -510,7 +648,7 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
first_block = key.objectid;
|
first_block = key.objectid;
|
||||||
|
|
||||||
ret = write_data_to_disk(root->fs_info, source->buf, first_block,
|
ret = write_data_to_disk(root->fs_info, write_buf, first_block,
|
||||||
to_write);
|
to_write);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error("failed to write %s", source->path_name);
|
error("failed to write %s", source->path_name);
|
||||||
@ -521,7 +659,7 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
|
|||||||
ret = btrfs_csum_file_block(trans, first_block + (i * sectorsize),
|
ret = btrfs_csum_file_block(trans, first_block + (i * sectorsize),
|
||||||
BTRFS_EXTENT_CSUM_OBJECTID,
|
BTRFS_EXTENT_CSUM_OBJECTID,
|
||||||
root->fs_info->csum_type,
|
root->fs_info->csum_type,
|
||||||
source->buf + (i * sectorsize));
|
write_buf + (i * sectorsize));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -529,8 +667,12 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
|
|||||||
btrfs_set_stack_file_extent_type(&stack_fi, BTRFS_FILE_EXTENT_REG);
|
btrfs_set_stack_file_extent_type(&stack_fi, BTRFS_FILE_EXTENT_REG);
|
||||||
btrfs_set_stack_file_extent_disk_bytenr(&stack_fi, first_block);
|
btrfs_set_stack_file_extent_disk_bytenr(&stack_fi, first_block);
|
||||||
btrfs_set_stack_file_extent_disk_num_bytes(&stack_fi, to_write);
|
btrfs_set_stack_file_extent_disk_num_bytes(&stack_fi, to_write);
|
||||||
btrfs_set_stack_file_extent_num_bytes(&stack_fi, to_write);
|
btrfs_set_stack_file_extent_num_bytes(&stack_fi, round_up(to_read, sectorsize));
|
||||||
btrfs_set_stack_file_extent_ram_bytes(&stack_fi, to_write);
|
btrfs_set_stack_file_extent_ram_bytes(&stack_fi, round_up(to_read, sectorsize));
|
||||||
|
|
||||||
|
if (do_comp)
|
||||||
|
btrfs_set_stack_file_extent_compression(&stack_fi, g_compression);
|
||||||
|
|
||||||
ret = insert_reserved_file_extent(trans, root, objectid, btrfs_inode,
|
ret = insert_reserved_file_extent(trans, root, objectid, btrfs_inode,
|
||||||
file_pos, &stack_fi);
|
file_pos, &stack_fi);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -539,6 +681,60 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
|
|||||||
return to_read;
|
return to_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the size of the compressed data if successful, -E2BIG if it is
|
||||||
|
* incompressible, or an error code.
|
||||||
|
*/
|
||||||
|
static ssize_t zlib_compress_inline_extent(char *buf, u64 size, char **comp_buf)
|
||||||
|
{
|
||||||
|
int zlib_ret;
|
||||||
|
ssize_t ret;
|
||||||
|
z_stream strm;
|
||||||
|
char *out = NULL;
|
||||||
|
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
zlib_ret = deflateInit(&strm, g_compression_level);
|
||||||
|
if (zlib_ret != Z_OK) {
|
||||||
|
error("deflateInit failed: %s", strm.msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = malloc(size);
|
||||||
|
if (!out) {
|
||||||
|
error_msg(ERROR_MSG_MEMORY, NULL);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
strm.next_out = (Bytef *)out;
|
||||||
|
strm.avail_out = size;
|
||||||
|
strm.next_in = (Bytef *)buf;
|
||||||
|
strm.avail_in = size;
|
||||||
|
|
||||||
|
zlib_ret = deflate(&strm, Z_FINISH);
|
||||||
|
|
||||||
|
if (zlib_ret != Z_OK && zlib_ret != Z_STREAM_END) {
|
||||||
|
error("deflate failed: %s", strm.msg);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zlib_ret == Z_STREAM_END && strm.avail_out > 0) {
|
||||||
|
*comp_buf = out;
|
||||||
|
ret = size - strm.avail_out;
|
||||||
|
} else {
|
||||||
|
ret = -E2BIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (ret < 0)
|
||||||
|
free(out);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int add_file_items(struct btrfs_trans_handle *trans,
|
static int add_file_items(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct btrfs_inode_item *btrfs_inode, u64 objectid,
|
struct btrfs_inode_item *btrfs_inode, u64 objectid,
|
||||||
@ -549,7 +745,7 @@ static int add_file_items(struct btrfs_trans_handle *trans,
|
|||||||
ssize_t ret_read;
|
ssize_t ret_read;
|
||||||
u32 sectorsize = fs_info->sectorsize;
|
u32 sectorsize = fs_info->sectorsize;
|
||||||
u64 file_pos = 0;
|
u64 file_pos = 0;
|
||||||
char *buf = NULL;
|
char *buf = NULL, *comp_buf = NULL;
|
||||||
struct source_descriptor source;
|
struct source_descriptor source;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@ -579,8 +775,28 @@ static int add_file_items(struct btrfs_trans_handle *trans,
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
|
switch (g_compression) {
|
||||||
buffer, st->st_size);
|
case BTRFS_COMPRESS_ZLIB:
|
||||||
|
ret = zlib_compress_inline_extent(buffer, st->st_size,
|
||||||
|
&comp_buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -E2BIG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = btrfs_insert_inline_extent(trans, root, objectid,
|
||||||
|
0, buffer, st->st_size,
|
||||||
|
BTRFS_COMPRESS_NONE,
|
||||||
|
st->st_size);
|
||||||
|
} else {
|
||||||
|
ret = btrfs_insert_inline_extent(trans, root, objectid,
|
||||||
|
0, comp_buf, ret,
|
||||||
|
g_compression,
|
||||||
|
st->st_size);
|
||||||
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
/* Update the inode nbytes for inline extents. */
|
/* Update the inode nbytes for inline extents. */
|
||||||
btrfs_set_stack_inode_nbytes(btrfs_inode, st->st_size);
|
btrfs_set_stack_inode_nbytes(btrfs_inode, st->st_size);
|
||||||
@ -593,10 +809,19 @@ static int add_file_items(struct btrfs_trans_handle *trans,
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_compression != BTRFS_COMPRESS_NONE) {
|
||||||
|
comp_buf = malloc(BTRFS_MAX_COMPRESSED);
|
||||||
|
if (!comp_buf) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
source.fd = fd;
|
source.fd = fd;
|
||||||
source.buf = buf;
|
source.buf = buf;
|
||||||
source.size = st->st_size;
|
source.size = st->st_size;
|
||||||
source.path_name = path_name;
|
source.path_name = path_name;
|
||||||
|
source.comp_buf = comp_buf;
|
||||||
|
|
||||||
while (file_pos < st->st_size) {
|
while (file_pos < st->st_size) {
|
||||||
ret = add_file_item_extent(trans, root, btrfs_inode, objectid,
|
ret = add_file_item_extent(trans, root, btrfs_inode, objectid,
|
||||||
@ -608,6 +833,7 @@ static int add_file_items(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
free(comp_buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
close(fd);
|
close(fd);
|
||||||
return ret;
|
return ret;
|
||||||
@ -1012,7 +1238,9 @@ static int set_default_subvolume(struct btrfs_trans_handle *trans)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,
|
int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,
|
||||||
struct btrfs_root *root, struct list_head *subvols)
|
struct btrfs_root *root, struct list_head *subvols,
|
||||||
|
enum btrfs_compression_type compression,
|
||||||
|
u64 compression_level)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct stat root_st;
|
struct stat root_st;
|
||||||
@ -1023,8 +1251,24 @@ int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir
|
|||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (compression) {
|
||||||
|
case BTRFS_COMPRESS_NONE:
|
||||||
|
break;
|
||||||
|
case BTRFS_COMPRESS_ZLIB:
|
||||||
|
if (compression_level > ZLIB_BTRFS_MAX_LEVEL)
|
||||||
|
compression_level = ZLIB_BTRFS_MAX_LEVEL;
|
||||||
|
else if (compression_level == 0)
|
||||||
|
compression_level = ZLIB_BTRFS_DEFAULT_LEVEL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("unsupported compression type");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
g_trans = trans;
|
g_trans = trans;
|
||||||
g_subvols = subvols;
|
g_subvols = subvols;
|
||||||
|
g_compression = compression;
|
||||||
|
g_compression_level = compression_level;
|
||||||
INIT_LIST_HEAD(¤t_path.inode_list);
|
INIT_LIST_HEAD(¤t_path.inode_list);
|
||||||
|
|
||||||
ret = nftw(source_dir, ftw_add_inode, 32, FTW_PHYS);
|
ret = nftw(source_dir, ftw_add_inode, 32, FTW_PHYS);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#define __BTRFS_MKFS_ROOTDIR_H__
|
#define __BTRFS_MKFS_ROOTDIR_H__
|
||||||
|
|
||||||
#include "kerncompat.h"
|
#include "kerncompat.h"
|
||||||
|
#include "kernel-shared/compression.h"
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@ -37,7 +38,9 @@ struct rootdir_subvol {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,
|
int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir,
|
||||||
struct btrfs_root *root, struct list_head *subvols);
|
struct btrfs_root *root, struct list_head *subvols,
|
||||||
|
enum btrfs_compression_type compression,
|
||||||
|
u64 compression_level);
|
||||||
u64 btrfs_mkfs_size_dir(const char *dir_name, u32 sectorsize, u64 min_dev_size,
|
u64 btrfs_mkfs_size_dir(const char *dir_name, u32 sectorsize, u64 min_dev_size,
|
||||||
u64 meta_profile, u64 data_profile);
|
u64 meta_profile, u64 data_profile);
|
||||||
int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret,
|
int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret,
|
||||||
|
Loading…
Reference in New Issue
Block a user