aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-04-04 14:08:15 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-04-04 14:08:15 -0400
commitd4dbff953e1f6f4079126c0404cc24f2ef14e925 (patch)
tree293d3fbe74ce991dbd1dc07ef4b9a97ff0337546 /fs/btrfs/ctree.c
parentdf24a2b9c9bcef3348e4b1a8f206cd484a248d36 (diff)
Btrfs: support for items bigger than 1/2 the blocksize
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c132
1 files changed, 97 insertions, 35 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 9ef65e2ecf51..864ee423b300 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -6,7 +6,8 @@
6static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root 6static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
7 *root, struct btrfs_path *path, int level); 7 *root, struct btrfs_path *path, int level);
8static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root 8static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
9 *root, struct btrfs_path *path, int data_size); 9 *root, struct btrfs_key *ins_key,
10 struct btrfs_path *path, int data_size);
10static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root 11static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root
11 *root, struct buffer_head *dst, struct buffer_head 12 *root, struct buffer_head *dst, struct buffer_head
12 *src); 13 *src);
@@ -102,19 +103,6 @@ static inline unsigned int leaf_data_end(struct btrfs_root *root,
102} 103}
103 104
104/* 105/*
105 * The space between the end of the leaf items and
106 * the start of the leaf data. IOW, how much room
107 * the leaf has left for both items and data
108 */
109int btrfs_leaf_free_space(struct btrfs_root *root, struct btrfs_leaf *leaf)
110{
111 int data_end = leaf_data_end(root, leaf);
112 int nritems = btrfs_header_nritems(&leaf->header);
113 char *items_end = (char *)(leaf->items + nritems + 1);
114 return (char *)(btrfs_leaf_data(leaf) + data_end) - (char *)items_end;
115}
116
117/*
118 * compare two keys in a memcmp fashion 106 * compare two keys in a memcmp fashion
119 */ 107 */
120static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2) 108static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2)
@@ -510,8 +498,8 @@ again:
510 if (ret && slot > 0) 498 if (ret && slot > 0)
511 slot -= 1; 499 slot -= 1;
512 p->slots[level] = slot; 500 p->slots[level] = slot;
513 if (ins_len > 0 && btrfs_header_nritems(&c->header) == 501 if (ins_len > 0 && btrfs_header_nritems(&c->header) >=
514 BTRFS_NODEPTRS_PER_BLOCK(root)) { 502 BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
515 int sret = split_node(trans, root, p, level); 503 int sret = split_node(trans, root, p, level);
516 BUG_ON(sret > 0); 504 BUG_ON(sret > 0);
517 if (sret) 505 if (sret)
@@ -537,7 +525,8 @@ again:
537 p->slots[level] = slot; 525 p->slots[level] = slot;
538 if (ins_len > 0 && btrfs_leaf_free_space(root, l) < 526 if (ins_len > 0 && btrfs_leaf_free_space(root, l) <
539 sizeof(struct btrfs_item) + ins_len) { 527 sizeof(struct btrfs_item) + ins_len) {
540 int sret = split_leaf(trans, root, p, ins_len); 528 int sret = split_leaf(trans, root, key,
529 p, ins_len);
541 BUG_ON(sret > 0); 530 BUG_ON(sret > 0);
542 if (sret) 531 if (sret)
543 return sret; 532 return sret;
@@ -825,17 +814,30 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
825static int leaf_space_used(struct btrfs_leaf *l, int start, int nr) 814static int leaf_space_used(struct btrfs_leaf *l, int start, int nr)
826{ 815{
827 int data_len; 816 int data_len;
828 int end = start + nr - 1; 817 int nritems = btrfs_header_nritems(&l->header);
818 int end = min(nritems, start + nr) - 1;
829 819
830 if (!nr) 820 if (!nr)
831 return 0; 821 return 0;
832 data_len = btrfs_item_end(l->items + start); 822 data_len = btrfs_item_end(l->items + start);
833 data_len = data_len - btrfs_item_offset(l->items + end); 823 data_len = data_len - btrfs_item_offset(l->items + end);
834 data_len += sizeof(struct btrfs_item) * nr; 824 data_len += sizeof(struct btrfs_item) * nr;
825 WARN_ON(data_len < 0);
835 return data_len; 826 return data_len;
836} 827}
837 828
838/* 829/*
830 * The space between the end of the leaf items and
831 * the start of the leaf data. IOW, how much room
832 * the leaf has left for both items and data
833 */
834int btrfs_leaf_free_space(struct btrfs_root *root, struct btrfs_leaf *leaf)
835{
836 int nritems = btrfs_header_nritems(&leaf->header);
837 return BTRFS_LEAF_DATA_SIZE(root) - leaf_space_used(leaf, 0, nritems);
838}
839
840/*
839 * push some data in the path leaf to the right, trying to free up at 841 * push some data in the path leaf to the right, trying to free up at
840 * least data_size bytes. returns zero if the push worked, nonzero otherwise 842 * least data_size bytes. returns zero if the push worked, nonzero otherwise
841 * 843 *
@@ -1084,7 +1086,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
1084 * returns 0 if all went well and < 0 on failure. 1086 * returns 0 if all went well and < 0 on failure.
1085 */ 1087 */
1086static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root 1088static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1087 *root, struct btrfs_path *path, int data_size) 1089 *root, struct btrfs_key *ins_key,
1090 struct btrfs_path *path, int data_size)
1088{ 1091{
1089 struct buffer_head *l_buf; 1092 struct buffer_head *l_buf;
1090 struct btrfs_leaf *l; 1093 struct btrfs_leaf *l;
@@ -1097,8 +1100,10 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1097 int data_copy_size; 1100 int data_copy_size;
1098 int rt_data_off; 1101 int rt_data_off;
1099 int i; 1102 int i;
1100 int ret; 1103 int ret = 0;
1101 int wret; 1104 int wret;
1105 int double_split = 0;
1106 struct btrfs_disk_key disk_key;
1102 1107
1103 /* first try to make some room by pushing left and right */ 1108 /* first try to make some room by pushing left and right */
1104 wret = push_leaf_left(trans, root, path, data_size); 1109 wret = push_leaf_left(trans, root, path, data_size);
@@ -1127,26 +1132,58 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1127 mid = (nritems + 1)/ 2; 1132 mid = (nritems + 1)/ 2;
1128 right_buffer = btrfs_alloc_free_block(trans, root); 1133 right_buffer = btrfs_alloc_free_block(trans, root);
1129 BUG_ON(!right_buffer); 1134 BUG_ON(!right_buffer);
1130 BUG_ON(mid == nritems);
1131 right = btrfs_buffer_leaf(right_buffer); 1135 right = btrfs_buffer_leaf(right_buffer);
1132 memset(&right->header, 0, sizeof(right->header)); 1136 memset(&right->header, 0, sizeof(right->header));
1133 if (mid <= slot) {
1134 /* FIXME, just alloc a new leaf here */
1135 if (leaf_space_used(l, mid, nritems - mid) + space_needed >
1136 BTRFS_LEAF_DATA_SIZE(root))
1137 BUG();
1138 } else {
1139 /* FIXME, just alloc a new leaf here */
1140 if (leaf_space_used(l, 0, mid + 1) + space_needed >
1141 BTRFS_LEAF_DATA_SIZE(root))
1142 BUG();
1143 }
1144 btrfs_set_header_nritems(&right->header, nritems - mid);
1145 btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr); 1137 btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr);
1146 btrfs_set_header_generation(&right->header, trans->transid); 1138 btrfs_set_header_generation(&right->header, trans->transid);
1147 btrfs_set_header_level(&right->header, 0); 1139 btrfs_set_header_level(&right->header, 0);
1148 btrfs_set_header_parentid(&right->header, 1140 btrfs_set_header_parentid(&right->header,
1149 btrfs_header_parentid(btrfs_buffer_header(root->node))); 1141 btrfs_header_parentid(btrfs_buffer_header(root->node)));
1142 if (mid <= slot) {
1143 if (nritems == 1 ||
1144 leaf_space_used(l, mid, nritems - mid) + space_needed >
1145 BTRFS_LEAF_DATA_SIZE(root)) {
1146 if (slot >= nritems) {
1147 btrfs_cpu_key_to_disk(&disk_key, ins_key);
1148 btrfs_set_header_nritems(&right->header, 0);
1149 wret = insert_ptr(trans, root, path,
1150 &disk_key,
1151 right_buffer->b_blocknr,
1152 path->slots[1] + 1, 1);
1153 if (wret)
1154 ret = wret;
1155 btrfs_block_release(root, path->nodes[0]);
1156 path->nodes[0] = right_buffer;
1157 path->slots[0] = 0;
1158 path->slots[1] += 1;
1159 return ret;
1160 }
1161 mid = slot;
1162 double_split = 1;
1163 }
1164 } else {
1165 if (leaf_space_used(l, 0, mid + 1) + space_needed >
1166 BTRFS_LEAF_DATA_SIZE(root)) {
1167 if (slot == 0) {
1168 btrfs_cpu_key_to_disk(&disk_key, ins_key);
1169 btrfs_set_header_nritems(&right->header, 0);
1170 wret = insert_ptr(trans, root, path,
1171 &disk_key,
1172 right_buffer->b_blocknr,
1173 path->slots[1] - 1, 1);
1174 if (wret)
1175 ret = wret;
1176 btrfs_block_release(root, path->nodes[0]);
1177 path->nodes[0] = right_buffer;
1178 path->slots[0] = 0;
1179 path->slots[1] -= 1;
1180 return ret;
1181 }
1182 mid = slot;
1183 double_split = 1;
1184 }
1185 }
1186 btrfs_set_header_nritems(&right->header, nritems - mid);
1150 data_copy_size = btrfs_item_end(l->items + mid) - 1187 data_copy_size = btrfs_item_end(l->items + mid) -
1151 leaf_data_end(root, l); 1188 leaf_data_end(root, l);
1152 btrfs_memcpy(root, right, right->items, l->items + mid, 1189 btrfs_memcpy(root, right, right->items, l->items + mid,
@@ -1180,6 +1217,31 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
1180 } else 1217 } else
1181 btrfs_block_release(root, right_buffer); 1218 btrfs_block_release(root, right_buffer);
1182 BUG_ON(path->slots[0] < 0); 1219 BUG_ON(path->slots[0] < 0);
1220
1221 if (!double_split)
1222 return ret;
1223 right_buffer = btrfs_alloc_free_block(trans, root);
1224 BUG_ON(!right_buffer);
1225 right = btrfs_buffer_leaf(right_buffer);
1226 memset(&right->header, 0, sizeof(right->header));
1227 btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr);
1228 btrfs_set_header_generation(&right->header, trans->transid);
1229 btrfs_set_header_level(&right->header, 0);
1230 btrfs_set_header_parentid(&right->header,
1231 btrfs_header_parentid(btrfs_buffer_header(root->node)));
1232 btrfs_cpu_key_to_disk(&disk_key, ins_key);
1233 btrfs_set_header_nritems(&right->header, 0);
1234 wret = insert_ptr(trans, root, path,
1235 &disk_key,
1236 right_buffer->b_blocknr,
1237 path->slots[1], 1);
1238 if (wret)
1239 ret = wret;
1240 btrfs_block_release(root, path->nodes[0]);
1241 path->nodes[0] = right_buffer;
1242 path->slots[0] = 0;
1243 check_node(root, path, 1);
1244 check_leaf(root, path, 0);
1183 return ret; 1245 return ret;
1184} 1246}
1185 1247
@@ -1220,9 +1282,9 @@ int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root
1220 data_end = leaf_data_end(root, leaf); 1282 data_end = leaf_data_end(root, leaf);
1221 1283
1222 if (btrfs_leaf_free_space(root, leaf) < 1284 if (btrfs_leaf_free_space(root, leaf) <
1223 sizeof(struct btrfs_item) + data_size) 1285 sizeof(struct btrfs_item) + data_size) {
1224 BUG(); 1286 BUG();
1225 1287 }
1226 slot = path->slots[0]; 1288 slot = path->slots[0];
1227 BUG_ON(slot < 0); 1289 BUG_ON(slot < 0);
1228 if (slot != nritems) { 1290 if (slot != nritems) {