lkml.org 
[lkml]   [2014]   [Jun]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.15 130/139] Btrfs: fix scrub_print_warning to handle skinny metadata extents
    Date
    3.15-stable review patch.  If anyone has any objections, please let me know.

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

    From: Liu Bo <bo.li.liu@oracle.com>

    commit 6eda71d0c030af0fc2f68aaa676e6d445600855b upstream.

    The skinny extents are intepreted incorrectly in scrub_print_warning(),
    and end up hitting the BUG() in btrfs_extent_inline_ref_size.

    Reported-by: Konstantinos Skarlatos <k.skarlatos@gmail.com>
    Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
    Signed-off-by: Chris Mason <clm@fb.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/btrfs/backref.c | 30 +++++++++++++++++++-----------
    fs/btrfs/backref.h | 4 ++--
    fs/btrfs/scrub.c | 5 +++--
    3 files changed, 24 insertions(+), 15 deletions(-)

    --- a/fs/btrfs/backref.c
    +++ b/fs/btrfs/backref.c
    @@ -1405,9 +1405,10 @@ int extent_from_logical(struct btrfs_fs_
    * returns <0 on error
    */
    static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
    - struct btrfs_extent_item *ei, u32 item_size,
    - struct btrfs_extent_inline_ref **out_eiref,
    - int *out_type)
    + struct btrfs_key *key,
    + struct btrfs_extent_item *ei, u32 item_size,
    + struct btrfs_extent_inline_ref **out_eiref,
    + int *out_type)
    {
    unsigned long end;
    u64 flags;
    @@ -1417,9 +1418,16 @@ static int __get_extent_inline_ref(unsig
    /* first call */
    flags = btrfs_extent_flags(eb, ei);
    if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
    - info = (struct btrfs_tree_block_info *)(ei + 1);
    - *out_eiref =
    - (struct btrfs_extent_inline_ref *)(info + 1);
    + if (key->type == BTRFS_METADATA_ITEM_KEY) {
    + /* a skinny metadata extent */
    + *out_eiref =
    + (struct btrfs_extent_inline_ref *)(ei + 1);
    + } else {
    + WARN_ON(key->type != BTRFS_EXTENT_ITEM_KEY);
    + info = (struct btrfs_tree_block_info *)(ei + 1);
    + *out_eiref =
    + (struct btrfs_extent_inline_ref *)(info + 1);
    + }
    } else {
    *out_eiref = (struct btrfs_extent_inline_ref *)(ei + 1);
    }
    @@ -1429,7 +1437,7 @@ static int __get_extent_inline_ref(unsig
    }

    end = (unsigned long)ei + item_size;
    - *out_eiref = (struct btrfs_extent_inline_ref *)*ptr;
    + *out_eiref = (struct btrfs_extent_inline_ref *)(*ptr);
    *out_type = btrfs_extent_inline_ref_type(eb, *out_eiref);

    *ptr += btrfs_extent_inline_ref_size(*out_type);
    @@ -1448,8 +1456,8 @@ static int __get_extent_inline_ref(unsig
    * <0 on error.
    */
    int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
    - struct btrfs_extent_item *ei, u32 item_size,
    - u64 *out_root, u8 *out_level)
    + struct btrfs_key *key, struct btrfs_extent_item *ei,
    + u32 item_size, u64 *out_root, u8 *out_level)
    {
    int ret;
    int type;
    @@ -1460,8 +1468,8 @@ int tree_backref_for_extent(unsigned lon
    return 1;

    while (1) {
    - ret = __get_extent_inline_ref(ptr, eb, ei, item_size,
    - &eiref, &type);
    + ret = __get_extent_inline_ref(ptr, eb, key, ei, item_size,
    + &eiref, &type);
    if (ret < 0)
    return ret;

    --- a/fs/btrfs/backref.h
    +++ b/fs/btrfs/backref.h
    @@ -40,8 +40,8 @@ int extent_from_logical(struct btrfs_fs_
    u64 *flags);

    int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
    - struct btrfs_extent_item *ei, u32 item_size,
    - u64 *out_root, u8 *out_level);
    + struct btrfs_key *key, struct btrfs_extent_item *ei,
    + u32 item_size, u64 *out_root, u8 *out_level);

    int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
    u64 extent_item_objectid,
    --- a/fs/btrfs/scrub.c
    +++ b/fs/btrfs/scrub.c
    @@ -588,8 +588,9 @@ static void scrub_print_warning(const ch

    if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
    do {
    - ret = tree_backref_for_extent(&ptr, eb, ei, item_size,
    - &ref_root, &ref_level);
    + ret = tree_backref_for_extent(&ptr, eb, &found_key, ei,
    + item_size, &ref_root,
    + &ref_level);
    printk_in_rcu(KERN_WARNING
    "BTRFS: %s at logical %llu on dev %s, "
    "sector %llu: metadata %s (level %d) in tree "



    \
     
     \ /
      Last update: 2014-06-28 20:41    [W:2.872 / U:0.040 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site