aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2015-03-13 15:01:24 -0400
committerJosef Bacik <jbacik@fb.com>2015-03-17 16:28:21 -0400
commitba117213554bc747561c5b7bf274d60ac93b8598 (patch)
treebaf4bb97cdf8edcf3397bef2030c9d458361c62b /fs
parentdcdf7f6ddba006f3482ebee73dfa6b75aec5f07b (diff)
Btrfs: account merges/splits properly
My fix Btrfs: fix merge delalloc logic only fixed half of the problems, it didn't fix the case where we have two large extents on either side and then join them together with a new small extent. We need to instead keep track of how many extents we have accounted for with each side of the new extent, and then see how many extents we need for the new large extent. If they match then we know we need to keep our reservation, otherwise we need to drop our reservation. This shows up with a case like this [BTRFS_MAX_EXTENT_SIZE+4K][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4K] Previously the logic would have said that the number extents required for the new size (3) is larger than the number of extents required for the largest side (2) therefore we need to keep our reservation. But this isn't the case, since both sides require a reservation of 2 which leads to 4 for the whole range currently reserved, but we only need 3, so we need to drop one of the reservations. The same problem existed for splits, we'd think we only need 3 extents when creating the hole but in reality we need 4. Thanks, Signed-off-by: Josef Bacik <jbacik@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/inode.c57
1 files changed, 30 insertions, 27 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 97b601bec326..bb74a4181075 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1542,30 +1542,17 @@ static void btrfs_split_extent_hook(struct inode *inode,
1542 u64 new_size; 1542 u64 new_size;
1543 1543
1544 /* 1544 /*
1545 * We need the largest size of the remaining extent to see if we 1545 * See the explanation in btrfs_merge_extent_hook, the same
1546 * need to add a new outstanding extent. Think of the following 1546 * applies here, just in reverse.
1547 * case
1548 *
1549 * [MEAX_EXTENT_SIZEx2 - 4k][4k]
1550 *
1551 * The new_size would just be 4k and we'd think we had enough
1552 * outstanding extents for this if we only took one side of the
1553 * split, same goes for the other direction. We need to see if
1554 * the larger size still is the same amount of extents as the
1555 * original size, because if it is we need to add a new
1556 * outstanding extent. But if we split up and the larger size
1557 * is less than the original then we are good to go since we've
1558 * already accounted for the extra extent in our original
1559 * accounting.
1560 */ 1547 */
1561 new_size = orig->end - split + 1; 1548 new_size = orig->end - split + 1;
1562 if ((split - orig->start) > new_size) 1549 num_extents = div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
1563 new_size = split - orig->start;
1564
1565 num_extents = div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
1566 BTRFS_MAX_EXTENT_SIZE); 1550 BTRFS_MAX_EXTENT_SIZE);
1567 if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1, 1551 new_size = split - orig->start;
1568 BTRFS_MAX_EXTENT_SIZE) < num_extents) 1552 num_extents += div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
1553 BTRFS_MAX_EXTENT_SIZE);
1554 if (div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
1555 BTRFS_MAX_EXTENT_SIZE) >= num_extents)
1569 return; 1556 return;
1570 } 1557 }
1571 1558
@@ -1591,9 +1578,6 @@ static void btrfs_merge_extent_hook(struct inode *inode,
1591 if (!(other->state & EXTENT_DELALLOC)) 1578 if (!(other->state & EXTENT_DELALLOC))
1592 return; 1579 return;
1593 1580
1594 old_size = other->end - other->start + 1;
1595 if (old_size < (new->end - new->start + 1))
1596 old_size = (new->end - new->start + 1);
1597 if (new->start > other->start) 1581 if (new->start > other->start)
1598 new_size = new->end - other->start + 1; 1582 new_size = new->end - other->start + 1;
1599 else 1583 else
@@ -1608,13 +1592,32 @@ static void btrfs_merge_extent_hook(struct inode *inode,
1608 } 1592 }
1609 1593
1610 /* 1594 /*
1611 * If we grew by another max_extent, just return, we want to keep that 1595 * We have to add up either side to figure out how many extents were
1612 * reserved amount. 1596 * accounted for before we merged into one big extent. If the number of
1597 * extents we accounted for is <= the amount we need for the new range
1598 * then we can return, otherwise drop. Think of it like this
1599 *
1600 * [ 4k][MAX_SIZE]
1601 *
1602 * So we've grown the extent by a MAX_SIZE extent, this would mean we
1603 * need 2 outstanding extents, on one side we have 1 and the other side
1604 * we have 1 so they are == and we can return. But in this case
1605 *
1606 * [MAX_SIZE+4k][MAX_SIZE+4k]
1607 *
1608 * Each range on their own accounts for 2 extents, but merged together
1609 * they are only 3 extents worth of accounting, so we need to drop in
1610 * this case.
1613 */ 1611 */
1612 old_size = other->end - other->start + 1;
1614 num_extents = div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1, 1613 num_extents = div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
1615 BTRFS_MAX_EXTENT_SIZE); 1614 BTRFS_MAX_EXTENT_SIZE);
1615 old_size = new->end - new->start + 1;
1616 num_extents += div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
1617 BTRFS_MAX_EXTENT_SIZE);
1618
1616 if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1, 1619 if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
1617 BTRFS_MAX_EXTENT_SIZE) > num_extents) 1620 BTRFS_MAX_EXTENT_SIZE) >= num_extents)
1618 return; 1621 return;
1619 1622
1620 spin_lock(&BTRFS_I(inode)->lock); 1623 spin_lock(&BTRFS_I(inode)->lock);