lkml.org 
[lkml]   [2020]   [Apr]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.16 038/245] btrfs: Refactor check_leaf function for later expansion
    3.16.83-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Qu Wenruo <quwenruo.btrfs@gmx.com>

    commit c3267bbaa9cae09b62960eafe33ad19196803285 upstream.

    Current check_leaf() function does a good job checking key order and
    item offset/size.

    However it only checks from slot 0 to the last but one slot, this is
    good but makes later expansion hard.

    So this refactoring iterates from slot 0 to the last slot.
    For key comparison, it uses a key with all 0 as initial key, so all
    valid keys should be larger than that.

    And for item size/offset checks, it compares current item end with
    previous item offset.
    For slot 0, use leaf end as a special case.

    This makes later item/key offset checks and item size checks easier to
    be implemented.

    Also, makes check_leaf() to return -EUCLEAN other than -EIO to indicate
    error.

    Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
    Reviewed-by: Nikolay Borisov <nborisov@suse.com>
    Reviewed-by: David Sterba <dsterba@suse.com>
    Signed-off-by: David Sterba <dsterba@suse.com>
    [bwh: Backported to 4.4:
    - BTRFS_LEAF_DATA_SIZE() takes a root rather than an fs_info
    - Adjust context]
    Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    fs/btrfs/disk-io.c | 50 +++++++++++++++++++++++++---------------------
    1 file changed, 27 insertions(+), 23 deletions(-)

    --- a/fs/btrfs/disk-io.c
    +++ b/fs/btrfs/disk-io.c
    @@ -516,8 +516,9 @@ static int check_tree_block_fsid(struct
    static noinline int check_leaf(struct btrfs_root *root,
    struct extent_buffer *leaf)
    {
    + /* No valid key type is 0, so all key should be larger than this key */
    + struct btrfs_key prev_key = {0, 0, 0};
    struct btrfs_key key;
    - struct btrfs_key leaf_key;
    u32 nritems = btrfs_header_nritems(leaf);
    int slot;

    @@ -550,7 +551,7 @@ static noinline int check_leaf(struct bt
    CORRUPT("non-root leaf's nritems is 0",
    leaf, check_root, 0);
    free_extent_buffer(eb);
    - return -EIO;
    + return -EUCLEAN;
    }
    free_extent_buffer(eb);
    }
    @@ -560,28 +561,23 @@ static noinline int check_leaf(struct bt
    if (nritems == 0)
    return 0;

    - /* Check the 0 item */
    - if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
    - BTRFS_LEAF_DATA_SIZE(root)) {
    - CORRUPT("invalid item offset size pair", leaf, root, 0);
    - return -EIO;
    - }
    -
    /*
    - * Check to make sure each items keys are in the correct order and their
    - * offsets make sense. We only have to loop through nritems-1 because
    - * we check the current slot against the next slot, which verifies the
    - * next slot's offset+size makes sense and that the current's slot
    - * offset is correct.
    + * Check the following things to make sure this is a good leaf, and
    + * leaf users won't need to bother with similar sanity checks:
    + *
    + * 1) key order
    + * 2) item offset and size
    + * No overlap, no hole, all inside the leaf.
    */
    - for (slot = 0; slot < nritems - 1; slot++) {
    - btrfs_item_key_to_cpu(leaf, &leaf_key, slot);
    - btrfs_item_key_to_cpu(leaf, &key, slot + 1);
    + for (slot = 0; slot < nritems; slot++) {
    + u32 item_end_expected;
    +
    + btrfs_item_key_to_cpu(leaf, &key, slot);

    /* Make sure the keys are in the right order */
    - if (btrfs_comp_cpu_keys(&leaf_key, &key) >= 0) {
    + if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
    CORRUPT("bad key order", leaf, root, slot);
    - return -EIO;
    + return -EUCLEAN;
    }

    /*
    @@ -589,10 +585,14 @@ static noinline int check_leaf(struct bt
    * item data starts at the end of the leaf and grows towards the
    * front.
    */
    - if (btrfs_item_offset_nr(leaf, slot) !=
    - btrfs_item_end_nr(leaf, slot + 1)) {
    + if (slot == 0)
    + item_end_expected = BTRFS_LEAF_DATA_SIZE(root);
    + else
    + item_end_expected = btrfs_item_offset_nr(leaf,
    + slot - 1);
    + if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
    CORRUPT("slot offset bad", leaf, root, slot);
    - return -EIO;
    + return -EUCLEAN;
    }

    /*
    @@ -603,8 +603,12 @@ static noinline int check_leaf(struct bt
    if (btrfs_item_end_nr(leaf, slot) >
    BTRFS_LEAF_DATA_SIZE(root)) {
    CORRUPT("slot end outside of leaf", leaf, root, slot);
    - return -EIO;
    + return -EUCLEAN;
    }
    +
    + prev_key.objectid = key.objectid;
    + prev_key.type = key.type;
    + prev_key.offset = key.offset;
    }

    return 0;
    \
     
     \ /
      Last update: 2020-04-24 01:24    [W:4.090 / U:0.088 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site