aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2012-06-27 15:10:56 -0400
committerChris Mason <chris.mason@fusionio.com>2012-07-02 15:39:18 -0400
commitbdb7d303b33c1648514c9f9461d7513a4c05ce48 (patch)
tree78e24aa16c3d3cec9133616fa9076f7420e03612 /fs
parent6bf02314d9a5c29f6ec30285b9ad5361c2d4c85a (diff)
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 <sreich@kde.org> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/free-space-cache.c145
1 files changed, 52 insertions, 93 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 19a0d85b451c..a70c54e2e1be 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -1542,29 +1542,26 @@ again:
1542 end = bitmap_info->offset + (u64)(BITS_PER_BITMAP * ctl->unit) - 1; 1542 end = bitmap_info->offset + (u64)(BITS_PER_BITMAP * ctl->unit) - 1;
1543 1543
1544 /* 1544 /*
1545 * XXX - this can go away after a few releases. 1545 * We need to search for bits in this bitmap. We could only cover some
1546 * 1546 * of the extent in this bitmap thanks to how we add space, so we need
1547 * since the only user of btrfs_remove_free_space is the tree logging 1547 * to search for as much as it as we can and clear that amount, and then
1548 * stuff, and the only way to test that is under crash conditions, we 1548 * go searching for the next bit.
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.
1553 */ 1549 */
1554 search_start = *offset; 1550 search_start = *offset;
1555 search_bytes = *bytes; 1551 search_bytes = ctl->unit;
1556 search_bytes = min(search_bytes, end - search_start + 1); 1552 search_bytes = min(search_bytes, end - search_start + 1);
1557 ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes); 1553 ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes);
1558 BUG_ON(ret < 0 || search_start != *offset); 1554 BUG_ON(ret < 0 || search_start != *offset);
1559 1555
1560 if (*offset > bitmap_info->offset && *offset + *bytes > end) { 1556 /* We may have found more bits than what we need */
1561 bitmap_clear_bits(ctl, bitmap_info, *offset, end - *offset + 1); 1557 search_bytes = min(search_bytes, *bytes);
1562 *bytes -= end - *offset + 1; 1558
1563 *offset = end + 1; 1559 /* Cannot clear past the end of the bitmap */
1564 } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) { 1560 search_bytes = min(search_bytes, end - search_start + 1);
1565 bitmap_clear_bits(ctl, bitmap_info, *offset, *bytes); 1561
1566 *bytes = 0; 1562 bitmap_clear_bits(ctl, bitmap_info, search_start, search_bytes);
1567 } 1563 *offset += search_bytes;
1564 *bytes -= search_bytes;
1568 1565
1569 if (*bytes) { 1566 if (*bytes) {
1570 struct rb_node *next = rb_next(&bitmap_info->offset_index); 1567 struct rb_node *next = rb_next(&bitmap_info->offset_index);
@@ -1595,7 +1592,7 @@ again:
1595 * everything over again. 1592 * everything over again.
1596 */ 1593 */
1597 search_start = *offset; 1594 search_start = *offset;
1598 search_bytes = *bytes; 1595 search_bytes = ctl->unit;
1599 ret = search_bitmap(ctl, bitmap_info, &search_start, 1596 ret = search_bitmap(ctl, bitmap_info, &search_start,
1600 &search_bytes); 1597 &search_bytes);
1601 if (ret < 0 || search_start != *offset) 1598 if (ret < 0 || search_start != *offset)
@@ -1878,12 +1875,14 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
1878{ 1875{
1879 struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; 1876 struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
1880 struct btrfs_free_space *info; 1877 struct btrfs_free_space *info;
1881 struct btrfs_free_space *next_info = NULL;
1882 int ret = 0; 1878 int ret = 0;
1883 1879
1884 spin_lock(&ctl->tree_lock); 1880 spin_lock(&ctl->tree_lock);
1885 1881
1886again: 1882again:
1883 if (!bytes)
1884 goto out_lock;
1885
1887 info = tree_search_offset(ctl, offset, 0, 0); 1886 info = tree_search_offset(ctl, offset, 0, 0);
1888 if (!info) { 1887 if (!info) {
1889 /* 1888 /*
@@ -1904,88 +1903,48 @@ again:
1904 } 1903 }
1905 } 1904 }
1906 1905
1907 if (info->bytes < bytes && rb_next(&info->offset_index)) { 1906 if (!info->bitmap) {
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) {
1935 unlink_free_space(ctl, info); 1907 unlink_free_space(ctl, info);
1936 if (info->bitmap) { 1908 if (offset == info->offset) {
1937 kfree(info->bitmap); 1909 u64 to_free = min(bytes, info->bytes);
1938 ctl->total_bitmaps--; 1910
1939 } 1911 info->bytes -= to_free;
1940 kmem_cache_free(btrfs_free_space_cachep, info); 1912 info->offset += to_free;
1941 ret = 0; 1913 if (info->bytes) {
1942 goto out_lock; 1914 ret = link_free_space(ctl, info);
1943 } 1915 WARN_ON(ret);
1944 1916 } else {
1945 if (!info->bitmap && info->offset == offset) { 1917 kmem_cache_free(btrfs_free_space_cachep, info);
1946 unlink_free_space(ctl, info); 1918 }
1947 info->offset += bytes;
1948 info->bytes -= bytes;
1949 ret = link_free_space(ctl, info);
1950 WARN_ON(ret);
1951 goto out_lock;
1952 }
1953 1919
1954 if (!info->bitmap && info->offset <= offset && 1920 offset += to_free;
1955 info->offset + info->bytes >= offset + bytes) { 1921 bytes -= to_free;
1956 u64 old_start = info->offset; 1922 goto again;
1957 /* 1923 } else {
1958 * we're freeing space in the middle of the info, 1924 u64 old_end = info->bytes + info->offset;
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;
1967 1925
1968 info->offset = offset + bytes; 1926 info->bytes = offset - info->offset;
1969 info->bytes = old_end - info->offset;
1970 ret = link_free_space(ctl, info); 1927 ret = link_free_space(ctl, info);
1971 WARN_ON(ret); 1928 WARN_ON(ret);
1972 if (ret) 1929 if (ret)
1973 goto out_lock; 1930 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);
1981 1931
1982 /* step two, insert a new info struct to cover 1932 /* Not enough bytes in this entry to satisfy us */
1983 * anything before the hole 1933 if (old_end < offset + bytes) {
1984 */ 1934 bytes -= old_end - offset;
1985 ret = btrfs_add_free_space(block_group, old_start, 1935 offset = old_end;
1986 offset - old_start); 1936 goto again;
1987 WARN_ON(ret); /* -ENOMEM */ 1937 } else if (old_end == offset + bytes) {
1988 goto out; 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 }
1989 } 1948 }
1990 1949
1991 ret = remove_from_bitmap(ctl, info, &offset, &bytes); 1950 ret = remove_from_bitmap(ctl, info, &offset, &bytes);