Btrfs: try harder to migrate items to left sibling before splitting a leaf
authorFilipe Manana <fdmanana@suse.com>
Fri, 17 Feb 2017 18:43:57 +0000 (18:43 +0000)
committerFilipe Manana <fdmanana@suse.com>
Fri, 24 Feb 2017 00:39:44 +0000 (00:39 +0000)
Before attempting to split a leaf we try to migrate items from the leaf to
its right and left siblings. We start by trying to move items into the
rigth sibling and, if the new item is meant to be inserted at the end of
our leaf, we try to free from our leaf an amount of bytes equal to the
number of bytes used by the new item, by setting the variable space_needed
to the byte size of that new item. However if we fail to move enough items
to the right sibling due to lack of space in that sibling, we then try
to move items into the left sibling, and in that case we try to free
an amount equal to the size of the new item from our leaf, when we need
only to free an amount corresponding to the size of the new item minus
the current free space of our leaf. So make sure that before we try to
move items to the left sibling we do set the variable space_needed with
a value corresponding to the new item's size minus the leaf's current
free space.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Liu Bo <bo.li.liu@oracle.com>
fs/btrfs/ctree.c

index 1192bc7d2ee782c1c915ba71aa771e57762b7d06..1fb60ee77b4a501bde2401462cc54b51169eb2fa 100644 (file)
@@ -4159,6 +4159,9 @@ static noinline int push_for_double_split(struct btrfs_trans_handle *trans,
 
        /* try to push all the items before our slot into the next leaf */
        slot = path->slots[0];
+       space_needed = data_size;
+       if (slot > 0)
+               space_needed -= btrfs_leaf_free_space(fs_info, path->nodes[0]);
        ret = push_leaf_left(trans, root, path, 1, space_needed, 0, slot);
        if (ret < 0)
                return ret;
@@ -4214,6 +4217,10 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
                if (wret < 0)
                        return wret;
                if (wret) {
+                       space_needed = data_size;
+                       if (slot > 0)
+                               space_needed -= btrfs_leaf_free_space(fs_info,
+                                                                     l);
                        wret = push_leaf_left(trans, root, path, space_needed,
                                              space_needed, 0, (u32)-1);
                        if (wret < 0)