• Filipe Manana's avatar
    btrfs: avoid unnecessary btree search restarts when reading node · 4bb59055
    Filipe Manana authored
    When reading a btree node, at read_block_for_search(), if we don't find
    the node's (or leaf) extent buffer in the cache, we will read it from
    disk. Since that requires waiting on IO, we release all upper level nodes
    from our path before reading the target node/leaf, and then return -EAGAIN
    to the caller, which will make the caller restart the while btree search.
    
    However we are causing the restart of btree search even for cases where
    it is not necessary:
    
    1) We have a path with ->skip_locking set to true, typically when doing
       a search on a commit root, so we are never holding locks on any node;
    
    2) We are doing a read search (the "ins_len" argument passed to
       btrfs_search_slot() is 0), or we are doing a search to modify an
       existing key (the "cow" argument passed to btrfs_search_slot() has
       a value of 1 and "ins_len" is 0), in which case we never hold locks
       for upper level nodes;
    
    3) We are doing a search to insert or delete a key, in which case we may
       or may not have upper level nodes locked. That depends on the current
       minimum write lock levels at btrfs_search_slot(), if we had to split
       or merge parent nodes, if we had to COW upper level nodes and if
       we ever visited slot 0 of an upper level node. It's still common to
       not have upper level nodes locked, but our current node must be at
       least at level 1, for insertions, or at least at level 2 for deletions.
       In these cases when we have locks on upper level nodes, they are always
       write locks.
    
    These cases where we are not holding locks on upper level nodes far
    outweigh the cases where we are holding locks, so it's completely wasteful
    to retry the whole search when we have no upper nodes locked.
    
    So change the logic to not return -EAGAIN, and make the caller retry the
    search, when we don't have the parent node locked - when it's not locked
    it means no other upper level nodes are locked as well.
    Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    4bb59055
ctree.c 125 KB