diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/inode.c | 57 |
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); |