aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-10-25 15:42:57 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:57 -0400
commitcc0c55384796b422133ff1f21646835b31590f88 (patch)
tree152933613a431cce89a5cdcd0c5761688f8e5124 /fs/btrfs/ctree.c
parent65555a06b4d1ae116ce223dc4b82d6068b36df96 (diff)
Btrfs: Fix split_leaf to detect when it is extending an item
When making room for a new item, it is ok to create an empty leaf, but when making room to extend an item, split_leaf needs to make sure it keeps the item we're extending in the path and make sure we don't end up with an empty leaf. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c78
1 files changed, 27 insertions, 51 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 53e40b5c084d..3eb5a9f30d14 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -26,7 +26,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
26 *root, struct btrfs_path *path, int level); 26 *root, struct btrfs_path *path, int level);
27static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root 27static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
28 *root, struct btrfs_key *ins_key, 28 *root, struct btrfs_key *ins_key,
29 struct btrfs_path *path, int data_size); 29 struct btrfs_path *path, int data_size, int extend);
30static int push_node_left(struct btrfs_trans_handle *trans, 30static int push_node_left(struct btrfs_trans_handle *trans,
31 struct btrfs_root *root, struct extent_buffer *dst, 31 struct btrfs_root *root, struct extent_buffer *dst,
32 struct extent_buffer *src); 32 struct extent_buffer *src);
@@ -1049,7 +1049,7 @@ again:
1049 if (ins_len > 0 && btrfs_leaf_free_space(root, b) < 1049 if (ins_len > 0 && btrfs_leaf_free_space(root, b) <
1050 sizeof(struct btrfs_item) + ins_len) { 1050 sizeof(struct btrfs_item) + ins_len) {
1051 int sret = split_leaf(trans, root, key, 1051 int sret = split_leaf(trans, root, key,
1052 p, ins_len); 1052 p, ins_len, ret == 0);
1053 BUG_ON(sret > 0); 1053 BUG_ON(sret > 0);
1054 if (sret) 1054 if (sret)
1055 return sret; 1055 return sret;
@@ -1755,7 +1755,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
1755 */ 1755 */
1756static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root 1756static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1757 *root, struct btrfs_key *ins_key, 1757 *root, struct btrfs_key *ins_key,
1758 struct btrfs_path *path, int data_size) 1758 struct btrfs_path *path, int data_size, int extend)
1759{ 1759{
1760 struct extent_buffer *l; 1760 struct extent_buffer *l;
1761 u32 nritems; 1761 u32 nritems;
@@ -1768,9 +1768,13 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1768 int i; 1768 int i;
1769 int ret = 0; 1769 int ret = 0;
1770 int wret; 1770 int wret;
1771 int double_split = 0; 1771 int double_split;
1772 int num_doubles = 0;
1772 struct btrfs_disk_key disk_key; 1773 struct btrfs_disk_key disk_key;
1773 1774
1775 if (extend)
1776 space_needed = data_size;
1777
1774 /* first try to make some room by pushing left and right */ 1778 /* first try to make some room by pushing left and right */
1775 if (ins_key->type != BTRFS_DIR_ITEM_KEY) { 1779 if (ins_key->type != BTRFS_DIR_ITEM_KEY) {
1776 wret = push_leaf_right(trans, root, path, data_size); 1780 wret = push_leaf_right(trans, root, path, data_size);
@@ -1785,12 +1789,8 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1785 l = path->nodes[0]; 1789 l = path->nodes[0];
1786 1790
1787 /* did the pushes work? */ 1791 /* did the pushes work? */
1788 if (btrfs_leaf_free_space(root, l) >= 1792 if (btrfs_leaf_free_space(root, l) >= space_needed)
1789 sizeof(struct btrfs_item) + data_size) {
1790 return 0; 1793 return 0;
1791 }
1792 } else {
1793 l = path->nodes[0];
1794 } 1794 }
1795 1795
1796 if (!path->nodes[1]) { 1796 if (!path->nodes[1]) {
@@ -1798,6 +1798,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1798 if (ret) 1798 if (ret)
1799 return ret; 1799 return ret;
1800 } 1800 }
1801again:
1802 double_split = 0;
1803 l = path->nodes[0];
1801 slot = path->slots[0]; 1804 slot = path->slots[0];
1802 nritems = btrfs_header_nritems(l); 1805 nritems = btrfs_header_nritems(l);
1803 mid = (nritems + 1)/ 2; 1806 mid = (nritems + 1)/ 2;
@@ -1815,7 +1818,6 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1815 write_extent_buffer(right, root->fs_info->fsid, 1818 write_extent_buffer(right, root->fs_info->fsid,
1816 (unsigned long)btrfs_header_fsid(right), 1819 (unsigned long)btrfs_header_fsid(right),
1817 BTRFS_FSID_SIZE); 1820 BTRFS_FSID_SIZE);
1818
1819 if (mid <= slot) { 1821 if (mid <= slot) {
1820 if (nritems == 1 || 1822 if (nritems == 1 ||
1821 leaf_space_used(l, mid, nritems - mid) + space_needed > 1823 leaf_space_used(l, mid, nritems - mid) + space_needed >
@@ -1844,7 +1846,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1844 } else { 1846 } else {
1845 if (leaf_space_used(l, 0, mid + 1) + space_needed > 1847 if (leaf_space_used(l, 0, mid + 1) + space_needed >
1846 BTRFS_LEAF_DATA_SIZE(root)) { 1848 BTRFS_LEAF_DATA_SIZE(root)) {
1847 if (slot == 0) { 1849 if (!extend && slot == 0) {
1848 btrfs_cpu_key_to_disk(&disk_key, ins_key); 1850 btrfs_cpu_key_to_disk(&disk_key, ins_key);
1849 btrfs_set_header_nritems(right, 0); 1851 btrfs_set_header_nritems(right, 0);
1850 wret = insert_ptr(trans, root, path, 1852 wret = insert_ptr(trans, root, path,
@@ -1863,12 +1865,15 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1863 ret = wret; 1865 ret = wret;
1864 } 1866 }
1865 return ret; 1867 return ret;
1866 } 1868 } else if (extend && slot == 0) {
1867 mid = slot; 1869 mid = 1;
1868 if (mid != nritems && 1870 } else {
1869 leaf_space_used(l, mid, nritems - mid) + 1871 mid = slot;
1870 space_needed > BTRFS_LEAF_DATA_SIZE(root)) { 1872 if (mid != nritems &&
1871 double_split = 1; 1873 leaf_space_used(l, mid, nritems - mid) +
1874 space_needed > BTRFS_LEAF_DATA_SIZE(root)) {
1875 double_split = 1;
1876 }
1872 } 1877 }
1873 } 1878 }
1874 } 1879 }
@@ -1931,39 +1936,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1931 1936
1932 BUG_ON(path->slots[0] < 0); 1937 BUG_ON(path->slots[0] < 0);
1933 1938
1934 if (!double_split) { 1939 if (double_split) {
1935 return ret; 1940 BUG_ON(num_doubles != 0);
1936 } 1941 num_doubles++;
1937 1942 goto again;
1938 right = btrfs_alloc_free_block(trans, root, root->leafsize,
1939 l->start, 0);
1940 if (IS_ERR(right))
1941 return PTR_ERR(right);
1942
1943 memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
1944 btrfs_set_header_bytenr(right, right->start);
1945 btrfs_set_header_generation(right, trans->transid);
1946 btrfs_set_header_owner(right, root->root_key.objectid);
1947 btrfs_set_header_level(right, 0);
1948 write_extent_buffer(right, root->fs_info->fsid,
1949 (unsigned long)btrfs_header_fsid(right),
1950 BTRFS_FSID_SIZE);
1951
1952 btrfs_cpu_key_to_disk(&disk_key, ins_key);
1953 btrfs_set_header_nritems(right, 0);
1954 wret = insert_ptr(trans, root, path,
1955 &disk_key, right->start,
1956 path->slots[1], 1);
1957 if (wret)
1958 ret = wret;
1959 if (path->slots[1] == 0) {
1960 wret = fixup_low_keys(trans, root, path, &disk_key, 1);
1961 if (wret)
1962 ret = wret;
1963 } 1943 }
1964 free_extent_buffer(path->nodes[0]);
1965 path->nodes[0] = right;
1966 path->slots[0] = 0;
1967 return ret; 1944 return ret;
1968} 1945}
1969 1946
@@ -1992,8 +1969,7 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
1992 1969
1993 slot = path->slots[0]; 1970 slot = path->slots[0];
1994 old_data_start = btrfs_item_offset_nr(leaf, slot); 1971 old_data_start = btrfs_item_offset_nr(leaf, slot);
1995 old_size = btrfs_item_size_nr(leaf, slot); 1972 old_size = btrfs_item_size_nr(leaf, slot); BUG_ON(old_size <= new_size);
1996 BUG_ON(old_size <= new_size);
1997 size_diff = old_size - new_size; 1973 size_diff = old_size - new_size;
1998 1974
1999 BUG_ON(slot < 0); 1975 BUG_ON(slot < 0);