• Filipe David Borba Manana's avatar
    Btrfs: don't miss skinny extent items on delayed ref head contention · 639eefc8
    Filipe David Borba Manana authored
    Currently extent-tree.c:btrfs_lookup_extent_info() can miss the lookup
    of skinny extent items. This can happen when the execution flow is the
    following:
    
    * We do an extent tree lookup and fail to find a skinny extent item;
    
    * As a result, we attempt to see if a non-skinny extent item exists,
      either by looking at previous item in the leaf or by doing another
      full extent tree search;
    
    * We have a transaction and then we check for a matching delayed ref
      head in the transaction's delayed refs rbtree;
    
    * We find such delayed ref head and then we try to lock it with a
      call to mutex_trylock();
    
    * The lock was contended so we jump to the label "again", which repeats
      the extent tree search but for a non-skinny extent item, because we set
      previously metadata variable to 0 and the search key to look for a
      non-skinny extent-item;
    
    * After the jump (and after releasing the transaction's delayed refs
      lock), a skinny extent item might have been added to the extent tree
      but we will miss it because metadata is set to 0 and the search key
      is set for a non-skinny extent-item.
    
    The fix here is to not reset metadata to 0 and to jump to the initial search
    key setup if the delayed ref head is contended, instead of jumping directly
    to the extent tree search label ("again").
    
    This issue was found while investigating the issue reported at Bugzilla 64961.
    
    David Sterba suspected this function was missing extent items, and that
    this could be caused by the last change to this function, which was made
    in the following patch:
    
        [PATCH] Btrfs: optimize btrfs_lookup_extent_info()
        (commit 74be9510)
    
    But in fact this issue already existed before, because after failing to find
    a skinny extent item, the code set the search key for a non-skinny extent
    item, and on contention of a matching delayed ref head it would not search
    the extent tree for a skinny extent item anymore.
    Signed-off-by: default avatarFilipe David Borba Manana <fdmanana@gmail.com>
    Reviewed-by: default avatarLiu Bo <bo.li.liu@oracle.com>
    Signed-off-by: default avatarChris Mason <clm@fb.com>
    639eefc8
extent-tree.c 238 KB