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:
Mark Harmstone 2024-11-19 15:19:31 +00:00 committed by David Sterba
parent 0966aa21b3
commit 0134e755c1
11 changed files with 337 additions and 31 deletions

View File

@ -212,6 +212,15 @@ OPTIONS
$ 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
Forcibly overwrite the block devices when an existing filesystem is detected.
By default, :command:`mkfs.btrfs` will utilize *libblkid* to check for any known

View File

@ -740,11 +740,11 @@ btrfsck.static: btrfs.static
mkfs.btrfs: $(mkfs_objects) $(objects) libbtrfsutil.a
@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)
@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
@echo " [LD] $@"

View File

@ -20,6 +20,7 @@
#include "kernel-shared/uapi/btrfs_tree.h"
#include "kernel-shared/ctree.h"
#include "kernel-shared/disk-io.h"
#include "kernel-shared/free-space-tree.h"
#include "kernel-shared/transaction.h"
#include "common/extent-tree-utils.h"

View File

@ -19,6 +19,7 @@
#include "kerncompat.h"
#include "kernel-lib/bitops.h"
#include "kernel-shared/compression.h"
struct btrfs_inode_item;
struct btrfs_path;

View File

@ -457,7 +457,9 @@ static int ext2_create_file_extents(struct btrfs_trans_handle *trans,
if (num_bytes > inode_size)
num_bytes = inode_size;
ret = btrfs_insert_inline_extent(trans, root, objectid,
0, buffer, num_bytes);
0, buffer, num_bytes,
BTRFS_COMPRESS_NONE,
num_bytes);
if (ret)
goto fail;
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]);
BUG_ON(pathname[inode_size] != 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);
return ret;
}

View File

@ -384,7 +384,8 @@ static int reiserfs_convert_tail(struct btrfs_trans_handle *trans,
length, offset, convert_flags);
ret = btrfs_insert_inline_extent(trans, root, objectid,
offset, body, length);
offset, body, length,
BTRFS_COMPRESS_NONE, length);
if (ret)
return ret;
@ -544,7 +545,8 @@ static int reiserfs_copy_symlink(struct btrfs_trans_handle *trans,
goto fail;
}
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);
fail:
pathrelse(&path);

View File

@ -63,7 +63,9 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
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_key key;
@ -99,8 +101,8 @@ int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
struct btrfs_file_extent_item);
btrfs_set_file_extent_generation(leaf, ei, trans->transid);
btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
btrfs_set_file_extent_ram_bytes(leaf, ei, size);
btrfs_set_file_extent_compression(leaf, ei, 0);
btrfs_set_file_extent_ram_bytes(leaf, ei, ram_bytes);
btrfs_set_file_extent_compression(leaf, ei, comp);
btrfs_set_file_extent_encryption(leaf, ei, 0);
btrfs_set_file_extent_other_encoding(leaf, ei, 0);

View File

@ -10,6 +10,7 @@
#include "kernel-shared/ctree.h"
#include "kernel-shared/uapi/btrfs_tree.h"
#include "kernel-shared/accessors.h"
#include "kernel-shared/compression.h"
struct bio;
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);
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
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,
* but fs doesn't store that terminating NUL).

View File

@ -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("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
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"),
"General:",
OPTLINE("-q|--quiet", "no messages except errors"),
@ -1058,6 +1059,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
char *source_dir = NULL;
struct rootdir_subvol *rds;
bool has_default_subvol = false;
enum btrfs_compression_type compression = BTRFS_COMPRESS_NONE;
u64 compression_level = 0;
LIST_HEAD(subvols);
cpu_detect_flags();
@ -1072,6 +1075,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
GETOPT_VAL_CHECKSUM,
GETOPT_VAL_GLOBAL_ROOTS,
GETOPT_VAL_DEVICE_UUID,
GETOPT_VAL_COMPRESS,
};
static const struct option long_options[] = {
{ "byte-count", required_argument, NULL, 'b' },
@ -1099,6 +1103,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
{ "quiet", 0, NULL, 'q' },
{ "verbose", 0, NULL, 'v' },
{ "shrink", no_argument, NULL, GETOPT_VAL_SHRINK },
{ "compress", required_argument, NULL,
GETOPT_VAL_COMPRESS },
#if EXPERIMENTAL
{ "param", required_argument, NULL, GETOPT_VAL_PARAM },
{ "num-global-roots", required_argument, NULL, GETOPT_VAL_GLOBAL_ROOTS },
@ -1272,6 +1278,38 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
case 'q':
bconf_be_quiet();
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:
strncpy_null(dev_uuid, optarg, BTRFS_UUID_UNPARSED_SIZE);
break;
@ -1953,7 +1991,8 @@ raid_groups:
}
ret = btrfs_mkfs_fill_dir(trans, source_dir, root,
&subvols);
&subvols, compression,
compression_level);
if (ret) {
error("error while filling filesystem: %d", ret);
btrfs_abort_transaction(trans, ret);

View File

@ -27,6 +27,7 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include "kernel-lib/sizes.h"
#include "kernel-shared/accessors.h"
#include "kernel-shared/uapi/btrfs_tree.h"
@ -46,6 +47,9 @@
#include "common/rbtree-utils.h"
#include "mkfs/rootdir.h"
#define ZLIB_BTRFS_DEFAULT_LEVEL 3
#define ZLIB_BTRFS_MAX_LEVEL 9
static u32 fs_block_size;
/*
@ -145,6 +149,8 @@ static struct btrfs_trans_handle *g_trans = NULL;
static struct list_head *g_subvols;
static u64 next_subvol_id = BTRFS_FIRST_FREE_OBJECTID;
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)
{
@ -352,7 +358,8 @@ static int add_symbolic_link(struct btrfs_trans_handle *trans,
buf[ret] = '\0'; /* readlink does not do it for us */
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) {
errno = -ret;
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.type = BTRFS_EXTENT_ITEM_KEY;
ins_key.offset = num_bytes;
ins_key.offset = disk_num_bytes;
/* Update extent tree. */
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);
ret = btrfs_update_block_group(trans, disk_bytenr,
num_bytes, 1, 0);
disk_num_bytes, 1, 0);
if (ret)
goto fail;
} else if (ret != -EEXIST) {
@ -429,22 +436,19 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
}
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)
goto fail;
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);
if (ret)
goto fail;
btrfs_set_stack_inode_nbytes(inode,
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,
file_pos);
if (ret)
@ -455,6 +459,66 @@ fail:
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
* inside the tiny block groups created during mkfs
@ -466,6 +530,7 @@ struct source_descriptor {
char *buf;
u64 size;
const char *path_name;
char *comp_buf;
};
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;
struct btrfs_key key;
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;
@ -500,8 +574,72 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
bytes_read += ret_read;
}
to_write = round_up(to_read, sectorsize);
memset(source->buf + to_read, 0, to_write - to_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);
write_buf = source->buf;
memset(write_buf + to_read, 0, to_write - to_read);
}
ret = btrfs_reserve_extent(trans, root, to_write, 0, 0,
(u64)-1, &key, 1);
@ -510,7 +648,7 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
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);
if (ret) {
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),
BTRFS_EXTENT_CSUM_OBJECTID,
root->fs_info->csum_type,
source->buf + (i * sectorsize));
write_buf + (i * sectorsize));
if (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_disk_bytenr(&stack_fi, first_block);
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_ram_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, 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,
file_pos, &stack_fi);
if (ret)
@ -539,6 +681,60 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
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,
struct btrfs_root *root,
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;
u32 sectorsize = fs_info->sectorsize;
u64 file_pos = 0;
char *buf = NULL;
char *buf = NULL, *comp_buf = NULL;
struct source_descriptor source;
int fd;
@ -579,8 +775,28 @@ static int add_file_items(struct btrfs_trans_handle *trans,
goto end;
}
ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
buffer, st->st_size);
switch (g_compression) {
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);
/* Update the inode nbytes for inline extents. */
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;
}
if (g_compression != BTRFS_COMPRESS_NONE) {
comp_buf = malloc(BTRFS_MAX_COMPRESSED);
if (!comp_buf) {
ret = -ENOMEM;
goto end;
}
}
source.fd = fd;
source.buf = buf;
source.size = st->st_size;
source.path_name = path_name;
source.comp_buf = comp_buf;
while (file_pos < st->st_size) {
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:
free(comp_buf);
free(buf);
close(fd);
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,
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;
struct stat root_st;
@ -1023,8 +1251,24 @@ int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir
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_subvols = subvols;
g_compression = compression;
g_compression_level = compression_level;
INIT_LIST_HEAD(&current_path.inode_list);
ret = nftw(source_dir, ftw_add_inode, 32, FTW_PHYS);

View File

@ -22,6 +22,7 @@
#define __BTRFS_MKFS_ROOTDIR_H__
#include "kerncompat.h"
#include "kernel-shared/compression.h"
#include <sys/types.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,
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 meta_profile, u64 data_profile);
int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret,