Merge tag 'for-6.17-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull a few more btrfs fixes from David Sterba: - in tree-checker, fix wrong size of check for inode ref item - in ref-verify, handle combination of mount options that allow partially damaged extent tree (reported by syzbot) - additional validation of compression mount option to catch invalid string as level * tag 'for-6.17-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: reject invalid compression level btrfs: ref-verify: handle damaged extent root tree btrfs: tree-checker: fix the incorrect inode ref size check
This commit is contained in:
@@ -1616,25 +1616,29 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the compression suffix (eg. after "zlib" starting with ":") to
|
||||
* level, unrecognized string will set the default level. Negative level
|
||||
* numbers are allowed.
|
||||
* Convert the compression suffix (eg. after "zlib" starting with ":") to level.
|
||||
*
|
||||
* If the resulting level exceeds the algo's supported levels, it will be clamped.
|
||||
*
|
||||
* Return <0 if no valid string can be found.
|
||||
* Return 0 if everything is fine.
|
||||
*/
|
||||
int btrfs_compress_str2level(unsigned int type, const char *str)
|
||||
int btrfs_compress_str2level(unsigned int type, const char *str, int *level_ret)
|
||||
{
|
||||
int level = 0;
|
||||
int ret;
|
||||
|
||||
if (!type)
|
||||
if (!type) {
|
||||
*level_ret = btrfs_compress_set_level(type, level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (str[0] == ':') {
|
||||
ret = kstrtoint(str + 1, 10, &level);
|
||||
if (ret)
|
||||
level = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
level = btrfs_compress_set_level(type, level);
|
||||
|
||||
return level;
|
||||
*level_ret = btrfs_compress_set_level(type, level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
|
||||
bool writeback);
|
||||
void btrfs_submit_compressed_read(struct btrfs_bio *bbio);
|
||||
|
||||
int btrfs_compress_str2level(unsigned int type, const char *str);
|
||||
int btrfs_compress_str2level(unsigned int type, const char *str, int *level_ret);
|
||||
|
||||
struct folio *btrfs_alloc_compr_folio(void);
|
||||
void btrfs_free_compr_folio(struct folio *folio);
|
||||
|
||||
@@ -980,11 +980,18 @@ int btrfs_build_ref_tree(struct btrfs_fs_info *fs_info)
|
||||
if (!btrfs_test_opt(fs_info, REF_VERIFY))
|
||||
return 0;
|
||||
|
||||
extent_root = btrfs_extent_root(fs_info, 0);
|
||||
/* If the extent tree is damaged we cannot ignore it (IGNOREBADROOTS). */
|
||||
if (IS_ERR(extent_root)) {
|
||||
btrfs_warn(fs_info, "ref-verify: extent tree not available, disabling");
|
||||
btrfs_clear_opt(fs_info->mount_opt, REF_VERIFY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
extent_root = btrfs_extent_root(fs_info, 0);
|
||||
eb = btrfs_read_lock_root_node(extent_root);
|
||||
level = btrfs_header_level(eb);
|
||||
path->nodes[level] = eb;
|
||||
|
||||
@@ -276,6 +276,7 @@ static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
|
||||
const struct fs_parameter *param, int opt)
|
||||
{
|
||||
const char *string = param->string;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Provide the same semantics as older kernels that don't use fs
|
||||
@@ -294,15 +295,19 @@ static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
|
||||
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
|
||||
} else if (btrfs_match_compress_type(string, "zlib", true)) {
|
||||
ctx->compress_type = BTRFS_COMPRESS_ZLIB;
|
||||
ctx->compress_level = btrfs_compress_str2level(BTRFS_COMPRESS_ZLIB,
|
||||
string + 4);
|
||||
ret = btrfs_compress_str2level(BTRFS_COMPRESS_ZLIB, string + 4,
|
||||
&ctx->compress_level);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
btrfs_set_opt(ctx->mount_opt, COMPRESS);
|
||||
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
|
||||
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
|
||||
} else if (btrfs_match_compress_type(string, "lzo", true)) {
|
||||
ctx->compress_type = BTRFS_COMPRESS_LZO;
|
||||
ctx->compress_level = btrfs_compress_str2level(BTRFS_COMPRESS_LZO,
|
||||
string + 3);
|
||||
ret = btrfs_compress_str2level(BTRFS_COMPRESS_LZO, string + 3,
|
||||
&ctx->compress_level);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
if (string[3] == ':' && string[4])
|
||||
btrfs_warn(NULL, "Compression level ignored for LZO");
|
||||
btrfs_set_opt(ctx->mount_opt, COMPRESS);
|
||||
@@ -310,8 +315,10 @@ static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
|
||||
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
|
||||
} else if (btrfs_match_compress_type(string, "zstd", true)) {
|
||||
ctx->compress_type = BTRFS_COMPRESS_ZSTD;
|
||||
ctx->compress_level = btrfs_compress_str2level(BTRFS_COMPRESS_ZSTD,
|
||||
string + 4);
|
||||
ret = btrfs_compress_str2level(BTRFS_COMPRESS_ZSTD, string + 4,
|
||||
&ctx->compress_level);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
btrfs_set_opt(ctx->mount_opt, COMPRESS);
|
||||
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
|
||||
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
|
||||
@@ -322,10 +329,14 @@ static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
|
||||
btrfs_clear_opt(ctx->mount_opt, COMPRESS);
|
||||
btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
|
||||
} else {
|
||||
btrfs_err(NULL, "unrecognized compression value %s", string);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
btrfs_err(NULL, "failed to parse compression option '%s'", string);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
|
||||
@@ -1756,10 +1756,10 @@ static int check_inode_ref(struct extent_buffer *leaf,
|
||||
while (ptr < end) {
|
||||
u16 namelen;
|
||||
|
||||
if (unlikely(ptr + sizeof(iref) > end)) {
|
||||
if (unlikely(ptr + sizeof(*iref) > end)) {
|
||||
inode_ref_err(leaf, slot,
|
||||
"inode ref overflow, ptr %lu end %lu inode_ref_size %zu",
|
||||
ptr, end, sizeof(iref));
|
||||
ptr, end, sizeof(*iref));
|
||||
return -EUCLEAN;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user