extent-tree.c 24.3 KB
Newer Older
1
#include <linux/module.h>
2 3 4
#include "ctree.h"
#include "disk-io.h"
#include "print-tree.h"
5
#include "transaction.h"
6

7 8 9 10 11
static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
			    *orig_root, u64 num_blocks, u64 search_start, u64
			    search_end, struct btrfs_key *ins);
static int finish_current_insert(struct btrfs_trans_handle *trans, struct
				 btrfs_root *extent_root);
C
Chris Mason 已提交
12 13
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
			       btrfs_root *extent_root);
14

C
Chris Mason 已提交
15 16 17
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
				struct btrfs_root *root,
				u64 blocknr, u64 num_blocks)
C
Chris Mason 已提交
18
{
19
	struct btrfs_path *path;
C
Chris Mason 已提交
20
	int ret;
C
Chris Mason 已提交
21
	struct btrfs_key key;
C
Chris Mason 已提交
22 23
	struct btrfs_leaf *l;
	struct btrfs_extent_item *item;
C
Chris Mason 已提交
24
	struct btrfs_key ins;
C
Chris Mason 已提交
25
	u32 refs;
C
Chris Mason 已提交
26

27 28
	find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1,
			 &ins);
29 30 31
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
C
Chris Mason 已提交
32 33
	key.objectid = blocknr;
	key.flags = 0;
34
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
35
	key.offset = num_blocks;
36
	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
37
				0, 1);
38 39
	if (ret != 0) {
printk("can't find block %Lu %Lu\n", blocknr, num_blocks);
40
		BUG();
41
	}
C
Chris Mason 已提交
42
	BUG_ON(ret != 0);
43 44
	l = btrfs_buffer_leaf(path->nodes[0]);
	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
C
Chris Mason 已提交
45 46
	refs = btrfs_extent_refs(item);
	btrfs_set_extent_refs(item, refs + 1);
47
	btrfs_mark_buffer_dirty(path->nodes[0]);
48

49 50
	btrfs_release_path(root->fs_info->extent_root, path);
	btrfs_free_path(path);
51
	finish_current_insert(trans, root->fs_info->extent_root);
C
Chris Mason 已提交
52
	del_pending_extents(trans, root->fs_info->extent_root);
C
Chris Mason 已提交
53 54 55
	return 0;
}

C
Chris Mason 已提交
56 57 58
static int lookup_extent_ref(struct btrfs_trans_handle *trans,
			     struct btrfs_root *root, u64 blocknr,
			     u64 num_blocks, u32 *refs)
59
{
60
	struct btrfs_path *path;
61
	int ret;
C
Chris Mason 已提交
62
	struct btrfs_key key;
C
Chris Mason 已提交
63 64
	struct btrfs_leaf *l;
	struct btrfs_extent_item *item;
65 66 67

	path = btrfs_alloc_path();
	btrfs_init_path(path);
68
	key.objectid = blocknr;
69
	key.offset = num_blocks;
70 71
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
72
	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
73
				0, 0);
74 75
	if (ret != 0)
		BUG();
76 77
	l = btrfs_buffer_leaf(path->nodes[0]);
	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
C
Chris Mason 已提交
78
	*refs = btrfs_extent_refs(item);
79 80
	btrfs_release_path(root->fs_info->extent_root, path);
	btrfs_free_path(path);
81 82 83
	return 0;
}

C
Chris Mason 已提交
84 85 86
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *root)
{
C
Chris Mason 已提交
87
	return btrfs_inc_extent_ref(trans, root, bh_blocknr(root->node), 1);
C
Chris Mason 已提交
88 89
}

90
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
C
Chris Mason 已提交
91
		  struct buffer_head *buf)
C
Chris Mason 已提交
92 93
{
	u64 blocknr;
C
Chris Mason 已提交
94
	struct btrfs_node *buf_node;
95 96 97
	struct btrfs_leaf *buf_leaf;
	struct btrfs_disk_key *key;
	struct btrfs_file_extent_item *fi;
C
Chris Mason 已提交
98
	int i;
99 100
	int leaf;
	int ret;
101

102
	if (!root->ref_cows)
103
		return 0;
C
Chris Mason 已提交
104
	buf_node = btrfs_buffer_node(buf);
105 106
	leaf = btrfs_is_leaf(buf_node);
	buf_leaf = btrfs_buffer_leaf(buf);
C
Chris Mason 已提交
107
	for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
108 109 110 111 112 113
		if (leaf) {
			key = &buf_leaf->items[i].key;
			if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
				continue;
			fi = btrfs_item_ptr(buf_leaf, i,
					    struct btrfs_file_extent_item);
114 115 116
			if (btrfs_file_extent_type(fi) ==
			    BTRFS_FILE_EXTENT_INLINE)
				continue;
C
Chris Mason 已提交
117
			ret = btrfs_inc_extent_ref(trans, root,
118 119 120 121 122
				    btrfs_file_extent_disk_blocknr(fi),
				    btrfs_file_extent_disk_num_blocks(fi));
			BUG_ON(ret);
		} else {
			blocknr = btrfs_node_blockptr(buf_node, i);
C
Chris Mason 已提交
123
			ret = btrfs_inc_extent_ref(trans, root, blocknr, 1);
124 125
			BUG_ON(ret);
		}
C
Chris Mason 已提交
126 127 128 129
	}
	return 0;
}

C
Chris Mason 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
static int write_one_cache_group(struct btrfs_trans_handle *trans,
				 struct btrfs_root *root,
				 struct btrfs_path *path,
				 struct btrfs_block_group_cache *cache)
{
	int ret;
	int pending_ret;
	struct btrfs_root *extent_root = root->fs_info->extent_root;
	struct btrfs_block_group_item *bi;
	struct btrfs_key ins;

	find_free_extent(trans, extent_root, 0, 0, (u64)-1, &ins);
	ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);
	BUG_ON(ret);
	bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
			    struct btrfs_block_group_item);
	memcpy(bi, &cache->item, sizeof(*bi));
	mark_buffer_dirty(path->nodes[0]);
	btrfs_release_path(extent_root, path);

	finish_current_insert(trans, extent_root);
	pending_ret = del_pending_extents(trans, extent_root);
	if (ret)
		return ret;
	if (pending_ret)
		return pending_ret;
	return 0;

}

int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
				    struct btrfs_root *root)
{
	struct btrfs_block_group_cache *cache[8];
	int ret;
	int err = 0;
	int werr = 0;
	struct radix_tree_root *radix = &root->fs_info->block_group_radix;
	int i;
	struct btrfs_path *path;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;

	while(1) {
		ret = radix_tree_gang_lookup_tag(radix, (void **)cache,
						 0, ARRAY_SIZE(cache),
						 BTRFS_BLOCK_GROUP_DIRTY);
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
			radix_tree_tag_clear(radix, cache[i]->key.objectid +
					     cache[i]->key.offset - 1,
					     BTRFS_BLOCK_GROUP_DIRTY);
			err = write_one_cache_group(trans, root,
						    path, cache[i]);
			if (err)
				werr = err;
		}
	}
	btrfs_free_path(path);
	return werr;
}

static int update_block_group(struct btrfs_trans_handle *trans,
			      struct btrfs_root *root,
			      u64 blocknr, u64 num, int alloc)
{
	struct btrfs_block_group_cache *cache;
	struct btrfs_fs_info *info = root->fs_info;
	u64 total = num;
	u64 old_val;
	u64 block_in_group;
	int ret;
	while(total) {
		ret = radix_tree_gang_lookup(&info->block_group_radix,
					     (void **)&cache, blocknr, 1);
		if (!ret)
			return -1;
		block_in_group = blocknr - cache->key.objectid;
		WARN_ON(block_in_group > cache->key.offset);
		radix_tree_tag_set(&info->block_group_radix,
				   cache->key.objectid + cache->key.offset - 1,
				   BTRFS_BLOCK_GROUP_DIRTY);

		old_val = btrfs_block_group_used(&cache->item);
		num = min(total, cache->key.offset - block_in_group);
		total -= num;
		blocknr += num;
		if (alloc)
			old_val += num;
		else
			old_val -= num;
		btrfs_set_block_group_used(&cache->item, old_val);
	}
	return 0;
}

229 230
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
			       btrfs_root *root)
231
{
C
Chris Mason 已提交
232
	unsigned long gang[8];
233
	u64 first = 0;
234 235
	int ret;
	int i;
C
Chris Mason 已提交
236
	struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix;
237 238

	while(1) {
C
Chris Mason 已提交
239 240
		ret = find_first_radix_bit(pinned_radix, gang,
					   ARRAY_SIZE(gang));
241 242
		if (!ret)
			break;
243
		if (!first)
C
Chris Mason 已提交
244
			first = gang[0];
245
		for (i = 0; i < ret; i++) {
C
Chris Mason 已提交
246
			clear_radix_bit(pinned_radix, gang[i]);
247
		}
248
	}
249 250
	if (root->fs_info->last_insert.objectid > first)
		root->fs_info->last_insert.objectid = first;
251
	root->fs_info->last_insert.offset = 0;
252 253 254
	return 0;
}

255 256
static int finish_current_insert(struct btrfs_trans_handle *trans, struct
				 btrfs_root *extent_root)
C
Chris Mason 已提交
257
{
C
Chris Mason 已提交
258
	struct btrfs_key ins;
C
Chris Mason 已提交
259
	struct btrfs_extent_item extent_item;
C
Chris Mason 已提交
260 261
	int i;
	int ret;
262 263
	u64 super_blocks_used;
	struct btrfs_fs_info *info = extent_root->fs_info;
C
Chris Mason 已提交
264

C
Chris Mason 已提交
265
	btrfs_set_extent_refs(&extent_item, 1);
C
Chris Mason 已提交
266 267
	ins.offset = 1;
	ins.flags = 0;
268
	btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
269
	btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid);
C
Chris Mason 已提交
270

271 272
	for (i = 0; i < extent_root->fs_info->extent_tree_insert_nr; i++) {
		ins.objectid = extent_root->fs_info->extent_tree_insert[i];
273 274 275
		super_blocks_used = btrfs_super_blocks_used(info->disk_super);
		btrfs_set_super_blocks_used(info->disk_super,
					    super_blocks_used + 1);
276 277
		ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
					sizeof(extent_item));
C
Chris Mason 已提交
278 279
		BUG_ON(ret);
	}
280 281
	extent_root->fs_info->extent_tree_insert_nr = 0;
	extent_root->fs_info->extent_tree_prealloc_nr = 0;
C
Chris Mason 已提交
282 283 284
	return 0;
}

C
Chris Mason 已提交
285
static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
C
Chris Mason 已提交
286 287
{
	int err;
C
Chris Mason 已提交
288
	struct btrfs_header *header;
C
Chris Mason 已提交
289 290
	struct buffer_head *bh;

C
Chris Mason 已提交
291
	if (!pending) {
292
		bh = btrfs_find_tree_block(root, blocknr);
C
Chris Mason 已提交
293 294 295 296 297 298 299 300 301 302
		if (bh) {
			if (buffer_uptodate(bh)) {
				u64 transid =
				    root->fs_info->running_transaction->transid;
				header = btrfs_buffer_header(bh);
				if (btrfs_header_generation(header) ==
				    transid) {
					btrfs_block_release(root, bh);
					return 0;
				}
C
Chris Mason 已提交
303
			}
C
Chris Mason 已提交
304
			btrfs_block_release(root, bh);
C
Chris Mason 已提交
305 306
		}
		err = set_radix_bit(&root->fs_info->pinned_radix, blocknr);
C
Chris Mason 已提交
307 308 309
	} else {
		err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr);
	}
C
Chris Mason 已提交
310
	BUG_ON(err);
C
Chris Mason 已提交
311 312 313
	return 0;
}

314
/*
315
 * remove an extent from the root, returns 0 on success
316
 */
317
static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
C
Chris Mason 已提交
318
			 *root, u64 blocknr, u64 num_blocks, int pin)
319
{
320
	struct btrfs_path *path;
C
Chris Mason 已提交
321
	struct btrfs_key key;
322 323
	struct btrfs_fs_info *info = root->fs_info;
	struct btrfs_root *extent_root = info->extent_root;
324
	int ret;
C
Chris Mason 已提交
325
	struct btrfs_extent_item *ei;
C
Chris Mason 已提交
326
	struct btrfs_key ins;
C
Chris Mason 已提交
327
	u32 refs;
C
Chris Mason 已提交
328

329 330
	key.objectid = blocknr;
	key.flags = 0;
331
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
332 333
	key.offset = num_blocks;

334
	find_free_extent(trans, root, 0, 0, (u64)-1, &ins);
335 336 337
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
338

339
	ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
340
	if (ret) {
341
		printk("failed to find %Lu\n", key.objectid);
C
Chris Mason 已提交
342
		btrfs_print_tree(extent_root, extent_root->node);
343
		printk("failed to find %Lu\n", key.objectid);
344 345
		BUG();
	}
346
	ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
C
Chris Mason 已提交
347
			    struct btrfs_extent_item);
348
	BUG_ON(ei->refs == 0);
C
Chris Mason 已提交
349 350
	refs = btrfs_extent_refs(ei) - 1;
	btrfs_set_extent_refs(ei, refs);
351
	btrfs_mark_buffer_dirty(path->nodes[0]);
C
Chris Mason 已提交
352
	if (refs == 0) {
353
		u64 super_blocks_used;
C
Chris Mason 已提交
354 355

		if (pin) {
C
Chris Mason 已提交
356
			ret = pin_down_block(root, blocknr, 0);
C
Chris Mason 已提交
357 358 359
			BUG_ON(ret);
		}

360 361 362
		super_blocks_used = btrfs_super_blocks_used(info->disk_super);
		btrfs_set_super_blocks_used(info->disk_super,
					    super_blocks_used - num_blocks);
363
		ret = btrfs_del_item(trans, extent_root, path);
364 365
		if (ret)
			BUG();
C
Chris Mason 已提交
366 367
		ret = update_block_group(trans, root, blocknr, num_blocks, 0);
		BUG_ON(ret);
368
	}
369 370
	btrfs_release_path(extent_root, path);
	btrfs_free_path(path);
371
	finish_current_insert(trans, extent_root);
372 373 374 375 376 377 378
	return ret;
}

/*
 * find all the blocks marked as pending in the radix tree and remove
 * them from the extent map
 */
379 380
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
			       btrfs_root *extent_root)
381 382
{
	int ret;
C
Chris Mason 已提交
383 384
	int wret;
	int err = 0;
C
Chris Mason 已提交
385
	unsigned long gang[4];
386
	int i;
C
Chris Mason 已提交
387 388 389 390 391
	struct radix_tree_root *pending_radix;
	struct radix_tree_root *pinned_radix;

	pending_radix = &extent_root->fs_info->pending_del_radix;
	pinned_radix = &extent_root->fs_info->pinned_radix;
392 393

	while(1) {
C
Chris Mason 已提交
394 395
		ret = find_first_radix_bit(pending_radix, gang,
					   ARRAY_SIZE(gang));
396 397 398
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
C
Chris Mason 已提交
399 400 401 402
			wret = set_radix_bit(pinned_radix, gang[i]);
			BUG_ON(wret);
			wret = clear_radix_bit(pending_radix, gang[i]);
			BUG_ON(wret);
403
			wret = __free_extent(trans, extent_root,
C
Chris Mason 已提交
404
					     gang[i], 1, 0);
C
Chris Mason 已提交
405 406
			if (wret)
				err = wret;
407 408
		}
	}
C
Chris Mason 已提交
409
	return err;
410 411 412 413 414
}

/*
 * remove an extent from the root, returns 0 on success
 */
415 416
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, u64 blocknr, u64 num_blocks, int pin)
417
{
418
	struct btrfs_root *extent_root = root->fs_info->extent_root;
419 420
	int pending_ret;
	int ret;
421

422
	if (root == extent_root) {
C
Chris Mason 已提交
423
		pin_down_block(root, blocknr, 1);
424 425
		return 0;
	}
C
Chris Mason 已提交
426
	ret = __free_extent(trans, root, blocknr, num_blocks, pin);
C
Chris Mason 已提交
427
	pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
428 429 430 431 432 433 434
	return ret ? ret : pending_ret;
}

/*
 * walks the btree of allocated extents and find a hole of a given size.
 * The key ins is changed to record the hole:
 * ins->objectid == block start
435
 * ins->flags = BTRFS_EXTENT_ITEM_KEY
436 437 438
 * ins->offset == number of blocks
 * Any available blocks before search_start are skipped.
 */
439 440 441
static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
			    *orig_root, u64 num_blocks, u64 search_start, u64
			    search_end, struct btrfs_key *ins)
442
{
443
	struct btrfs_path *path;
C
Chris Mason 已提交
444
	struct btrfs_key key;
445 446 447
	int ret;
	u64 hole_size = 0;
	int slot = 0;
C
Chris Mason 已提交
448
	u64 last_block = 0;
C
Chris Mason 已提交
449
	u64 test_block;
450
	int start_found;
C
Chris Mason 已提交
451
	struct btrfs_leaf *l;
452
	struct btrfs_root * root = orig_root->fs_info->extent_root;
453
	struct btrfs_fs_info *info = root->fs_info;
454
	int total_needed = num_blocks;
455 456
	int total_found = 0;
	int fill_prealloc = 0;
C
Chris Mason 已提交
457
	int level;
458

459 460 461 462
	path = btrfs_alloc_path();
	ins->flags = 0;
	btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);

C
Chris Mason 已提交
463
	level = btrfs_header_level(btrfs_buffer_header(root->node));
464 465 466 467 468 469 470
	if (num_blocks == 0) {
		fill_prealloc = 1;
		num_blocks = 1;
		total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3;
	}
	if (info->last_insert.objectid > search_start)
		search_start = info->last_insert.objectid;
471

472
check_failed:
473
	btrfs_init_path(path);
474 475 476
	ins->objectid = search_start;
	ins->offset = 0;
	start_found = 0;
477
	ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
C
Chris Mason 已提交
478 479
	if (ret < 0)
		goto error;
C
Chris Mason 已提交
480

481 482
	if (path->slots[0] > 0)
		path->slots[0]--;
483

484
	while (1) {
485 486
		l = btrfs_buffer_leaf(path->nodes[0]);
		slot = path->slots[0];
487
		if (slot >= btrfs_header_nritems(&l->header)) {
488 489 490 491
			if (fill_prealloc) {
				info->extent_tree_prealloc_nr = 0;
				total_found = 0;
			}
492
			ret = btrfs_next_leaf(root, path);
493 494
			if (ret == 0)
				continue;
C
Chris Mason 已提交
495 496
			if (ret < 0)
				goto error;
497 498
			if (!start_found) {
				ins->objectid = search_start;
499
				ins->offset = (u64)-1 - search_start;
500 501 502 503 504
				start_found = 1;
				goto check_pending;
			}
			ins->objectid = last_block > search_start ?
					last_block : search_start;
505
			ins->offset = (u64)-1 - ins->objectid;
506 507
			goto check_pending;
		}
C
Chris Mason 已提交
508
		btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
C
Chris Mason 已提交
509 510
		if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY)
			goto next;
C
Chris Mason 已提交
511
		if (key.objectid >= search_start) {
512
			if (start_found) {
513 514
				if (last_block < search_start)
					last_block = search_start;
C
Chris Mason 已提交
515
				hole_size = key.objectid - last_block;
516
				if (hole_size > num_blocks) {
517
					ins->objectid = last_block;
C
Chris Mason 已提交
518
					ins->offset = hole_size;
519 520
					goto check_pending;
				}
521
			}
522
		}
523
		start_found = 1;
C
Chris Mason 已提交
524
		last_block = key.objectid + key.offset;
C
Chris Mason 已提交
525
next:
526
		path->slots[0]++;
527 528 529 530 531 532
	}
	// FIXME -ENOSPC
check_pending:
	/* we have to make sure we didn't find an extent that has already
	 * been allocated by the map tree or the original allocation
	 */
533
	btrfs_release_path(root, path);
534
	BUG_ON(ins->objectid < search_start);
C
Chris Mason 已提交
535
	for (test_block = ins->objectid;
536 537
	     test_block < ins->objectid + num_blocks; test_block++) {
		if (test_radix_bit(&info->pinned_radix, test_block)) {
C
Chris Mason 已提交
538
			search_start = test_block + 1;
539 540 541
			goto check_failed;
		}
	}
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
	if (!fill_prealloc && info->extent_tree_insert_nr) {
		u64 last =
		  info->extent_tree_insert[info->extent_tree_insert_nr - 1];
		if (ins->objectid + num_blocks >
		    info->extent_tree_insert[0] &&
		    ins->objectid <= last) {
			search_start = last + 1;
			WARN_ON(1);
			goto check_failed;
		}
	}
	if (!fill_prealloc && info->extent_tree_prealloc_nr) {
		u64 first =
		  info->extent_tree_prealloc[info->extent_tree_prealloc_nr - 1];
		if (ins->objectid + num_blocks > first &&
		    ins->objectid <= info->extent_tree_prealloc[0]) {
			search_start = info->extent_tree_prealloc[0] + 1;
			WARN_ON(1);
			goto check_failed;
		}
	}
	if (fill_prealloc) {
		int nr;
		test_block = ins->objectid;
		while(test_block < ins->objectid + ins->offset &&
		      total_found < total_needed) {
			nr = total_needed - total_found - 1;
			BUG_ON(nr < 0);
			root->fs_info->extent_tree_prealloc[nr] =
				test_block;
			total_found++;
			test_block++;
		}
		if (total_found < total_needed) {
			search_start = test_block;
			goto check_failed;
		}
		root->fs_info->extent_tree_prealloc_nr = total_found;
	}
581
	root->fs_info->last_insert.objectid = ins->objectid;
C
Chris Mason 已提交
582
	ins->offset = num_blocks;
583
	btrfs_free_path(path);
584
	return 0;
C
Chris Mason 已提交
585
error:
586 587
	btrfs_release_path(root, path);
	btrfs_free_path(path);
C
Chris Mason 已提交
588
	return ret;
589 590 591 592 593 594 595 596
}
/*
 * finds a free extent and does all the dirty work required for allocation
 * returns the key for the extent through ins, and a tree buffer for
 * the first block of the extent through buf.
 *
 * returns 0 if everything worked, non-zero otherwise.
 */
597 598
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
		       struct btrfs_root *root, u64 owner,
599
		       u64 num_blocks, u64 search_start,
600
		       u64 search_end, struct btrfs_key *ins)
601 602 603
{
	int ret;
	int pending_ret;
604 605 606
	u64 super_blocks_used;
	struct btrfs_fs_info *info = root->fs_info;
	struct btrfs_root *extent_root = info->extent_root;
C
Chris Mason 已提交
607
	struct btrfs_extent_item extent_item;
608
	struct btrfs_key prealloc_key;
C
Chris Mason 已提交
609

C
Chris Mason 已提交
610
	btrfs_set_extent_refs(&extent_item, 1);
611
	btrfs_set_extent_owner(&extent_item, owner);
612

C
Chris Mason 已提交
613
	if (root == extent_root) {
614 615
		int nr;
		BUG_ON(info->extent_tree_prealloc_nr == 0);
C
Chris Mason 已提交
616 617
		BUG_ON(num_blocks != 1);
		ins->offset = 1;
618 619 620 621 622
		info->extent_tree_prealloc_nr--;
		nr = info->extent_tree_prealloc_nr;
		ins->objectid = info->extent_tree_prealloc[nr];
		info->extent_tree_insert[info->extent_tree_insert_nr++] =
			ins->objectid;
C
Chris Mason 已提交
623 624 625
		ret = update_block_group(trans, root,
					 ins->objectid, ins->offset, 1);
		BUG_ON(ret);
626 627
		return 0;
	}
628
	/* do the real allocation */
629
	ret = find_free_extent(trans, root, num_blocks, search_start,
C
Chris Mason 已提交
630 631 632
			       search_end, ins);
	if (ret)
		return ret;
633

634 635 636 637 638 639
	/* then do prealloc for the extent tree */
	ret = find_free_extent(trans, root, 0, ins->objectid + ins->offset,
			       search_end, &prealloc_key);
	if (ret)
		return ret;

640 641 642
	super_blocks_used = btrfs_super_blocks_used(info->disk_super);
	btrfs_set_super_blocks_used(info->disk_super, super_blocks_used +
				    num_blocks);
643 644
	ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
				sizeof(extent_item));
C
Chris Mason 已提交
645

646
	finish_current_insert(trans, extent_root);
C
Chris Mason 已提交
647
	pending_ret = del_pending_extents(trans, extent_root);
C
Chris Mason 已提交
648 649 650 651
	if (ret)
		return ret;
	if (pending_ret)
		return pending_ret;
C
Chris Mason 已提交
652
	ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
C
Chris Mason 已提交
653
	return 0;
654 655 656 657 658 659
}

/*
 * helper function to allocate a block for a given tree
 * returns the tree buffer or NULL.
 */
C
Chris Mason 已提交
660
struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
661
					   struct btrfs_root *root)
662
{
C
Chris Mason 已提交
663
	struct btrfs_key ins;
664
	int ret;
C
Chris Mason 已提交
665
	struct buffer_head *buf;
666

667 668
	ret = btrfs_alloc_extent(trans, root, root->root_key.objectid,
				 1, 0, (unsigned long)-1, &ins);
669 670 671 672
	if (ret) {
		BUG();
		return NULL;
	}
C
Chris Mason 已提交
673
	BUG_ON(ret);
674
	buf = btrfs_find_create_tree_block(root, ins.objectid);
675
	set_buffer_uptodate(buf);
676 677
	return buf;
}
678

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
static int drop_leaf_ref(struct btrfs_trans_handle *trans,
			 struct btrfs_root *root, struct buffer_head *cur)
{
	struct btrfs_disk_key *key;
	struct btrfs_leaf *leaf;
	struct btrfs_file_extent_item *fi;
	int i;
	int nritems;
	int ret;

	BUG_ON(!btrfs_is_leaf(btrfs_buffer_node(cur)));
	leaf = btrfs_buffer_leaf(cur);
	nritems = btrfs_header_nritems(&leaf->header);
	for (i = 0; i < nritems; i++) {
		key = &leaf->items[i].key;
		if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
			continue;
		fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
697 698
		if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE)
			continue;
699 700 701 702 703 704 705 706 707 708 709 710 711
		/*
		 * FIXME make sure to insert a trans record that
		 * repeats the snapshot del on crash
		 */
		ret = btrfs_free_extent(trans, root,
					btrfs_file_extent_disk_blocknr(fi),
					btrfs_file_extent_disk_num_blocks(fi),
					0);
		BUG_ON(ret);
	}
	return 0;
}

C
Chris Mason 已提交
712 713 714 715
/*
 * helper function for drop_snapshot, this walks down the tree dropping ref
 * counts as it goes.
 */
716 717
static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
			  *root, struct btrfs_path *path, int *level)
C
Chris Mason 已提交
718
{
C
Chris Mason 已提交
719 720
	struct buffer_head *next;
	struct buffer_head *cur;
C
Chris Mason 已提交
721 722 723 724
	u64 blocknr;
	int ret;
	u32 refs;

725 726
	WARN_ON(*level < 0);
	WARN_ON(*level >= BTRFS_MAX_LEVEL);
C
Chris Mason 已提交
727
	ret = lookup_extent_ref(trans, root, bh_blocknr(path->nodes[*level]),
728
			       1, &refs);
C
Chris Mason 已提交
729 730 731
	BUG_ON(ret);
	if (refs > 1)
		goto out;
C
Chris Mason 已提交
732 733 734
	/*
	 * walk down to the last node level and free all the leaves
	 */
735
	while(*level >= 0) {
736 737
		WARN_ON(*level < 0);
		WARN_ON(*level >= BTRFS_MAX_LEVEL);
C
Chris Mason 已提交
738
		cur = path->nodes[*level];
C
Chris Mason 已提交
739 740
		if (btrfs_header_level(btrfs_buffer_header(cur)) != *level)
			WARN_ON(1);
741
		if (path->slots[*level] >=
C
Chris Mason 已提交
742
		    btrfs_header_nritems(btrfs_buffer_header(cur)))
C
Chris Mason 已提交
743
			break;
744 745 746 747 748
		if (*level == 0) {
			ret = drop_leaf_ref(trans, root, cur);
			BUG_ON(ret);
			break;
		}
C
Chris Mason 已提交
749 750
		blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur),
					      path->slots[*level]);
C
Chris Mason 已提交
751
		ret = lookup_extent_ref(trans, root, blocknr, 1, &refs);
752 753
		BUG_ON(ret);
		if (refs != 1) {
C
Chris Mason 已提交
754
			path->slots[*level]++;
755
			ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
C
Chris Mason 已提交
756 757 758 759
			BUG_ON(ret);
			continue;
		}
		next = read_tree_block(root, blocknr);
760
		WARN_ON(*level <= 0);
C
Chris Mason 已提交
761
		if (path->nodes[*level-1])
C
Chris Mason 已提交
762
			btrfs_block_release(root, path->nodes[*level-1]);
C
Chris Mason 已提交
763
		path->nodes[*level-1] = next;
C
Chris Mason 已提交
764
		*level = btrfs_header_level(btrfs_buffer_header(next));
C
Chris Mason 已提交
765 766 767
		path->slots[*level] = 0;
	}
out:
768 769
	WARN_ON(*level < 0);
	WARN_ON(*level >= BTRFS_MAX_LEVEL);
770
	ret = btrfs_free_extent(trans, root,
771
				bh_blocknr(path->nodes[*level]), 1, 1);
C
Chris Mason 已提交
772
	btrfs_block_release(root, path->nodes[*level]);
C
Chris Mason 已提交
773 774 775 776 777 778
	path->nodes[*level] = NULL;
	*level += 1;
	BUG_ON(ret);
	return 0;
}

C
Chris Mason 已提交
779 780 781 782 783
/*
 * helper for dropping snapshots.  This walks back up the tree in the path
 * to find the first node higher up where we haven't yet gone through
 * all the slots
 */
784 785
static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
			*root, struct btrfs_path *path, int *level)
C
Chris Mason 已提交
786 787 788 789
{
	int i;
	int slot;
	int ret;
C
Chris Mason 已提交
790
	for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
C
Chris Mason 已提交
791
		slot = path->slots[i];
C
Chris Mason 已提交
792 793
		if (slot < btrfs_header_nritems(
		    btrfs_buffer_header(path->nodes[i])) - 1) {
C
Chris Mason 已提交
794 795 796 797
			path->slots[i]++;
			*level = i;
			return 0;
		} else {
798
			ret = btrfs_free_extent(trans, root,
799
						bh_blocknr(path->nodes[*level]),
800
						1, 1);
801
			BUG_ON(ret);
C
Chris Mason 已提交
802
			btrfs_block_release(root, path->nodes[*level]);
C
Chris Mason 已提交
803
			path->nodes[*level] = NULL;
C
Chris Mason 已提交
804 805 806 807 808 809
			*level = i + 1;
		}
	}
	return 1;
}

C
Chris Mason 已提交
810 811 812 813 814
/*
 * drop the reference count on the tree rooted at 'snap'.  This traverses
 * the tree freeing any blocks that have a ref count of zero after being
 * decremented.
 */
815
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
C
Chris Mason 已提交
816
			*root, struct buffer_head *snap)
C
Chris Mason 已提交
817
{
818
	int ret = 0;
C
Chris Mason 已提交
819
	int wret;
C
Chris Mason 已提交
820
	int level;
821
	struct btrfs_path *path;
C
Chris Mason 已提交
822 823 824
	int i;
	int orig_level;

825 826 827
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
C
Chris Mason 已提交
828

C
Chris Mason 已提交
829
	level = btrfs_header_level(btrfs_buffer_header(snap));
C
Chris Mason 已提交
830
	orig_level = level;
831 832
	path->nodes[level] = snap;
	path->slots[level] = 0;
C
Chris Mason 已提交
833
	while(1) {
834
		wret = walk_down_tree(trans, root, path, &level);
C
Chris Mason 已提交
835
		if (wret > 0)
C
Chris Mason 已提交
836
			break;
C
Chris Mason 已提交
837 838 839
		if (wret < 0)
			ret = wret;

840
		wret = walk_up_tree(trans, root, path, &level);
C
Chris Mason 已提交
841
		if (wret > 0)
C
Chris Mason 已提交
842
			break;
C
Chris Mason 已提交
843 844
		if (wret < 0)
			ret = wret;
C
Chris Mason 已提交
845
	}
C
Chris Mason 已提交
846
	for (i = 0; i <= orig_level; i++) {
847 848
		if (path->nodes[i]) {
			btrfs_block_release(root, path->nodes[i]);
C
Chris Mason 已提交
849
		}
C
Chris Mason 已提交
850
	}
851
	btrfs_free_path(path);
C
Chris Mason 已提交
852
	return ret;
C
Chris Mason 已提交
853
}
C
Chris Mason 已提交
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932

int btrfs_free_block_groups(struct btrfs_fs_info *info)
{
	int ret;
	struct btrfs_block_group_cache *cache[8];
	int i;

	while(1) {
		ret = radix_tree_gang_lookup(&info->block_group_radix,
					     (void **)cache, 0,
					     ARRAY_SIZE(cache));
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
			radix_tree_delete(&info->block_group_radix,
					  cache[i]->key.objectid +
					  cache[i]->key.offset - 1);
			kfree(cache[i]);
		}
	}
	return 0;
}

int btrfs_read_block_groups(struct btrfs_root *root)
{
	struct btrfs_path *path;
	int ret;
	int err = 0;
	struct btrfs_block_group_item *bi;
	struct btrfs_block_group_cache *cache;
	struct btrfs_key key;
	struct btrfs_key found_key;
	struct btrfs_leaf *leaf;
	u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize;

	root = root->fs_info->extent_root;
	key.objectid = 0;
	key.offset = group_size_blocks;
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_BLOCK_GROUP_ITEM_KEY);

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;

	while(1) {
		ret = btrfs_search_slot(NULL, root->fs_info->extent_root,
					&key, path, 0, 0);
		if (ret != 0) {
			err = ret;
			break;
		}
		leaf = btrfs_buffer_leaf(path->nodes[0]);
		btrfs_disk_key_to_cpu(&found_key,
				      &leaf->items[path->slots[0]].key);
		cache = kmalloc(sizeof(*cache), GFP_NOFS);
		if (!cache) {
			err = -1;
			break;
		}
		bi = btrfs_item_ptr(leaf, path->slots[0],
				    struct btrfs_block_group_item);
		memcpy(&cache->item, bi, sizeof(*bi));
		memcpy(&cache->key, &found_key, sizeof(found_key));
		key.objectid = found_key.objectid + found_key.offset;
		btrfs_release_path(root, path);
		ret = radix_tree_insert(&root->fs_info->block_group_radix,
					found_key.objectid +
					found_key.offset - 1,
					(void *)cache);
		BUG_ON(ret);
		if (key.objectid >=
		    btrfs_super_total_blocks(root->fs_info->disk_super))
			break;
	}

	btrfs_free_path(path);
	return 0;
}