Skip to content

Commit bdb7d30

Browse files
Josef BacikChris Mason
authored andcommitted
Btrfs: fix tree log remove space corner case
The tree log stuff can have allocated space that we end up having split across a bitmap and a real extent. The free space code does not deal with this, it assumes that if it finds an extent or bitmap entry that the entire range must fall within the entry it finds. This isn't necessarily the case, so rework the remove function so it can handle this case properly. This fixed two panics the user hit, first in the case where the space was initially in a bitmap and then in an extent entry, and then the reverse case. Thanks, Reported-and-tested-by: Shaun Reich <[email protected]> Signed-off-by: Josef Bacik <[email protected]>
1 parent 6bf0231 commit bdb7d30

File tree

1 file changed

+52
-93
lines changed

1 file changed

+52
-93
lines changed

fs/btrfs/free-space-cache.c

Lines changed: 52 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,29 +1542,26 @@ static noinline int remove_from_bitmap(struct btrfs_free_space_ctl *ctl,
15421542
end = bitmap_info->offset + (u64)(BITS_PER_BITMAP * ctl->unit) - 1;
15431543

15441544
/*
1545-
* XXX - this can go away after a few releases.
1546-
*
1547-
* since the only user of btrfs_remove_free_space is the tree logging
1548-
* stuff, and the only way to test that is under crash conditions, we
1549-
* want to have this debug stuff here just in case somethings not
1550-
* working. Search the bitmap for the space we are trying to use to
1551-
* make sure its actually there. If its not there then we need to stop
1552-
* because something has gone wrong.
1545+
* We need to search for bits in this bitmap. We could only cover some
1546+
* of the extent in this bitmap thanks to how we add space, so we need
1547+
* to search for as much as it as we can and clear that amount, and then
1548+
* go searching for the next bit.
15531549
*/
15541550
search_start = *offset;
1555-
search_bytes = *bytes;
1551+
search_bytes = ctl->unit;
15561552
search_bytes = min(search_bytes, end - search_start + 1);
15571553
ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes);
15581554
BUG_ON(ret < 0 || search_start != *offset);
15591555

1560-
if (*offset > bitmap_info->offset && *offset + *bytes > end) {
1561-
bitmap_clear_bits(ctl, bitmap_info, *offset, end - *offset + 1);
1562-
*bytes -= end - *offset + 1;
1563-
*offset = end + 1;
1564-
} else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) {
1565-
bitmap_clear_bits(ctl, bitmap_info, *offset, *bytes);
1566-
*bytes = 0;
1567-
}
1556+
/* We may have found more bits than what we need */
1557+
search_bytes = min(search_bytes, *bytes);
1558+
1559+
/* Cannot clear past the end of the bitmap */
1560+
search_bytes = min(search_bytes, end - search_start + 1);
1561+
1562+
bitmap_clear_bits(ctl, bitmap_info, search_start, search_bytes);
1563+
*offset += search_bytes;
1564+
*bytes -= search_bytes;
15681565

15691566
if (*bytes) {
15701567
struct rb_node *next = rb_next(&bitmap_info->offset_index);
@@ -1595,7 +1592,7 @@ static noinline int remove_from_bitmap(struct btrfs_free_space_ctl *ctl,
15951592
* everything over again.
15961593
*/
15971594
search_start = *offset;
1598-
search_bytes = *bytes;
1595+
search_bytes = ctl->unit;
15991596
ret = search_bitmap(ctl, bitmap_info, &search_start,
16001597
&search_bytes);
16011598
if (ret < 0 || search_start != *offset)
@@ -1878,12 +1875,14 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
18781875
{
18791876
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
18801877
struct btrfs_free_space *info;
1881-
struct btrfs_free_space *next_info = NULL;
18821878
int ret = 0;
18831879

18841880
spin_lock(&ctl->tree_lock);
18851881

18861882
again:
1883+
if (!bytes)
1884+
goto out_lock;
1885+
18871886
info = tree_search_offset(ctl, offset, 0, 0);
18881887
if (!info) {
18891888
/*
@@ -1904,88 +1903,48 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
19041903
}
19051904
}
19061905

1907-
if (info->bytes < bytes && rb_next(&info->offset_index)) {
1908-
u64 end;
1909-
next_info = rb_entry(rb_next(&info->offset_index),
1910-
struct btrfs_free_space,
1911-
offset_index);
1912-
1913-
if (next_info->bitmap)
1914-
end = next_info->offset +
1915-
BITS_PER_BITMAP * ctl->unit - 1;
1916-
else
1917-
end = next_info->offset + next_info->bytes;
1918-
1919-
if (next_info->bytes < bytes ||
1920-
next_info->offset > offset || offset > end) {
1921-
printk(KERN_CRIT "Found free space at %llu, size %llu,"
1922-
" trying to use %llu\n",
1923-
(unsigned long long)info->offset,
1924-
(unsigned long long)info->bytes,
1925-
(unsigned long long)bytes);
1926-
WARN_ON(1);
1927-
ret = -EINVAL;
1928-
goto out_lock;
1929-
}
1930-
1931-
info = next_info;
1932-
}
1933-
1934-
if (info->bytes == bytes) {
1906+
if (!info->bitmap) {
19351907
unlink_free_space(ctl, info);
1936-
if (info->bitmap) {
1937-
kfree(info->bitmap);
1938-
ctl->total_bitmaps--;
1939-
}
1940-
kmem_cache_free(btrfs_free_space_cachep, info);
1941-
ret = 0;
1942-
goto out_lock;
1943-
}
1944-
1945-
if (!info->bitmap && info->offset == offset) {
1946-
unlink_free_space(ctl, info);
1947-
info->offset += bytes;
1948-
info->bytes -= bytes;
1949-
ret = link_free_space(ctl, info);
1950-
WARN_ON(ret);
1951-
goto out_lock;
1952-
}
1908+
if (offset == info->offset) {
1909+
u64 to_free = min(bytes, info->bytes);
1910+
1911+
info->bytes -= to_free;
1912+
info->offset += to_free;
1913+
if (info->bytes) {
1914+
ret = link_free_space(ctl, info);
1915+
WARN_ON(ret);
1916+
} else {
1917+
kmem_cache_free(btrfs_free_space_cachep, info);
1918+
}
19531919

1954-
if (!info->bitmap && info->offset <= offset &&
1955-
info->offset + info->bytes >= offset + bytes) {
1956-
u64 old_start = info->offset;
1957-
/*
1958-
* we're freeing space in the middle of the info,
1959-
* this can happen during tree log replay
1960-
*
1961-
* first unlink the old info and then
1962-
* insert it again after the hole we're creating
1963-
*/
1964-
unlink_free_space(ctl, info);
1965-
if (offset + bytes < info->offset + info->bytes) {
1966-
u64 old_end = info->offset + info->bytes;
1920+
offset += to_free;
1921+
bytes -= to_free;
1922+
goto again;
1923+
} else {
1924+
u64 old_end = info->bytes + info->offset;
19671925

1968-
info->offset = offset + bytes;
1969-
info->bytes = old_end - info->offset;
1926+
info->bytes = offset - info->offset;
19701927
ret = link_free_space(ctl, info);
19711928
WARN_ON(ret);
19721929
if (ret)
19731930
goto out_lock;
1974-
} else {
1975-
/* the hole we're creating ends at the end
1976-
* of the info struct, just free the info
1977-
*/
1978-
kmem_cache_free(btrfs_free_space_cachep, info);
1979-
}
1980-
spin_unlock(&ctl->tree_lock);
19811931

1982-
/* step two, insert a new info struct to cover
1983-
* anything before the hole
1984-
*/
1985-
ret = btrfs_add_free_space(block_group, old_start,
1986-
offset - old_start);
1987-
WARN_ON(ret); /* -ENOMEM */
1988-
goto out;
1932+
/* Not enough bytes in this entry to satisfy us */
1933+
if (old_end < offset + bytes) {
1934+
bytes -= old_end - offset;
1935+
offset = old_end;
1936+
goto again;
1937+
} else if (old_end == offset + bytes) {
1938+
/* all done */
1939+
goto out_lock;
1940+
}
1941+
spin_unlock(&ctl->tree_lock);
1942+
1943+
ret = btrfs_add_free_space(block_group, offset + bytes,
1944+
old_end - (offset + bytes));
1945+
WARN_ON(ret);
1946+
goto out;
1947+
}
19891948
}
19901949

19911950
ret = remove_from_bitmap(ctl, info, &offset, &bytes);

0 commit comments

Comments
 (0)