aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-22 12:13:20 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-22 12:13:20 -0400
commite20d96d64f9cf9288ffecc9ad4714e91c3b97ca8 (patch)
treefbe07d48bc7997226075169118ffa2a2e63f5d51 /fs/btrfs/extent-tree.c
parent2e635a278354a1a7951e16cfea4c247d6d0e7c99 (diff)
Mountable btrfs, with readdir
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c144
1 files changed, 74 insertions, 70 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 53a7550b5c1e..e3af2c035687 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -10,9 +10,8 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
10 search_end, struct btrfs_key *ins); 10 search_end, struct btrfs_key *ins);
11static int finish_current_insert(struct btrfs_trans_handle *trans, struct 11static int finish_current_insert(struct btrfs_trans_handle *trans, struct
12 btrfs_root *extent_root); 12 btrfs_root *extent_root);
13static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root 13static int del_pending_extents(struct btrfs_trans_handle *trans, struct
14 *extent_root); 14 btrfs_root *extent_root);
15
16/* 15/*
17 * pending extents are blocks that we're trying to allocate in the extent 16 * pending extents are blocks that we're trying to allocate in the extent
18 * map while trying to grow the map because of other allocations. To avoid 17 * map while trying to grow the map because of other allocations. To avoid
@@ -21,6 +20,7 @@ static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root
21 * manner for deletes. 20 * manner for deletes.
22 */ 21 */
23#define CTREE_EXTENT_PENDING_DEL 0 22#define CTREE_EXTENT_PENDING_DEL 0
23#define CTREE_EXTENT_PINNED 1
24 24
25static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root 25static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
26 *root, u64 blocknr) 26 *root, u64 blocknr)
@@ -45,15 +45,14 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
45 if (ret != 0) 45 if (ret != 0)
46 BUG(); 46 BUG();
47 BUG_ON(ret != 0); 47 BUG_ON(ret != 0);
48 l = &path.nodes[0]->leaf; 48 l = btrfs_buffer_leaf(path.nodes[0]);
49 item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item); 49 item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
50 refs = btrfs_extent_refs(item); 50 refs = btrfs_extent_refs(item);
51 btrfs_set_extent_refs(item, refs + 1); 51 btrfs_set_extent_refs(item, refs + 1);
52 52
53 BUG_ON(list_empty(&path.nodes[0]->dirty));
54 btrfs_release_path(root->fs_info->extent_root, &path); 53 btrfs_release_path(root->fs_info->extent_root, &path);
55 finish_current_insert(trans, root->fs_info->extent_root); 54 finish_current_insert(trans, root->fs_info->extent_root);
56 run_pending(trans, root->fs_info->extent_root); 55 del_pending_extents(trans, root->fs_info->extent_root);
57 return 0; 56 return 0;
58} 57}
59 58
@@ -74,7 +73,7 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
74 0, 0); 73 0, 0);
75 if (ret != 0) 74 if (ret != 0)
76 BUG(); 75 BUG();
77 l = &path.nodes[0]->leaf; 76 l = btrfs_buffer_leaf(path.nodes[0]);
78 item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item); 77 item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
79 *refs = btrfs_extent_refs(item); 78 *refs = btrfs_extent_refs(item);
80 btrfs_release_path(root->fs_info->extent_root, &path); 79 btrfs_release_path(root->fs_info->extent_root, &path);
@@ -82,18 +81,20 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
82} 81}
83 82
84int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, 83int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
85 struct btrfs_buffer *buf) 84 struct buffer_head *buf)
86{ 85{
87 u64 blocknr; 86 u64 blocknr;
87 struct btrfs_node *buf_node;
88 int i; 88 int i;
89 89
90 if (!root->ref_cows) 90 if (!root->ref_cows)
91 return 0; 91 return 0;
92 if (btrfs_is_leaf(&buf->node)) 92 buf_node = btrfs_buffer_node(buf);
93 if (btrfs_is_leaf(buf_node))
93 return 0; 94 return 0;
94 95
95 for (i = 0; i < btrfs_header_nritems(&buf->node.header); i++) { 96 for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
96 blocknr = btrfs_node_blockptr(&buf->node, i); 97 blocknr = btrfs_node_blockptr(buf_node, i);
97 inc_block_ref(trans, root, blocknr); 98 inc_block_ref(trans, root, blocknr);
98 } 99 }
99 return 0; 100 return 0;
@@ -108,9 +109,10 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
108 int i; 109 int i;
109 110
110 while(1) { 111 while(1) {
111 ret = radix_tree_gang_lookup(&root->fs_info->pinned_radix, 112 ret = radix_tree_gang_lookup_tag(&root->fs_info->pinned_radix,
112 (void **)gang, 0, 113 (void **)gang, 0,
113 ARRAY_SIZE(gang)); 114 ARRAY_SIZE(gang),
115 CTREE_EXTENT_PINNED);
114 if (!ret) 116 if (!ret)
115 break; 117 break;
116 if (!first) 118 if (!first)
@@ -137,7 +139,7 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
137 139
138 btrfs_set_extent_refs(&extent_item, 1); 140 btrfs_set_extent_refs(&extent_item, 1);
139 btrfs_set_extent_owner(&extent_item, 141 btrfs_set_extent_owner(&extent_item,
140 btrfs_header_parentid(&extent_root->node->node.header)); 142 btrfs_header_parentid(btrfs_buffer_header(extent_root->node)));
141 ins.offset = 1; 143 ins.offset = 1;
142 ins.flags = 0; 144 ins.flags = 0;
143 btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY); 145 btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
@@ -156,11 +158,24 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
156 return 0; 158 return 0;
157} 159}
158 160
161static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag)
162{
163 int err;
164 err = radix_tree_insert(&root->fs_info->pinned_radix,
165 blocknr, (void *)blocknr);
166 BUG_ON(err);
167 if (err)
168 return err;
169 radix_tree_tag_set(&root->fs_info->pinned_radix, blocknr,
170 tag);
171 return 0;
172}
173
159/* 174/*
160 * remove an extent from the root, returns 0 on success 175 * remove an extent from the root, returns 0 on success
161 */ 176 */
162static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root 177static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
163 *root, u64 blocknr, u64 num_blocks, int pin) 178 *root, u64 blocknr, u64 num_blocks)
164{ 179{
165 struct btrfs_path path; 180 struct btrfs_path path;
166 struct btrfs_key key; 181 struct btrfs_key key;
@@ -171,7 +186,6 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
171 struct btrfs_key ins; 186 struct btrfs_key ins;
172 u32 refs; 187 u32 refs;
173 188
174 BUG_ON(pin && num_blocks != 1);
175 key.objectid = blocknr; 189 key.objectid = blocknr;
176 key.flags = 0; 190 key.flags = 0;
177 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); 191 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
@@ -186,26 +200,18 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
186 printk("failed to find %Lu\n", key.objectid); 200 printk("failed to find %Lu\n", key.objectid);
187 BUG(); 201 BUG();
188 } 202 }
189 ei = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], 203 ei = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
190 struct btrfs_extent_item); 204 struct btrfs_extent_item);
191 BUG_ON(ei->refs == 0); 205 BUG_ON(ei->refs == 0);
192 refs = btrfs_extent_refs(ei) - 1; 206 refs = btrfs_extent_refs(ei) - 1;
193 btrfs_set_extent_refs(ei, refs); 207 btrfs_set_extent_refs(ei, refs);
194 if (refs == 0) { 208 if (refs == 0) {
195 u64 super_blocks_used; 209 u64 super_blocks_used;
196 if (pin) {
197 int err;
198 radix_tree_preload(GFP_KERNEL);
199 err = radix_tree_insert(&info->pinned_radix,
200 blocknr, (void *)blocknr);
201 BUG_ON(err);
202 radix_tree_preload_end();
203 }
204 super_blocks_used = btrfs_super_blocks_used(info->disk_super); 210 super_blocks_used = btrfs_super_blocks_used(info->disk_super);
205 btrfs_set_super_blocks_used(info->disk_super, 211 btrfs_set_super_blocks_used(info->disk_super,
206 super_blocks_used - num_blocks); 212 super_blocks_used - num_blocks);
207 ret = btrfs_del_item(trans, extent_root, &path); 213 ret = btrfs_del_item(trans, extent_root, &path);
208 if (!pin && extent_root->fs_info->last_insert.objectid > 214 if (extent_root->fs_info->last_insert.objectid >
209 blocknr) 215 blocknr)
210 extent_root->fs_info->last_insert.objectid = blocknr; 216 extent_root->fs_info->last_insert.objectid = blocknr;
211 if (ret) 217 if (ret)
@@ -224,39 +230,32 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
224 btrfs_root *extent_root) 230 btrfs_root *extent_root)
225{ 231{
226 int ret; 232 int ret;
227 struct btrfs_buffer *gang[4]; 233 int wret;
234 int err = 0;
235 unsigned long gang[4];
228 int i; 236 int i;
237 struct radix_tree_root *radix = &extent_root->fs_info->pinned_radix;
229 238
230 while(1) { 239 while(1) {
231 ret = radix_tree_gang_lookup_tag( 240 ret = radix_tree_gang_lookup_tag(
232 &extent_root->fs_info->cache_radix, 241 &extent_root->fs_info->pinned_radix,
233 (void **)gang, 0, 242 (void **)gang, 0,
234 ARRAY_SIZE(gang), 243 ARRAY_SIZE(gang),
235 CTREE_EXTENT_PENDING_DEL); 244 CTREE_EXTENT_PENDING_DEL);
236 if (!ret) 245 if (!ret)
237 break; 246 break;
238 for (i = 0; i < ret; i++) { 247 for (i = 0; i < ret; i++) {
239 ret = __free_extent(trans, extent_root, 248 radix_tree_tag_set(radix, gang[i], CTREE_EXTENT_PINNED);
240 gang[i]->blocknr, 1, 1); 249 radix_tree_tag_clear(radix, gang[i],
241 radix_tree_tag_clear(&extent_root->fs_info->cache_radix,
242 gang[i]->blocknr,
243 CTREE_EXTENT_PENDING_DEL); 250 CTREE_EXTENT_PENDING_DEL);
244 btrfs_block_release(extent_root, gang[i]); 251 wret = __free_extent(trans, extent_root, gang[i], 1);
252 if (wret)
253 err = wret;
245 } 254 }
246 } 255 }
247 return 0; 256 return err;
248} 257}
249 258
250static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root
251 *extent_root)
252{
253 while(radix_tree_tagged(&extent_root->fs_info->cache_radix,
254 CTREE_EXTENT_PENDING_DEL))
255 del_pending_extents(trans, extent_root);
256 return 0;
257}
258
259
260/* 259/*
261 * remove an extent from the root, returns 0 on success 260 * remove an extent from the root, returns 0 on success
262 */ 261 */
@@ -264,18 +263,21 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
264 *root, u64 blocknr, u64 num_blocks, int pin) 263 *root, u64 blocknr, u64 num_blocks, int pin)
265{ 264{
266 struct btrfs_root *extent_root = root->fs_info->extent_root; 265 struct btrfs_root *extent_root = root->fs_info->extent_root;
267 struct btrfs_buffer *t; 266 struct buffer_head *t;
268 int pending_ret; 267 int pending_ret;
269 int ret; 268 int ret;
270 269
271 if (root == extent_root) { 270 if (root == extent_root) {
272 t = find_tree_block(root, blocknr); 271 t = find_tree_block(root, blocknr);
273 radix_tree_tag_set(&root->fs_info->cache_radix, blocknr, 272 pin_down_block(root, blocknr, CTREE_EXTENT_PENDING_DEL);
274 CTREE_EXTENT_PENDING_DEL);
275 return 0; 273 return 0;
276 } 274 }
277 ret = __free_extent(trans, root, blocknr, num_blocks, pin); 275 if (pin) {
278 pending_ret = run_pending(trans, root->fs_info->extent_root); 276 ret = pin_down_block(root, blocknr, CTREE_EXTENT_PINNED);
277 BUG_ON(ret);
278 }
279 ret = __free_extent(trans, root, blocknr, num_blocks);
280 pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
279 return ret ? ret : pending_ret; 281 return ret ? ret : pending_ret;
280} 282}
281 283
@@ -296,14 +298,16 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
296 int ret; 298 int ret;
297 u64 hole_size = 0; 299 u64 hole_size = 0;
298 int slot = 0; 300 int slot = 0;
299 u64 last_block; 301 u64 last_block = 0;
300 u64 test_block; 302 u64 test_block;
301 int start_found; 303 int start_found;
302 struct btrfs_leaf *l; 304 struct btrfs_leaf *l;
303 struct btrfs_root * root = orig_root->fs_info->extent_root; 305 struct btrfs_root * root = orig_root->fs_info->extent_root;
304 int total_needed = num_blocks; 306 int total_needed = num_blocks;
307 int level;
305 308
306 total_needed += (btrfs_header_level(&root->node->node.header) + 1) * 3; 309 level = btrfs_header_level(btrfs_buffer_header(root->node));
310 total_needed += (level + 1) * 3;
307 if (root->fs_info->last_insert.objectid > search_start) 311 if (root->fs_info->last_insert.objectid > search_start)
308 search_start = root->fs_info->last_insert.objectid; 312 search_start = root->fs_info->last_insert.objectid;
309 313
@@ -323,7 +327,7 @@ check_failed:
323 path.slots[0]--; 327 path.slots[0]--;
324 328
325 while (1) { 329 while (1) {
326 l = &path.nodes[0]->leaf; 330 l = btrfs_buffer_leaf(path.nodes[0]);
327 slot = path.slots[0]; 331 slot = path.slots[0];
328 if (slot >= btrfs_header_nritems(&l->header)) { 332 if (slot >= btrfs_header_nritems(&l->header)) {
329 ret = btrfs_next_leaf(root, &path); 333 ret = btrfs_next_leaf(root, &path);
@@ -429,7 +433,7 @@ static int alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
429 sizeof(extent_item)); 433 sizeof(extent_item));
430 434
431 finish_current_insert(trans, extent_root); 435 finish_current_insert(trans, extent_root);
432 pending_ret = run_pending(trans, extent_root); 436 pending_ret = del_pending_extents(trans, extent_root);
433 if (ret) 437 if (ret)
434 return ret; 438 return ret;
435 if (pending_ret) 439 if (pending_ret)
@@ -441,16 +445,15 @@ static int alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
441 * helper function to allocate a block for a given tree 445 * helper function to allocate a block for a given tree
442 * returns the tree buffer or NULL. 446 * returns the tree buffer or NULL.
443 */ 447 */
444struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, 448struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
445 struct btrfs_root *root) 449 struct btrfs_root *root)
446{ 450{
447 struct btrfs_key ins; 451 struct btrfs_key ins;
448 int ret; 452 int ret;
449 struct btrfs_buffer *buf; 453 struct buffer_head *buf;
450 454
451 ret = alloc_extent(trans, root, 1, 0, (unsigned long)-1, 455 ret = alloc_extent(trans, root, 1, 0, (unsigned long)-1,
452 btrfs_header_parentid(&root->node->node.header), 456 btrfs_header_parentid(btrfs_buffer_header(root->node)), &ins);
453 &ins);
454 if (ret) { 457 if (ret) {
455 BUG(); 458 BUG();
456 return NULL; 459 return NULL;
@@ -467,13 +470,13 @@ struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
467static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root 470static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
468 *root, struct btrfs_path *path, int *level) 471 *root, struct btrfs_path *path, int *level)
469{ 472{
470 struct btrfs_buffer *next; 473 struct buffer_head *next;
471 struct btrfs_buffer *cur; 474 struct buffer_head *cur;
472 u64 blocknr; 475 u64 blocknr;
473 int ret; 476 int ret;
474 u32 refs; 477 u32 refs;
475 478
476 ret = lookup_block_ref(trans, root, path->nodes[*level]->blocknr, 479 ret = lookup_block_ref(trans, root, path->nodes[*level]->b_blocknr,
477 &refs); 480 &refs);
478 BUG_ON(ret); 481 BUG_ON(ret);
479 if (refs > 1) 482 if (refs > 1)
@@ -484,9 +487,10 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
484 while(*level > 0) { 487 while(*level > 0) {
485 cur = path->nodes[*level]; 488 cur = path->nodes[*level];
486 if (path->slots[*level] >= 489 if (path->slots[*level] >=
487 btrfs_header_nritems(&cur->node.header)) 490 btrfs_header_nritems(btrfs_buffer_header(cur)))
488 break; 491 break;
489 blocknr = btrfs_node_blockptr(&cur->node, path->slots[*level]); 492 blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur),
493 path->slots[*level]);
490 ret = lookup_block_ref(trans, root, blocknr, &refs); 494 ret = lookup_block_ref(trans, root, blocknr, &refs);
491 if (refs != 1 || *level == 1) { 495 if (refs != 1 || *level == 1) {
492 path->slots[*level]++; 496 path->slots[*level]++;
@@ -499,12 +503,12 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
499 if (path->nodes[*level-1]) 503 if (path->nodes[*level-1])
500 btrfs_block_release(root, path->nodes[*level-1]); 504 btrfs_block_release(root, path->nodes[*level-1]);
501 path->nodes[*level-1] = next; 505 path->nodes[*level-1] = next;
502 *level = btrfs_header_level(&next->node.header); 506 *level = btrfs_header_level(btrfs_buffer_header(next));
503 path->slots[*level] = 0; 507 path->slots[*level] = 0;
504 } 508 }
505out: 509out:
506 ret = btrfs_free_extent(trans, root, path->nodes[*level]->blocknr, 1, 510 ret = btrfs_free_extent(trans, root, path->nodes[*level]->b_blocknr,
507 1); 511 1, 1);
508 btrfs_block_release(root, path->nodes[*level]); 512 btrfs_block_release(root, path->nodes[*level]);
509 path->nodes[*level] = NULL; 513 path->nodes[*level] = NULL;
510 *level += 1; 514 *level += 1;
@@ -525,14 +529,14 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
525 int ret; 529 int ret;
526 for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { 530 for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
527 slot = path->slots[i]; 531 slot = path->slots[i];
528 if (slot < 532 if (slot < btrfs_header_nritems(
529 btrfs_header_nritems(&path->nodes[i]->node.header)- 1) { 533 btrfs_buffer_header(path->nodes[i])) - 1) {
530 path->slots[i]++; 534 path->slots[i]++;
531 *level = i; 535 *level = i;
532 return 0; 536 return 0;
533 } else { 537 } else {
534 ret = btrfs_free_extent(trans, root, 538 ret = btrfs_free_extent(trans, root,
535 path->nodes[*level]->blocknr, 539 path->nodes[*level]->b_blocknr,
536 1, 1); 540 1, 1);
537 btrfs_block_release(root, path->nodes[*level]); 541 btrfs_block_release(root, path->nodes[*level]);
538 path->nodes[*level] = NULL; 542 path->nodes[*level] = NULL;
@@ -549,7 +553,7 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
549 * decremented. 553 * decremented.
550 */ 554 */
551int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root 555int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
552 *root, struct btrfs_buffer *snap) 556 *root, struct buffer_head *snap)
553{ 557{
554 int ret = 0; 558 int ret = 0;
555 int wret; 559 int wret;
@@ -560,7 +564,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
560 564
561 btrfs_init_path(&path); 565 btrfs_init_path(&path);
562 566
563 level = btrfs_header_level(&snap->node.header); 567 level = btrfs_header_level(btrfs_buffer_header(snap));
564 orig_level = level; 568 orig_level = level;
565 path.nodes[level] = snap; 569 path.nodes[level] = snap;
566 path.slots[level] = 0; 570 path.slots[level] = 0;