Skip to content

Commit f975f08

Browse files
committed
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
2 parents fce2420 + b98b208 commit f975f08

File tree

5 files changed

+43
-21
lines changed

5 files changed

+43
-21
lines changed

fs/btrfs/compression.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,25 +1616,29 @@ int btrfs_compress_heuristic(struct btrfs_inode *inode, u64 start, u64 end)
16161616
}
16171617

16181618
/*
1619-
* Convert the compression suffix (eg. after "zlib" starting with ":") to
1620-
* level, unrecognized string will set the default level. Negative level
1621-
* numbers are allowed.
1619+
* Convert the compression suffix (eg. after "zlib" starting with ":") to level.
1620+
*
1621+
* If the resulting level exceeds the algo's supported levels, it will be clamped.
1622+
*
1623+
* Return <0 if no valid string can be found.
1624+
* Return 0 if everything is fine.
16221625
*/
1623-
int btrfs_compress_str2level(unsigned int type, const char *str)
1626+
int btrfs_compress_str2level(unsigned int type, const char *str, int *level_ret)
16241627
{
16251628
int level = 0;
16261629
int ret;
16271630

1628-
if (!type)
1631+
if (!type) {
1632+
*level_ret = btrfs_compress_set_level(type, level);
16291633
return 0;
1634+
}
16301635

16311636
if (str[0] == ':') {
16321637
ret = kstrtoint(str + 1, 10, &level);
16331638
if (ret)
1634-
level = 0;
1639+
return ret;
16351640
}
16361641

1637-
level = btrfs_compress_set_level(type, level);
1638-
1639-
return level;
1642+
*level_ret = btrfs_compress_set_level(type, level);
1643+
return 0;
16401644
}

fs/btrfs/compression.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
102102
bool writeback);
103103
void btrfs_submit_compressed_read(struct btrfs_bio *bbio);
104104

105-
int btrfs_compress_str2level(unsigned int type, const char *str);
105+
int btrfs_compress_str2level(unsigned int type, const char *str, int *level_ret);
106106

107107
struct folio *btrfs_alloc_compr_folio(void);
108108
void btrfs_free_compr_folio(struct folio *folio);

fs/btrfs/ref-verify.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -980,11 +980,18 @@ int btrfs_build_ref_tree(struct btrfs_fs_info *fs_info)
980980
if (!btrfs_test_opt(fs_info, REF_VERIFY))
981981
return 0;
982982

983+
extent_root = btrfs_extent_root(fs_info, 0);
984+
/* If the extent tree is damaged we cannot ignore it (IGNOREBADROOTS). */
985+
if (IS_ERR(extent_root)) {
986+
btrfs_warn(fs_info, "ref-verify: extent tree not available, disabling");
987+
btrfs_clear_opt(fs_info->mount_opt, REF_VERIFY);
988+
return 0;
989+
}
990+
983991
path = btrfs_alloc_path();
984992
if (!path)
985993
return -ENOMEM;
986994

987-
extent_root = btrfs_extent_root(fs_info, 0);
988995
eb = btrfs_read_lock_root_node(extent_root);
989996
level = btrfs_header_level(eb);
990997
path->nodes[level] = eb;

fs/btrfs/super.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
276276
const struct fs_parameter *param, int opt)
277277
{
278278
const char *string = param->string;
279+
int ret;
279280

280281
/*
281282
* Provide the same semantics as older kernels that don't use fs
@@ -294,24 +295,30 @@ static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
294295
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
295296
} else if (btrfs_match_compress_type(string, "zlib", true)) {
296297
ctx->compress_type = BTRFS_COMPRESS_ZLIB;
297-
ctx->compress_level = btrfs_compress_str2level(BTRFS_COMPRESS_ZLIB,
298-
string + 4);
298+
ret = btrfs_compress_str2level(BTRFS_COMPRESS_ZLIB, string + 4,
299+
&ctx->compress_level);
300+
if (ret < 0)
301+
goto error;
299302
btrfs_set_opt(ctx->mount_opt, COMPRESS);
300303
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
301304
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
302305
} else if (btrfs_match_compress_type(string, "lzo", true)) {
303306
ctx->compress_type = BTRFS_COMPRESS_LZO;
304-
ctx->compress_level = btrfs_compress_str2level(BTRFS_COMPRESS_LZO,
305-
string + 3);
307+
ret = btrfs_compress_str2level(BTRFS_COMPRESS_LZO, string + 3,
308+
&ctx->compress_level);
309+
if (ret < 0)
310+
goto error;
306311
if (string[3] == ':' && string[4])
307312
btrfs_warn(NULL, "Compression level ignored for LZO");
308313
btrfs_set_opt(ctx->mount_opt, COMPRESS);
309314
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
310315
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
311316
} else if (btrfs_match_compress_type(string, "zstd", true)) {
312317
ctx->compress_type = BTRFS_COMPRESS_ZSTD;
313-
ctx->compress_level = btrfs_compress_str2level(BTRFS_COMPRESS_ZSTD,
314-
string + 4);
318+
ret = btrfs_compress_str2level(BTRFS_COMPRESS_ZSTD, string + 4,
319+
&ctx->compress_level);
320+
if (ret < 0)
321+
goto error;
315322
btrfs_set_opt(ctx->mount_opt, COMPRESS);
316323
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
317324
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
@@ -322,10 +329,14 @@ static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
322329
btrfs_clear_opt(ctx->mount_opt, COMPRESS);
323330
btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
324331
} else {
325-
btrfs_err(NULL, "unrecognized compression value %s", string);
326-
return -EINVAL;
332+
ret = -EINVAL;
333+
goto error;
327334
}
328335
return 0;
336+
error:
337+
btrfs_err(NULL, "failed to parse compression option '%s'", string);
338+
return ret;
339+
329340
}
330341

331342
static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param)

fs/btrfs/tree-checker.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,10 +1756,10 @@ static int check_inode_ref(struct extent_buffer *leaf,
17561756
while (ptr < end) {
17571757
u16 namelen;
17581758

1759-
if (unlikely(ptr + sizeof(iref) > end)) {
1759+
if (unlikely(ptr + sizeof(*iref) > end)) {
17601760
inode_ref_err(leaf, slot,
17611761
"inode ref overflow, ptr %lu end %lu inode_ref_size %zu",
1762-
ptr, end, sizeof(iref));
1762+
ptr, end, sizeof(*iref));
17631763
return -EUCLEAN;
17641764
}
17651765

0 commit comments

Comments
 (0)