Skip to content

Commit 9c6e071

Browse files
zhangyi089tytso
authored andcommitted
ext4: check for inconsistent extents between index and leaf block
Now that we can check out overlapping extents in leaf block and out-of-order index extents in index block. But the .ee_block in the first extent of one leaf block should equal to the .ei_block in it's parent index extent entry. This patch add a check to verify such inconsistent between the index and leaf block. Signed-off-by: Zhang Yi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 8dd27fe commit 9c6e071

File tree

1 file changed

+36
-23
lines changed

1 file changed

+36
-23
lines changed

fs/ext4/extents.c

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,8 @@ static int ext4_valid_extent_idx(struct inode *inode,
354354

355355
static int ext4_valid_extent_entries(struct inode *inode,
356356
struct ext4_extent_header *eh,
357-
ext4_fsblk_t *pblk, int depth)
357+
ext4_lblk_t lblk, ext4_fsblk_t *pblk,
358+
int depth)
358359
{
359360
unsigned short entries;
360361
ext4_lblk_t lblock = 0;
@@ -368,6 +369,14 @@ static int ext4_valid_extent_entries(struct inode *inode,
368369
if (depth == 0) {
369370
/* leaf entries */
370371
struct ext4_extent *ext = EXT_FIRST_EXTENT(eh);
372+
373+
/*
374+
* The logical block in the first entry should equal to
375+
* the number in the index block.
376+
*/
377+
if (depth != ext_depth(inode) &&
378+
lblk != le32_to_cpu(ext->ee_block))
379+
return 0;
371380
while (entries) {
372381
if (!ext4_valid_extent(inode, ext))
373382
return 0;
@@ -384,6 +393,14 @@ static int ext4_valid_extent_entries(struct inode *inode,
384393
}
385394
} else {
386395
struct ext4_extent_idx *ext_idx = EXT_FIRST_INDEX(eh);
396+
397+
/*
398+
* The logical block in the first entry should equal to
399+
* the number in the parent index block.
400+
*/
401+
if (depth != ext_depth(inode) &&
402+
lblk != le32_to_cpu(ext_idx->ei_block))
403+
return 0;
387404
while (entries) {
388405
if (!ext4_valid_extent_idx(inode, ext_idx))
389406
return 0;
@@ -404,7 +421,7 @@ static int ext4_valid_extent_entries(struct inode *inode,
404421

405422
static int __ext4_ext_check(const char *function, unsigned int line,
406423
struct inode *inode, struct ext4_extent_header *eh,
407-
int depth, ext4_fsblk_t pblk)
424+
int depth, ext4_fsblk_t pblk, ext4_lblk_t lblk)
408425
{
409426
const char *error_msg;
410427
int max = 0, err = -EFSCORRUPTED;
@@ -430,7 +447,7 @@ static int __ext4_ext_check(const char *function, unsigned int line,
430447
error_msg = "invalid eh_entries";
431448
goto corrupted;
432449
}
433-
if (!ext4_valid_extent_entries(inode, eh, &pblk, depth)) {
450+
if (!ext4_valid_extent_entries(inode, eh, lblk, &pblk, depth)) {
434451
error_msg = "invalid extent entries";
435452
goto corrupted;
436453
}
@@ -460,7 +477,7 @@ static int __ext4_ext_check(const char *function, unsigned int line,
460477
}
461478

462479
#define ext4_ext_check(inode, eh, depth, pblk) \
463-
__ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk))
480+
__ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk), 0)
464481

465482
int ext4_ext_check_inode(struct inode *inode)
466483
{
@@ -493,16 +510,18 @@ static void ext4_cache_extents(struct inode *inode,
493510

494511
static struct buffer_head *
495512
__read_extent_tree_block(const char *function, unsigned int line,
496-
struct inode *inode, ext4_fsblk_t pblk, int depth,
497-
int flags)
513+
struct inode *inode, struct ext4_extent_idx *idx,
514+
int depth, int flags)
498515
{
499516
struct buffer_head *bh;
500517
int err;
501518
gfp_t gfp_flags = __GFP_MOVABLE | GFP_NOFS;
519+
ext4_fsblk_t pblk;
502520

503521
if (flags & EXT4_EX_NOFAIL)
504522
gfp_flags |= __GFP_NOFAIL;
505523

524+
pblk = ext4_idx_pblock(idx);
506525
bh = sb_getblk_gfp(inode->i_sb, pblk, gfp_flags);
507526
if (unlikely(!bh))
508527
return ERR_PTR(-ENOMEM);
@@ -515,8 +534,8 @@ __read_extent_tree_block(const char *function, unsigned int line,
515534
}
516535
if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE))
517536
return bh;
518-
err = __ext4_ext_check(function, line, inode,
519-
ext_block_hdr(bh), depth, pblk);
537+
err = __ext4_ext_check(function, line, inode, ext_block_hdr(bh),
538+
depth, pblk, le32_to_cpu(idx->ei_block));
520539
if (err)
521540
goto errout;
522541
set_buffer_verified(bh);
@@ -534,8 +553,8 @@ __read_extent_tree_block(const char *function, unsigned int line,
534553

535554
}
536555

537-
#define read_extent_tree_block(inode, pblk, depth, flags) \
538-
__read_extent_tree_block(__func__, __LINE__, (inode), (pblk), \
556+
#define read_extent_tree_block(inode, idx, depth, flags) \
557+
__read_extent_tree_block(__func__, __LINE__, (inode), (idx), \
539558
(depth), (flags))
540559

541560
/*
@@ -585,8 +604,7 @@ int ext4_ext_precache(struct inode *inode)
585604
i--;
586605
continue;
587606
}
588-
bh = read_extent_tree_block(inode,
589-
ext4_idx_pblock(path[i].p_idx++),
607+
bh = read_extent_tree_block(inode, path[i].p_idx++,
590608
depth - i - 1,
591609
EXT4_EX_FORCE_CACHE);
592610
if (IS_ERR(bh)) {
@@ -893,8 +911,7 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
893911
path[ppos].p_depth = i;
894912
path[ppos].p_ext = NULL;
895913

896-
bh = read_extent_tree_block(inode, path[ppos].p_block, --i,
897-
flags);
914+
bh = read_extent_tree_block(inode, path[ppos].p_idx, --i, flags);
898915
if (IS_ERR(bh)) {
899916
ret = PTR_ERR(bh);
900917
goto err;
@@ -1503,7 +1520,6 @@ static int ext4_ext_search_right(struct inode *inode,
15031520
struct ext4_extent_header *eh;
15041521
struct ext4_extent_idx *ix;
15051522
struct ext4_extent *ex;
1506-
ext4_fsblk_t block;
15071523
int depth; /* Note, NOT eh_depth; depth from top of tree */
15081524
int ee_len;
15091525

@@ -1570,20 +1586,17 @@ static int ext4_ext_search_right(struct inode *inode,
15701586
* follow it and find the closest allocated
15711587
* block to the right */
15721588
ix++;
1573-
block = ext4_idx_pblock(ix);
15741589
while (++depth < path->p_depth) {
15751590
/* subtract from p_depth to get proper eh_depth */
1576-
bh = read_extent_tree_block(inode, block,
1577-
path->p_depth - depth, 0);
1591+
bh = read_extent_tree_block(inode, ix, path->p_depth - depth, 0);
15781592
if (IS_ERR(bh))
15791593
return PTR_ERR(bh);
15801594
eh = ext_block_hdr(bh);
15811595
ix = EXT_FIRST_INDEX(eh);
1582-
block = ext4_idx_pblock(ix);
15831596
put_bh(bh);
15841597
}
15851598

1586-
bh = read_extent_tree_block(inode, block, path->p_depth - depth, 0);
1599+
bh = read_extent_tree_block(inode, ix, path->p_depth - depth, 0);
15871600
if (IS_ERR(bh))
15881601
return PTR_ERR(bh);
15891602
eh = ext_block_hdr(bh);
@@ -2962,9 +2975,9 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
29622975
ext_debug(inode, "move to level %d (block %llu)\n",
29632976
i + 1, ext4_idx_pblock(path[i].p_idx));
29642977
memset(path + i + 1, 0, sizeof(*path));
2965-
bh = read_extent_tree_block(inode,
2966-
ext4_idx_pblock(path[i].p_idx), depth - i - 1,
2967-
EXT4_EX_NOCACHE);
2978+
bh = read_extent_tree_block(inode, path[i].p_idx,
2979+
depth - i - 1,
2980+
EXT4_EX_NOCACHE);
29682981
if (IS_ERR(bh)) {
29692982
/* should we reset i_size? */
29702983
err = PTR_ERR(bh);

0 commit comments

Comments
 (0)