The commit is pushed to "branch-rh7-3.10.0-1160.62.1.vz7.187.x-ovz" and will 
appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1160.62.1.vz7.187.5
------>
commit 95b93077b2c7f751466fb0a5f2732b1fa426d29c
Author: Zhang Yi <yi.zh...@huawei.com>
Date:   Tue Jun 14 17:53:31 2022 +0300

    ms/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 <yi.zh...@huawei.com>
    Link: https://lore.kernel.org/r/20210908120850.4012324-3-yi.zh...@huawei.com
    Signed-off-by: Theodore Ts'o <ty...@mit.edu>
    
    (cherry-picked from ms commit 9c6e071913792d80894cd0be98cc3c4b770e26d3)
    https://jira.sw.ru/browse/PSBM-139452
    Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com>
---
 fs/ext4/extents.c | 58 +++++++++++++++++++++++++++++++++----------------------
 1 file changed, 35 insertions(+), 23 deletions(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 76a2f153fb72..0b6ed085f3d9 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -397,7 +397,7 @@ static int ext4_valid_extent_idx(struct inode *inode,
 
 static int ext4_valid_extent_entries(struct inode *inode,
                                struct ext4_extent_header *eh,
-                               int depth)
+                               ext4_lblk_t lblk, int depth)
 {
        struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
        unsigned short entries;
@@ -413,6 +413,14 @@ static int ext4_valid_extent_entries(struct inode *inode,
        if (depth == 0) {
                /* leaf entries */
                struct ext4_extent *ext = EXT_FIRST_EXTENT(eh);
+
+               /*
+                * The logical block in the first entry should equal to
+                * the number in the index block.
+                */
+               if (depth != ext_depth(inode) &&
+                   lblk != le32_to_cpu(ext->ee_block))
+                       return 0;
                while (entries) {
                        if (!ext4_valid_extent(inode, ext))
                                return 0;
@@ -430,6 +438,14 @@ static int ext4_valid_extent_entries(struct inode *inode,
                }
        } else {
                struct ext4_extent_idx *ext_idx = EXT_FIRST_INDEX(eh);
+
+               /*
+                * The logical block in the first entry should equal to
+                * the number in the parent index block.
+                */
+               if (depth != ext_depth(inode) &&
+                   lblk != le32_to_cpu(ext_idx->ei_block))
+                       return 0;
                while (entries) {
                        if (!ext4_valid_extent_idx(inode, ext_idx))
                                return 0;
@@ -451,7 +467,7 @@ static int ext4_valid_extent_entries(struct inode *inode,
 
 static int __ext4_ext_check(const char *function, unsigned int line,
                            struct inode *inode, struct ext4_extent_header *eh,
-                           int depth, ext4_fsblk_t pblk)
+                           int depth, ext4_fsblk_t pblk, ext4_lblk_t lblk)
 {
        const char *error_msg;
        int max = 0;
@@ -477,7 +493,7 @@ static int __ext4_ext_check(const char *function, unsigned 
int line,
                error_msg = "invalid eh_entries";
                goto corrupted;
        }
-       if (!ext4_valid_extent_entries(inode, eh, depth)) {
+       if (!ext4_valid_extent_entries(inode, eh, lblk, depth)) {
                error_msg = "invalid extent entries";
                goto corrupted;
        }
@@ -501,7 +517,7 @@ static int __ext4_ext_check(const char *function, unsigned 
int line,
 }
 
 #define ext4_ext_check(inode, eh, depth, pblk)                 \
-       __ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk))
+       __ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk), 0)
 
 int ext4_ext_check_inode(struct inode *inode)
 {
@@ -510,12 +526,14 @@ int ext4_ext_check_inode(struct inode *inode)
 
 static struct buffer_head *
 __read_extent_tree_block(const char *function, unsigned int line,
-                        struct inode *inode, ext4_fsblk_t pblk, int depth,
-                        int flags)
+                        struct inode *inode, struct ext4_extent_idx *idx,
+                        int depth, int flags)
 {
        struct buffer_head              *bh;
        int                             err;
+       ext4_fsblk_t                    pblk;
 
+       pblk = ext4_idx_pblock(idx);
        bh = sb_getblk(inode->i_sb, pblk);
        if (unlikely(!bh))
                return ERR_PTR(-ENOMEM);
@@ -528,8 +546,8 @@ __read_extent_tree_block(const char *function, unsigned int 
line,
        }
        if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE))
                return bh;
-       err = __ext4_ext_check(function, line, inode,
-                              ext_block_hdr(bh), depth, pblk);
+       err = __ext4_ext_check(function, line, inode, ext_block_hdr(bh),
+                              depth, pblk, le32_to_cpu(idx->ei_block));
        if (err)
                goto errout;
        set_buffer_verified(bh);
@@ -566,8 +584,8 @@ __read_extent_tree_block(const char *function, unsigned int 
line,
 
 }
 
-#define read_extent_tree_block(inode, pblk, depth, flags)              \
-       __read_extent_tree_block(__func__, __LINE__, (inode), (pblk),   \
+#define read_extent_tree_block(inode, idx, depth, flags)               \
+       __read_extent_tree_block(__func__, __LINE__, (inode), (idx),    \
                                 (depth), (flags))
 
 /*
@@ -614,8 +632,7 @@ int ext4_ext_precache(struct inode *inode)
                        i--;
                        continue;
                }
-               bh = read_extent_tree_block(inode,
-                                           ext4_idx_pblock(path[i].p_idx++),
+               bh = read_extent_tree_block(inode, path[i].p_idx++,
                                            depth - i - 1,
                                            EXT4_EX_FORCE_CACHE);
                if (IS_ERR(bh)) {
@@ -907,8 +924,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
                path[ppos].p_depth = i;
                path[ppos].p_ext = NULL;
 
-               bh = read_extent_tree_block(inode, path[ppos].p_block, --i,
-                                           flags);
+               bh = read_extent_tree_block(inode, path[ppos].p_idx, --i, 
flags);
                if (IS_ERR(bh)) {
                        ret = PTR_ERR(bh);
                        goto err;
@@ -1504,7 +1520,6 @@ static int ext4_ext_search_right(struct inode *inode,
        struct ext4_extent_header *eh;
        struct ext4_extent_idx *ix;
        struct ext4_extent *ex;
-       ext4_fsblk_t block;
        int depth;      /* Note, NOT eh_depth; depth from top of tree */
        int ee_len;
 
@@ -1571,20 +1586,17 @@ static int ext4_ext_search_right(struct inode *inode,
         * follow it and find the closest allocated
         * block to the right */
        ix++;
-       block = ext4_idx_pblock(ix);
        while (++depth < path->p_depth) {
                /* subtract from p_depth to get proper eh_depth */
-               bh = read_extent_tree_block(inode, block,
-                                           path->p_depth - depth, 0);
+               bh = read_extent_tree_block(inode, ix, path->p_depth - depth, 
0);
                if (IS_ERR(bh))
                        return PTR_ERR(bh);
                eh = ext_block_hdr(bh);
                ix = EXT_FIRST_INDEX(eh);
-               block = ext4_idx_pblock(ix);
                put_bh(bh);
        }
 
-       bh = read_extent_tree_block(inode, block, path->p_depth - depth, 0);
+       bh = read_extent_tree_block(inode, ix, path->p_depth - depth, 0);
        if (IS_ERR(bh))
                return PTR_ERR(bh);
        eh = ext_block_hdr(bh);
@@ -3002,9 +3014,9 @@ int ext4_ext_remove_space(struct inode *inode, 
ext4_lblk_t start,
                        ext_debug("move to level %d (block %llu)\n",
                                  i + 1, ext4_idx_pblock(path[i].p_idx));
                        memset(path + i + 1, 0, sizeof(*path));
-                       bh = read_extent_tree_block(inode,
-                               ext4_idx_pblock(path[i].p_idx), depth - i - 1,
-                               EXT4_EX_NOCACHE);
+                       bh = read_extent_tree_block(inode, path[i].p_idx,
+                                                   depth - i - 1,
+                                                   EXT4_EX_NOCACHE);
                        if (IS_ERR(bh)) {
                                /* should we reset i_size? */
                                err = PTR_ERR(bh);
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to