extent-tree.c 26.6 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 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
static int find_search_start(struct btrfs_root *root, int data)
{
	struct btrfs_block_group_cache *cache[8];
	struct btrfs_fs_info *info = root->fs_info;
	u64 used;
	u64 last;
	int i;
	int ret;

	cache[0] = info->block_group_cache;
	if (!cache[0])
		goto find_new;
	used = btrfs_block_group_used(&cache[0]->item);
	if (used < (cache[0]->key.offset * 3 / 2))
		return 0;
find_new:
	last = 0;
	while(1) {
		ret = radix_tree_gang_lookup_tag(&info->block_group_radix,
						 (void **)cache,
						 last, ARRAY_SIZE(cache),
						 BTRFS_BLOCK_GROUP_DIRTY);
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
			used = btrfs_block_group_used(&cache[i]->item);
			if (used < (cache[i]->key.offset * 3 / 2)) {
				info->block_group_cache = cache[i];
				cache[i]->last_alloc = cache[i]->first_free;
				return 0;
			}
			last = cache[i]->key.objectid +
				cache[i]->key.offset - 1;
		}
	}
	last = 0;
	while(1) {
		ret = radix_tree_gang_lookup(&info->block_group_radix,
						 (void **)cache,
						 last, ARRAY_SIZE(cache));
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
			used = btrfs_block_group_used(&cache[i]->item);
			if (used < (cache[i]->key.offset * 3 / 2)) {
				info->block_group_cache = cache[i];
				cache[i]->last_alloc = cache[i]->first_free;
				return 0;
			}
			last = cache[i]->key.objectid +
				cache[i]->key.offset - 1;
		}
	}
	info->block_group_cache = NULL;
	return 0;
}

C
Chris Mason 已提交
72 73 74
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
				struct btrfs_root *root,
				u64 blocknr, u64 num_blocks)
C
Chris Mason 已提交
75
{
76
	struct btrfs_path *path;
C
Chris Mason 已提交
77
	int ret;
C
Chris Mason 已提交
78
	struct btrfs_key key;
C
Chris Mason 已提交
79 80
	struct btrfs_leaf *l;
	struct btrfs_extent_item *item;
C
Chris Mason 已提交
81
	struct btrfs_key ins;
C
Chris Mason 已提交
82
	u32 refs;
C
Chris Mason 已提交
83

84 85
	find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1,
			 &ins);
86 87 88
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
C
Chris Mason 已提交
89 90
	key.objectid = blocknr;
	key.flags = 0;
91
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
92
	key.offset = num_blocks;
93
	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
94
				0, 1);
95 96
	if (ret != 0) {
printk("can't find block %Lu %Lu\n", blocknr, num_blocks);
97
		BUG();
98
	}
C
Chris Mason 已提交
99
	BUG_ON(ret != 0);
100 101
	l = btrfs_buffer_leaf(path->nodes[0]);
	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
C
Chris Mason 已提交
102 103
	refs = btrfs_extent_refs(item);
	btrfs_set_extent_refs(item, refs + 1);
104
	btrfs_mark_buffer_dirty(path->nodes[0]);
105

106 107
	btrfs_release_path(root->fs_info->extent_root, path);
	btrfs_free_path(path);
108
	finish_current_insert(trans, root->fs_info->extent_root);
C
Chris Mason 已提交
109
	del_pending_extents(trans, root->fs_info->extent_root);
C
Chris Mason 已提交
110 111 112
	return 0;
}

C
Chris Mason 已提交
113 114 115
static int lookup_extent_ref(struct btrfs_trans_handle *trans,
			     struct btrfs_root *root, u64 blocknr,
			     u64 num_blocks, u32 *refs)
116
{
117
	struct btrfs_path *path;
118
	int ret;
C
Chris Mason 已提交
119
	struct btrfs_key key;
C
Chris Mason 已提交
120 121
	struct btrfs_leaf *l;
	struct btrfs_extent_item *item;
122 123 124

	path = btrfs_alloc_path();
	btrfs_init_path(path);
125
	key.objectid = blocknr;
126
	key.offset = num_blocks;
127 128
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
129
	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
130
				0, 0);
131 132
	if (ret != 0)
		BUG();
133 134
	l = btrfs_buffer_leaf(path->nodes[0]);
	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
C
Chris Mason 已提交
135
	*refs = btrfs_extent_refs(item);
136 137
	btrfs_release_path(root->fs_info->extent_root, path);
	btrfs_free_path(path);
138 139 140
	return 0;
}

C
Chris Mason 已提交
141 142 143
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *root)
{
C
Chris Mason 已提交
144
	return btrfs_inc_extent_ref(trans, root, bh_blocknr(root->node), 1);
C
Chris Mason 已提交
145 146
}

147
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
C
Chris Mason 已提交
148
		  struct buffer_head *buf)
C
Chris Mason 已提交
149 150
{
	u64 blocknr;
C
Chris Mason 已提交
151
	struct btrfs_node *buf_node;
152 153 154
	struct btrfs_leaf *buf_leaf;
	struct btrfs_disk_key *key;
	struct btrfs_file_extent_item *fi;
C
Chris Mason 已提交
155
	int i;
156 157
	int leaf;
	int ret;
158

159
	if (!root->ref_cows)
160
		return 0;
C
Chris Mason 已提交
161
	buf_node = btrfs_buffer_node(buf);
162 163
	leaf = btrfs_is_leaf(buf_node);
	buf_leaf = btrfs_buffer_leaf(buf);
C
Chris Mason 已提交
164
	for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
165 166 167 168 169 170
		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);
171 172 173
			if (btrfs_file_extent_type(fi) ==
			    BTRFS_FILE_EXTENT_INLINE)
				continue;
C
Chris Mason 已提交
174
			ret = btrfs_inc_extent_ref(trans, root,
175 176 177 178 179
				    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 已提交
180
			ret = btrfs_inc_extent_ref(trans, root, blocknr, 1);
181 182
			BUG_ON(ret);
		}
C
Chris Mason 已提交
183 184 185 186
	}
	return 0;
}

C
Chris Mason 已提交
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 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
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);
C
Chris Mason 已提交
265 266 267
		if (!ret) {
			printk(KERN_CRIT "blocknr %Lu lookup failed\n",
			       blocknr);
C
Chris Mason 已提交
268
			return -1;
C
Chris Mason 已提交
269
		}
C
Chris Mason 已提交
270 271 272 273 274 275 276 277 278 279
		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;
C
Chris Mason 已提交
280
		if (alloc) {
C
Chris Mason 已提交
281
			old_val += num;
C
Chris Mason 已提交
282 283 284
			if (blocknr > cache->last_alloc)
				cache->last_alloc = blocknr;
		} else {
C
Chris Mason 已提交
285
			old_val -= num;
C
Chris Mason 已提交
286 287 288
			if (blocknr < cache->first_free)
				cache->first_free = blocknr;
		}
C
Chris Mason 已提交
289 290 291 292 293
		btrfs_set_block_group_used(&cache->item, old_val);
	}
	return 0;
}

294 295 296 297 298 299 300
static int try_remove_page(struct address_space *mapping, unsigned long index)
{
	int ret;
	ret = invalidate_mapping_pages(mapping, index, index);
	return ret;
}

301 302
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
			       btrfs_root *root)
303
{
C
Chris Mason 已提交
304
	unsigned long gang[8];
305
	struct inode *btree_inode = root->fs_info->btree_inode;
306
	u64 first = 0;
307 308
	int ret;
	int i;
C
Chris Mason 已提交
309
	struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix;
310 311

	while(1) {
C
Chris Mason 已提交
312 313
		ret = find_first_radix_bit(pinned_radix, gang,
					   ARRAY_SIZE(gang));
314 315
		if (!ret)
			break;
316
		if (!first)
C
Chris Mason 已提交
317
			first = gang[0];
318
		for (i = 0; i < ret; i++) {
C
Chris Mason 已提交
319
			clear_radix_bit(pinned_radix, gang[i]);
320 321 322
			try_remove_page(btree_inode->i_mapping,
					gang[i] << (PAGE_CACHE_SHIFT -
						    btree_inode->i_blkbits));
323
		}
324
	}
C
Chris Mason 已提交
325 326 327 328
	if (root->fs_info->block_group_cache) {
		root->fs_info->block_group_cache->last_alloc =
			root->fs_info->block_group_cache->first_free;
	}
329 330 331
	return 0;
}

332 333
static int finish_current_insert(struct btrfs_trans_handle *trans, struct
				 btrfs_root *extent_root)
C
Chris Mason 已提交
334
{
C
Chris Mason 已提交
335
	struct btrfs_key ins;
C
Chris Mason 已提交
336
	struct btrfs_extent_item extent_item;
C
Chris Mason 已提交
337 338
	int i;
	int ret;
339 340
	u64 super_blocks_used;
	struct btrfs_fs_info *info = extent_root->fs_info;
C
Chris Mason 已提交
341

C
Chris Mason 已提交
342
	btrfs_set_extent_refs(&extent_item, 1);
C
Chris Mason 已提交
343 344
	ins.offset = 1;
	ins.flags = 0;
345
	btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
346
	btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid);
C
Chris Mason 已提交
347

348 349
	for (i = 0; i < extent_root->fs_info->extent_tree_insert_nr; i++) {
		ins.objectid = extent_root->fs_info->extent_tree_insert[i];
350 351 352
		super_blocks_used = btrfs_super_blocks_used(info->disk_super);
		btrfs_set_super_blocks_used(info->disk_super,
					    super_blocks_used + 1);
353 354
		ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
					sizeof(extent_item));
C
Chris Mason 已提交
355 356
		BUG_ON(ret);
	}
357 358
	extent_root->fs_info->extent_tree_insert_nr = 0;
	extent_root->fs_info->extent_tree_prealloc_nr = 0;
C
Chris Mason 已提交
359 360 361
	return 0;
}

C
Chris Mason 已提交
362
static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
C
Chris Mason 已提交
363 364
{
	int err;
C
Chris Mason 已提交
365
	struct btrfs_header *header;
C
Chris Mason 已提交
366 367
	struct buffer_head *bh;

C
Chris Mason 已提交
368
	if (!pending) {
369
		bh = btrfs_find_tree_block(root, blocknr);
C
Chris Mason 已提交
370 371 372 373 374 375 376 377 378 379
		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 已提交
380
			}
C
Chris Mason 已提交
381
			btrfs_block_release(root, bh);
C
Chris Mason 已提交
382 383
		}
		err = set_radix_bit(&root->fs_info->pinned_radix, blocknr);
C
Chris Mason 已提交
384 385 386
	} else {
		err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr);
	}
C
Chris Mason 已提交
387
	BUG_ON(err);
C
Chris Mason 已提交
388 389 390
	return 0;
}

391
/*
392
 * remove an extent from the root, returns 0 on success
393
 */
394
static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
C
Chris Mason 已提交
395
			 *root, u64 blocknr, u64 num_blocks, int pin)
396
{
397
	struct btrfs_path *path;
C
Chris Mason 已提交
398
	struct btrfs_key key;
399 400
	struct btrfs_fs_info *info = root->fs_info;
	struct btrfs_root *extent_root = info->extent_root;
401
	int ret;
C
Chris Mason 已提交
402
	struct btrfs_extent_item *ei;
C
Chris Mason 已提交
403
	struct btrfs_key ins;
C
Chris Mason 已提交
404
	u32 refs;
C
Chris Mason 已提交
405

406 407
	key.objectid = blocknr;
	key.flags = 0;
408
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
409 410
	key.offset = num_blocks;

411
	find_free_extent(trans, root, 0, 0, (u64)-1, &ins);
412 413 414
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
415

416
	ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
417
	if (ret) {
418
		printk("failed to find %Lu\n", key.objectid);
C
Chris Mason 已提交
419
		btrfs_print_tree(extent_root, extent_root->node);
420
		printk("failed to find %Lu\n", key.objectid);
421 422
		BUG();
	}
423
	ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
C
Chris Mason 已提交
424
			    struct btrfs_extent_item);
425
	BUG_ON(ei->refs == 0);
C
Chris Mason 已提交
426 427
	refs = btrfs_extent_refs(ei) - 1;
	btrfs_set_extent_refs(ei, refs);
428
	btrfs_mark_buffer_dirty(path->nodes[0]);
C
Chris Mason 已提交
429
	if (refs == 0) {
430
		u64 super_blocks_used;
C
Chris Mason 已提交
431 432

		if (pin) {
C
Chris Mason 已提交
433
			ret = pin_down_block(root, blocknr, 0);
C
Chris Mason 已提交
434 435 436
			BUG_ON(ret);
		}

437 438 439
		super_blocks_used = btrfs_super_blocks_used(info->disk_super);
		btrfs_set_super_blocks_used(info->disk_super,
					    super_blocks_used - num_blocks);
440
		ret = btrfs_del_item(trans, extent_root, path);
441 442
		if (ret)
			BUG();
C
Chris Mason 已提交
443 444
		ret = update_block_group(trans, root, blocknr, num_blocks, 0);
		BUG_ON(ret);
445
	}
446 447
	btrfs_release_path(extent_root, path);
	btrfs_free_path(path);
448
	finish_current_insert(trans, extent_root);
449 450 451 452 453 454 455
	return ret;
}

/*
 * find all the blocks marked as pending in the radix tree and remove
 * them from the extent map
 */
456 457
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
			       btrfs_root *extent_root)
458 459
{
	int ret;
C
Chris Mason 已提交
460 461
	int wret;
	int err = 0;
C
Chris Mason 已提交
462
	unsigned long gang[4];
463
	int i;
C
Chris Mason 已提交
464 465 466 467 468
	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;
469 470

	while(1) {
C
Chris Mason 已提交
471 472
		ret = find_first_radix_bit(pending_radix, gang,
					   ARRAY_SIZE(gang));
473 474 475
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
C
Chris Mason 已提交
476 477 478 479
			wret = set_radix_bit(pinned_radix, gang[i]);
			BUG_ON(wret);
			wret = clear_radix_bit(pending_radix, gang[i]);
			BUG_ON(wret);
480
			wret = __free_extent(trans, extent_root,
C
Chris Mason 已提交
481
					     gang[i], 1, 0);
C
Chris Mason 已提交
482 483
			if (wret)
				err = wret;
484 485
		}
	}
C
Chris Mason 已提交
486
	return err;
487 488 489 490 491
}

/*
 * remove an extent from the root, returns 0 on success
 */
492 493
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, u64 blocknr, u64 num_blocks, int pin)
494
{
495
	struct btrfs_root *extent_root = root->fs_info->extent_root;
496 497
	int pending_ret;
	int ret;
498

499
	if (root == extent_root) {
C
Chris Mason 已提交
500
		pin_down_block(root, blocknr, 1);
501 502
		return 0;
	}
C
Chris Mason 已提交
503
	ret = __free_extent(trans, root, blocknr, num_blocks, pin);
C
Chris Mason 已提交
504
	pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
505 506 507 508 509 510 511
	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
512
 * ins->flags = BTRFS_EXTENT_ITEM_KEY
513 514 515
 * ins->offset == number of blocks
 * Any available blocks before search_start are skipped.
 */
516 517 518
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)
519
{
520
	struct btrfs_path *path;
C
Chris Mason 已提交
521
	struct btrfs_key key;
522 523 524
	int ret;
	u64 hole_size = 0;
	int slot = 0;
C
Chris Mason 已提交
525
	u64 last_block = 0;
C
Chris Mason 已提交
526
	u64 test_block;
527
	int start_found;
C
Chris Mason 已提交
528
	struct btrfs_leaf *l;
529
	struct btrfs_root * root = orig_root->fs_info->extent_root;
530
	struct btrfs_fs_info *info = root->fs_info;
531
	int total_needed = num_blocks;
532 533
	int total_found = 0;
	int fill_prealloc = 0;
C
Chris Mason 已提交
534
	int level;
535

536 537 538 539
	path = btrfs_alloc_path();
	ins->flags = 0;
	btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);

C
Chris Mason 已提交
540
	level = btrfs_header_level(btrfs_buffer_header(root->node));
541 542 543 544 545
	if (num_blocks == 0) {
		fill_prealloc = 1;
		num_blocks = 1;
		total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3;
	}
C
Chris Mason 已提交
546 547 548 549
	find_search_start(root, 0);
	if (info->block_group_cache &&
	    info->block_group_cache->last_alloc > search_start)
		search_start = info->block_group_cache->last_alloc;
550

551
check_failed:
552
	btrfs_init_path(path);
553 554 555
	ins->objectid = search_start;
	ins->offset = 0;
	start_found = 0;
556
	ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
C
Chris Mason 已提交
557 558
	if (ret < 0)
		goto error;
C
Chris Mason 已提交
559

560 561
	if (path->slots[0] > 0)
		path->slots[0]--;
562

563
	while (1) {
564 565
		l = btrfs_buffer_leaf(path->nodes[0]);
		slot = path->slots[0];
566
		if (slot >= btrfs_header_nritems(&l->header)) {
567 568 569 570
			if (fill_prealloc) {
				info->extent_tree_prealloc_nr = 0;
				total_found = 0;
			}
571
			ret = btrfs_next_leaf(root, path);
572 573
			if (ret == 0)
				continue;
C
Chris Mason 已提交
574 575
			if (ret < 0)
				goto error;
576 577
			if (!start_found) {
				ins->objectid = search_start;
578
				ins->offset = (u64)-1 - search_start;
579 580 581 582 583
				start_found = 1;
				goto check_pending;
			}
			ins->objectid = last_block > search_start ?
					last_block : search_start;
584
			ins->offset = (u64)-1 - ins->objectid;
585 586
			goto check_pending;
		}
C
Chris Mason 已提交
587
		btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
C
Chris Mason 已提交
588 589
		if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY)
			goto next;
C
Chris Mason 已提交
590
		if (key.objectid >= search_start) {
591
			if (start_found) {
592 593
				if (last_block < search_start)
					last_block = search_start;
C
Chris Mason 已提交
594
				hole_size = key.objectid - last_block;
C
Chris Mason 已提交
595
				if (hole_size >= num_blocks) {
596
					ins->objectid = last_block;
C
Chris Mason 已提交
597
					ins->offset = hole_size;
598 599
					goto check_pending;
				}
600
			}
601
		}
602
		start_found = 1;
C
Chris Mason 已提交
603
		last_block = key.objectid + key.offset;
C
Chris Mason 已提交
604
next:
605
		path->slots[0]++;
606 607 608 609 610 611
	}
	// 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
	 */
612
	btrfs_release_path(root, path);
613
	BUG_ON(ins->objectid < search_start);
614 615 616 617 618 619
	if (ins->objectid >= btrfs_super_total_blocks(info->disk_super)) {
		if (search_start == 0)
			return -ENOSPC;
		search_start = 0;
		goto check_failed;
	}
C
Chris Mason 已提交
620
	for (test_block = ins->objectid;
621 622
	     test_block < ins->objectid + num_blocks; test_block++) {
		if (test_radix_bit(&info->pinned_radix, test_block)) {
C
Chris Mason 已提交
623
			search_start = test_block + 1;
624 625 626
			goto check_failed;
		}
	}
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
	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);
C
Chris Mason 已提交
655
			info->extent_tree_prealloc[nr] = test_block;
656 657 658 659 660 661 662
			total_found++;
			test_block++;
		}
		if (total_found < total_needed) {
			search_start = test_block;
			goto check_failed;
		}
C
Chris Mason 已提交
663 664 665 666 667 668 669
		info->extent_tree_prealloc_nr = total_found;
	}
	ret = radix_tree_gang_lookup(&info->block_group_radix,
				     (void **)&info->block_group_cache,
				     ins->objectid, 1);
	if (ret) {
		info->block_group_cache->last_alloc = ins->objectid;
670
	}
C
Chris Mason 已提交
671
	ins->offset = num_blocks;
672
	btrfs_free_path(path);
673
	return 0;
C
Chris Mason 已提交
674
error:
675 676
	btrfs_release_path(root, path);
	btrfs_free_path(path);
C
Chris Mason 已提交
677
	return ret;
678 679 680 681 682 683 684 685
}
/*
 * 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.
 */
686 687
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
		       struct btrfs_root *root, u64 owner,
688
		       u64 num_blocks, u64 search_start,
689
		       u64 search_end, struct btrfs_key *ins)
690 691 692
{
	int ret;
	int pending_ret;
693 694 695
	u64 super_blocks_used;
	struct btrfs_fs_info *info = root->fs_info;
	struct btrfs_root *extent_root = info->extent_root;
C
Chris Mason 已提交
696
	struct btrfs_extent_item extent_item;
697
	struct btrfs_key prealloc_key;
C
Chris Mason 已提交
698

C
Chris Mason 已提交
699
	btrfs_set_extent_refs(&extent_item, 1);
700
	btrfs_set_extent_owner(&extent_item, owner);
701

C
Chris Mason 已提交
702
	if (root == extent_root) {
703 704
		int nr;
		BUG_ON(info->extent_tree_prealloc_nr == 0);
C
Chris Mason 已提交
705 706
		BUG_ON(num_blocks != 1);
		ins->offset = 1;
707 708 709 710 711
		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 已提交
712 713 714
		ret = update_block_group(trans, root,
					 ins->objectid, ins->offset, 1);
		BUG_ON(ret);
715 716
		return 0;
	}
717
	/* do the real allocation */
718
	ret = find_free_extent(trans, root, num_blocks, search_start,
C
Chris Mason 已提交
719 720 721
			       search_end, ins);
	if (ret)
		return ret;
722

723 724 725 726 727 728
	/* 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;

729 730 731
	super_blocks_used = btrfs_super_blocks_used(info->disk_super);
	btrfs_set_super_blocks_used(info->disk_super, super_blocks_used +
				    num_blocks);
732 733
	ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
				sizeof(extent_item));
C
Chris Mason 已提交
734

735
	finish_current_insert(trans, extent_root);
C
Chris Mason 已提交
736
	pending_ret = del_pending_extents(trans, extent_root);
C
Chris Mason 已提交
737 738 739 740
	if (ret)
		return ret;
	if (pending_ret)
		return pending_ret;
C
Chris Mason 已提交
741
	ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
C
Chris Mason 已提交
742
	return 0;
743 744 745 746 747 748
}

/*
 * helper function to allocate a block for a given tree
 * returns the tree buffer or NULL.
 */
C
Chris Mason 已提交
749
struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
750
					   struct btrfs_root *root)
751
{
C
Chris Mason 已提交
752
	struct btrfs_key ins;
753
	int ret;
C
Chris Mason 已提交
754
	struct buffer_head *buf;
755

756 757
	ret = btrfs_alloc_extent(trans, root, root->root_key.objectid,
				 1, 0, (unsigned long)-1, &ins);
758 759 760 761
	if (ret) {
		BUG();
		return NULL;
	}
C
Chris Mason 已提交
762
	BUG_ON(ret);
763
	buf = btrfs_find_create_tree_block(root, ins.objectid);
764
	set_buffer_uptodate(buf);
765
	set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index);
766 767
	return buf;
}
768

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
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);
787 788
		if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE)
			continue;
789 790 791 792 793 794 795 796 797 798 799 800 801
		/*
		 * 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 已提交
802 803 804 805
/*
 * helper function for drop_snapshot, this walks down the tree dropping ref
 * counts as it goes.
 */
806 807
static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
			  *root, struct btrfs_path *path, int *level)
C
Chris Mason 已提交
808
{
C
Chris Mason 已提交
809 810
	struct buffer_head *next;
	struct buffer_head *cur;
C
Chris Mason 已提交
811 812 813 814
	u64 blocknr;
	int ret;
	u32 refs;

815 816
	WARN_ON(*level < 0);
	WARN_ON(*level >= BTRFS_MAX_LEVEL);
C
Chris Mason 已提交
817
	ret = lookup_extent_ref(trans, root, bh_blocknr(path->nodes[*level]),
818
			       1, &refs);
C
Chris Mason 已提交
819 820 821
	BUG_ON(ret);
	if (refs > 1)
		goto out;
C
Chris Mason 已提交
822 823 824
	/*
	 * walk down to the last node level and free all the leaves
	 */
825
	while(*level >= 0) {
826 827
		WARN_ON(*level < 0);
		WARN_ON(*level >= BTRFS_MAX_LEVEL);
C
Chris Mason 已提交
828
		cur = path->nodes[*level];
C
Chris Mason 已提交
829 830
		if (btrfs_header_level(btrfs_buffer_header(cur)) != *level)
			WARN_ON(1);
831
		if (path->slots[*level] >=
C
Chris Mason 已提交
832
		    btrfs_header_nritems(btrfs_buffer_header(cur)))
C
Chris Mason 已提交
833
			break;
834 835 836 837 838
		if (*level == 0) {
			ret = drop_leaf_ref(trans, root, cur);
			BUG_ON(ret);
			break;
		}
C
Chris Mason 已提交
839 840
		blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur),
					      path->slots[*level]);
C
Chris Mason 已提交
841
		ret = lookup_extent_ref(trans, root, blocknr, 1, &refs);
842 843
		BUG_ON(ret);
		if (refs != 1) {
C
Chris Mason 已提交
844
			path->slots[*level]++;
845
			ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
C
Chris Mason 已提交
846 847 848 849
			BUG_ON(ret);
			continue;
		}
		next = read_tree_block(root, blocknr);
850
		WARN_ON(*level <= 0);
C
Chris Mason 已提交
851
		if (path->nodes[*level-1])
C
Chris Mason 已提交
852
			btrfs_block_release(root, path->nodes[*level-1]);
C
Chris Mason 已提交
853
		path->nodes[*level-1] = next;
C
Chris Mason 已提交
854
		*level = btrfs_header_level(btrfs_buffer_header(next));
C
Chris Mason 已提交
855 856 857
		path->slots[*level] = 0;
	}
out:
858 859
	WARN_ON(*level < 0);
	WARN_ON(*level >= BTRFS_MAX_LEVEL);
860
	ret = btrfs_free_extent(trans, root,
861
				bh_blocknr(path->nodes[*level]), 1, 1);
C
Chris Mason 已提交
862
	btrfs_block_release(root, path->nodes[*level]);
C
Chris Mason 已提交
863 864 865 866 867 868
	path->nodes[*level] = NULL;
	*level += 1;
	BUG_ON(ret);
	return 0;
}

C
Chris Mason 已提交
869 870 871 872 873
/*
 * 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
 */
874 875
static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
			*root, struct btrfs_path *path, int *level)
C
Chris Mason 已提交
876 877 878 879
{
	int i;
	int slot;
	int ret;
C
Chris Mason 已提交
880
	for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
C
Chris Mason 已提交
881
		slot = path->slots[i];
C
Chris Mason 已提交
882 883
		if (slot < btrfs_header_nritems(
		    btrfs_buffer_header(path->nodes[i])) - 1) {
C
Chris Mason 已提交
884 885 886 887
			path->slots[i]++;
			*level = i;
			return 0;
		} else {
888
			ret = btrfs_free_extent(trans, root,
889
						bh_blocknr(path->nodes[*level]),
890
						1, 1);
891
			BUG_ON(ret);
C
Chris Mason 已提交
892
			btrfs_block_release(root, path->nodes[*level]);
C
Chris Mason 已提交
893
			path->nodes[*level] = NULL;
C
Chris Mason 已提交
894 895 896 897 898 899
			*level = i + 1;
		}
	}
	return 1;
}

C
Chris Mason 已提交
900 901 902 903 904
/*
 * 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.
 */
905
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
C
Chris Mason 已提交
906
			*root, struct buffer_head *snap)
C
Chris Mason 已提交
907
{
908
	int ret = 0;
C
Chris Mason 已提交
909
	int wret;
C
Chris Mason 已提交
910
	int level;
911
	struct btrfs_path *path;
C
Chris Mason 已提交
912 913 914
	int i;
	int orig_level;

915 916 917
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
C
Chris Mason 已提交
918

C
Chris Mason 已提交
919
	level = btrfs_header_level(btrfs_buffer_header(snap));
C
Chris Mason 已提交
920
	orig_level = level;
921 922
	path->nodes[level] = snap;
	path->slots[level] = 0;
C
Chris Mason 已提交
923
	while(1) {
924
		wret = walk_down_tree(trans, root, path, &level);
C
Chris Mason 已提交
925
		if (wret > 0)
C
Chris Mason 已提交
926
			break;
C
Chris Mason 已提交
927 928 929
		if (wret < 0)
			ret = wret;

930
		wret = walk_up_tree(trans, root, path, &level);
C
Chris Mason 已提交
931
		if (wret > 0)
C
Chris Mason 已提交
932
			break;
C
Chris Mason 已提交
933 934
		if (wret < 0)
			ret = wret;
C
Chris Mason 已提交
935
	}
C
Chris Mason 已提交
936
	for (i = 0; i <= orig_level; i++) {
937 938
		if (path->nodes[i]) {
			btrfs_block_release(root, path->nodes[i]);
C
Chris Mason 已提交
939
		}
C
Chris Mason 已提交
940
	}
941
	btrfs_free_path(path);
C
Chris Mason 已提交
942
	return ret;
C
Chris Mason 已提交
943
}
C
Chris Mason 已提交
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007

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));
C
Chris Mason 已提交
1008 1009
		cache->last_alloc = 0;
		cache->first_free = 0;
C
Chris Mason 已提交
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
		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;
}