for-6.17-rc6-tag

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmjPff0ACgkQxWXV+ddt
 WDvaVRAAqcPlR07B5Y1S+73JlqVXx5g9S77uarkn48FS5OGJ97ad7NFF79LdFKaQ
 d5OpD2aZRzi+XLQTlD7Wz9udmr2OvHLnTih6E6KOa7ukL+bJMsK6CXw4usLW5ke0
 nHNPNCLnEtIbQ5hKFpsjfsUrJaNtGcFNoWlnkl0iG1E0vjJQFBYqTNzBytv/ygc/
 jVDdoftA7vqnUeXemVGhnfvLqyP5g374jnUB3CIejMQfzSJXCS07DXwmn/eeRoxl
 HdJre+kjavV3WL/fvAqq0f6wEBlYRXXiLUnSt2xRr5a70svy0eWhx8ggE6gBqlyR
 fo4UC8hsETZdQAW35ZgUfJBtUVqx+bwNLZ5xVFlDKv8uix7B9x7Fgcmhsin+GovN
 JowBYe28FTctU4x3IBqyweXZOn2815HvvZlIbU/D9jVSB7RSQ/2nUKAec1tYBk2G
 dy9TRxxE+N3/csJ3J+VqvFEMnGorVDN1GBXFPwIgy2OTpNi6dM7s3909lO2ebp2+
 Kw2vBFtwEVdGk7ZkYVkHtsPa/Rn+uXLSCp+m08eqIJKTPxbTn2W6XXsoptHt5iXL
 t43oRP/wq9qUKgYJUd8242nQp/Sf+zEvIjHYDpbsDHajPsTfUo0nuCN8ZojceWat
 RRJclWk7KXdicQT4JiWp19mQakn9gjM+vOoMriGZwRf4ZGkO1PE=
 =Oj5R
 -----END PGP SIGNATURE-----

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:
Linus Torvalds 2025-09-20 21:41:26 -07:00
commit f975f08c2e
5 changed files with 43 additions and 21 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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;
}