extent-tree.c 28.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

15 16 17
struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
						 struct btrfs_block_group_cache
						 *hint, int data)
C
Chris Mason 已提交
18 19
{
	struct btrfs_block_group_cache *cache[8];
20
	struct btrfs_block_group_cache *found_group = NULL;
C
Chris Mason 已提交
21 22
	struct btrfs_fs_info *info = root->fs_info;
	u64 used;
23 24
	u64 last = 0;
	u64 hint_last;
C
Chris Mason 已提交
25 26
	int i;
	int ret;
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
	int full_search = 0;
	if (hint) {
		used = btrfs_block_group_used(&hint->item);
		if (used < (hint->key.offset * 2) / 3) {
			return hint;
		}
		radix_tree_tag_clear(&info->block_group_radix,
				     hint->key.objectid + hint->key.offset - 1,
				     BTRFS_BLOCK_GROUP_AVAIL);
		last = hint->key.objectid + hint->key.offset;
		hint_last = last;
	} else {
		hint_last = 0;
		last = 0;
	}
C
Chris Mason 已提交
42 43 44 45
	while(1) {
		ret = radix_tree_gang_lookup_tag(&info->block_group_radix,
						 (void **)cache,
						 last, ARRAY_SIZE(cache),
46
						 BTRFS_BLOCK_GROUP_AVAIL);
C
Chris Mason 已提交
47 48 49 50
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
			used = btrfs_block_group_used(&cache[i]->item);
51
			if (used < (cache[i]->key.offset * 2) / 3) {
C
Chris Mason 已提交
52
				info->block_group_cache = cache[i];
53 54
				found_group = cache[i];
				goto found;
C
Chris Mason 已提交
55
			}
56 57 58 59
			radix_tree_tag_clear(&info->block_group_radix,
					   cache[i]->key.objectid +
					   cache[i]->key.offset - 1,
					   BTRFS_BLOCK_GROUP_AVAIL);
C
Chris Mason 已提交
60
			last = cache[i]->key.objectid +
61
				cache[i]->key.offset;
C
Chris Mason 已提交
62 63
		}
	}
64 65
	last = hint_last;
again:
C
Chris Mason 已提交
66 67 68 69 70 71 72 73
	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);
74
			if (used < cache[i]->key.offset) {
C
Chris Mason 已提交
75
				info->block_group_cache = cache[i];
76 77
				found_group = cache[i];
				goto found;
C
Chris Mason 已提交
78
			}
79 80 81 82
			radix_tree_tag_clear(&info->block_group_radix,
					   cache[i]->key.objectid +
					   cache[i]->key.offset - 1,
					   BTRFS_BLOCK_GROUP_AVAIL);
C
Chris Mason 已提交
83
			last = cache[i]->key.objectid +
84
				cache[i]->key.offset;
C
Chris Mason 已提交
85 86 87
		}
	}
	info->block_group_cache = NULL;
88 89 90 91 92 93 94 95 96 97 98 99
	if (!full_search) {
		last = 0;
		full_search = 1;
		goto again;
	}
found:
	if (!found_group) {
		ret = radix_tree_gang_lookup(&info->block_group_radix,
					     (void **)&found_group, 0, 1);
		BUG_ON(ret != 1);
	}
	return found_group;
C
Chris Mason 已提交
100 101
}

C
Chris Mason 已提交
102 103 104
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
				struct btrfs_root *root,
				u64 blocknr, u64 num_blocks)
C
Chris Mason 已提交
105
{
106
	struct btrfs_path *path;
C
Chris Mason 已提交
107
	int ret;
C
Chris Mason 已提交
108
	struct btrfs_key key;
C
Chris Mason 已提交
109 110
	struct btrfs_leaf *l;
	struct btrfs_extent_item *item;
C
Chris Mason 已提交
111
	struct btrfs_key ins;
C
Chris Mason 已提交
112
	u32 refs;
C
Chris Mason 已提交
113

114 115
	find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1,
			 &ins);
116 117 118
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
C
Chris Mason 已提交
119 120
	key.objectid = blocknr;
	key.flags = 0;
121
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
122
	key.offset = num_blocks;
123
	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
124
				0, 1);
125 126
	if (ret != 0) {
printk("can't find block %Lu %Lu\n", blocknr, num_blocks);
127
		BUG();
128
	}
C
Chris Mason 已提交
129
	BUG_ON(ret != 0);
130 131
	l = btrfs_buffer_leaf(path->nodes[0]);
	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
C
Chris Mason 已提交
132 133
	refs = btrfs_extent_refs(item);
	btrfs_set_extent_refs(item, refs + 1);
134
	btrfs_mark_buffer_dirty(path->nodes[0]);
135

136 137
	btrfs_release_path(root->fs_info->extent_root, path);
	btrfs_free_path(path);
138
	finish_current_insert(trans, root->fs_info->extent_root);
C
Chris Mason 已提交
139
	del_pending_extents(trans, root->fs_info->extent_root);
C
Chris Mason 已提交
140 141 142
	return 0;
}

C
Chris Mason 已提交
143 144 145
static int lookup_extent_ref(struct btrfs_trans_handle *trans,
			     struct btrfs_root *root, u64 blocknr,
			     u64 num_blocks, u32 *refs)
146
{
147
	struct btrfs_path *path;
148
	int ret;
C
Chris Mason 已提交
149
	struct btrfs_key key;
C
Chris Mason 已提交
150 151
	struct btrfs_leaf *l;
	struct btrfs_extent_item *item;
152 153 154

	path = btrfs_alloc_path();
	btrfs_init_path(path);
155
	key.objectid = blocknr;
156
	key.offset = num_blocks;
157 158
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
159
	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
160
				0, 0);
161 162
	if (ret != 0)
		BUG();
163 164
	l = btrfs_buffer_leaf(path->nodes[0]);
	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
C
Chris Mason 已提交
165
	*refs = btrfs_extent_refs(item);
166 167
	btrfs_release_path(root->fs_info->extent_root, path);
	btrfs_free_path(path);
168 169 170
	return 0;
}

C
Chris Mason 已提交
171 172 173
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *root)
{
C
Chris Mason 已提交
174
	return btrfs_inc_extent_ref(trans, root, bh_blocknr(root->node), 1);
C
Chris Mason 已提交
175 176
}

177
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
C
Chris Mason 已提交
178
		  struct buffer_head *buf)
C
Chris Mason 已提交
179 180
{
	u64 blocknr;
C
Chris Mason 已提交
181
	struct btrfs_node *buf_node;
182 183 184
	struct btrfs_leaf *buf_leaf;
	struct btrfs_disk_key *key;
	struct btrfs_file_extent_item *fi;
C
Chris Mason 已提交
185
	int i;
186 187
	int leaf;
	int ret;
188

189
	if (!root->ref_cows)
190
		return 0;
C
Chris Mason 已提交
191
	buf_node = btrfs_buffer_node(buf);
192 193
	leaf = btrfs_is_leaf(buf_node);
	buf_leaf = btrfs_buffer_leaf(buf);
C
Chris Mason 已提交
194
	for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
195 196 197 198 199 200
		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);
201 202 203
			if (btrfs_file_extent_type(fi) ==
			    BTRFS_FILE_EXTENT_INLINE)
				continue;
C
Chris Mason 已提交
204
			ret = btrfs_inc_extent_ref(trans, root,
205 206 207 208 209
				    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 已提交
210
			ret = btrfs_inc_extent_ref(trans, root, blocknr, 1);
211 212
			BUG_ON(ret);
		}
C
Chris Mason 已提交
213 214 215 216
	}
	return 0;
}

C
Chris Mason 已提交
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 265 266 267 268 269 270 271 272 273 274 275
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;
276
			cache[i]->last_alloc = cache[i]->first_free;
C
Chris Mason 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
		}
	}
	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 已提交
296 297 298
		if (!ret) {
			printk(KERN_CRIT "blocknr %Lu lookup failed\n",
			       blocknr);
C
Chris Mason 已提交
299
			return -1;
C
Chris Mason 已提交
300
		}
C
Chris Mason 已提交
301 302 303 304 305 306 307 308 309 310
		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 已提交
311
		if (alloc) {
C
Chris Mason 已提交
312
			old_val += num;
C
Chris Mason 已提交
313 314 315
			if (blocknr > cache->last_alloc)
				cache->last_alloc = blocknr;
		} else {
C
Chris Mason 已提交
316
			old_val -= num;
C
Chris Mason 已提交
317 318 319
			if (blocknr < cache->first_free)
				cache->first_free = blocknr;
		}
C
Chris Mason 已提交
320 321 322 323 324
		btrfs_set_block_group_used(&cache->item, old_val);
	}
	return 0;
}

325 326 327 328 329 330 331
static int try_remove_page(struct address_space *mapping, unsigned long index)
{
	int ret;
	ret = invalidate_mapping_pages(mapping, index, index);
	return ret;
}

332 333
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
			       btrfs_root *root)
334
{
C
Chris Mason 已提交
335
	unsigned long gang[8];
336
	struct inode *btree_inode = root->fs_info->btree_inode;
337
	u64 first = 0;
338 339
	int ret;
	int i;
C
Chris Mason 已提交
340
	struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix;
341 342

	while(1) {
C
Chris Mason 已提交
343 344
		ret = find_first_radix_bit(pinned_radix, gang,
					   ARRAY_SIZE(gang));
345 346
		if (!ret)
			break;
347
		if (!first)
C
Chris Mason 已提交
348
			first = gang[0];
349
		for (i = 0; i < ret; i++) {
C
Chris Mason 已提交
350
			clear_radix_bit(pinned_radix, gang[i]);
351 352 353
			try_remove_page(btree_inode->i_mapping,
					gang[i] << (PAGE_CACHE_SHIFT -
						    btree_inode->i_blkbits));
354
		}
355 356 357 358
	}
	return 0;
}

359 360
static int finish_current_insert(struct btrfs_trans_handle *trans, struct
				 btrfs_root *extent_root)
C
Chris Mason 已提交
361
{
C
Chris Mason 已提交
362
	struct btrfs_key ins;
C
Chris Mason 已提交
363
	struct btrfs_extent_item extent_item;
C
Chris Mason 已提交
364 365
	int i;
	int ret;
366 367
	u64 super_blocks_used;
	struct btrfs_fs_info *info = extent_root->fs_info;
C
Chris Mason 已提交
368

C
Chris Mason 已提交
369
	btrfs_set_extent_refs(&extent_item, 1);
C
Chris Mason 已提交
370 371
	ins.offset = 1;
	ins.flags = 0;
372
	btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
373
	btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid);
C
Chris Mason 已提交
374

375 376
	for (i = 0; i < extent_root->fs_info->extent_tree_insert_nr; i++) {
		ins.objectid = extent_root->fs_info->extent_tree_insert[i];
377 378 379
		super_blocks_used = btrfs_super_blocks_used(info->disk_super);
		btrfs_set_super_blocks_used(info->disk_super,
					    super_blocks_used + 1);
380 381
		ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
					sizeof(extent_item));
C
Chris Mason 已提交
382 383
		BUG_ON(ret);
	}
384 385
	extent_root->fs_info->extent_tree_insert_nr = 0;
	extent_root->fs_info->extent_tree_prealloc_nr = 0;
C
Chris Mason 已提交
386 387 388
	return 0;
}

C
Chris Mason 已提交
389
static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
C
Chris Mason 已提交
390 391
{
	int err;
C
Chris Mason 已提交
392
	struct btrfs_header *header;
C
Chris Mason 已提交
393 394
	struct buffer_head *bh;

C
Chris Mason 已提交
395
	if (!pending) {
396
		bh = btrfs_find_tree_block(root, blocknr);
C
Chris Mason 已提交
397 398 399 400 401 402 403 404 405 406
		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 已提交
407
			}
C
Chris Mason 已提交
408
			btrfs_block_release(root, bh);
C
Chris Mason 已提交
409 410
		}
		err = set_radix_bit(&root->fs_info->pinned_radix, blocknr);
C
Chris Mason 已提交
411 412 413
	} else {
		err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr);
	}
C
Chris Mason 已提交
414
	BUG_ON(err);
C
Chris Mason 已提交
415 416 417
	return 0;
}

418
/*
419
 * remove an extent from the root, returns 0 on success
420
 */
421
static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
C
Chris Mason 已提交
422
			 *root, u64 blocknr, u64 num_blocks, int pin)
423
{
424
	struct btrfs_path *path;
C
Chris Mason 已提交
425
	struct btrfs_key key;
426 427
	struct btrfs_fs_info *info = root->fs_info;
	struct btrfs_root *extent_root = info->extent_root;
428
	int ret;
C
Chris Mason 已提交
429
	struct btrfs_extent_item *ei;
C
Chris Mason 已提交
430
	struct btrfs_key ins;
C
Chris Mason 已提交
431
	u32 refs;
C
Chris Mason 已提交
432

433 434
	key.objectid = blocknr;
	key.flags = 0;
435
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
436 437
	key.offset = num_blocks;

438
	find_free_extent(trans, root, 0, 0, (u64)-1, &ins);
439 440 441
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
442

443
	ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
444
	if (ret) {
445
		printk("failed to find %Lu\n", key.objectid);
C
Chris Mason 已提交
446
		btrfs_print_tree(extent_root, extent_root->node);
447
		printk("failed to find %Lu\n", key.objectid);
448 449
		BUG();
	}
450
	ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
C
Chris Mason 已提交
451
			    struct btrfs_extent_item);
452
	BUG_ON(ei->refs == 0);
C
Chris Mason 已提交
453 454
	refs = btrfs_extent_refs(ei) - 1;
	btrfs_set_extent_refs(ei, refs);
455
	btrfs_mark_buffer_dirty(path->nodes[0]);
C
Chris Mason 已提交
456
	if (refs == 0) {
457
		u64 super_blocks_used;
C
Chris Mason 已提交
458 459

		if (pin) {
C
Chris Mason 已提交
460
			ret = pin_down_block(root, blocknr, 0);
C
Chris Mason 已提交
461 462 463
			BUG_ON(ret);
		}

464 465 466
		super_blocks_used = btrfs_super_blocks_used(info->disk_super);
		btrfs_set_super_blocks_used(info->disk_super,
					    super_blocks_used - num_blocks);
467
		ret = btrfs_del_item(trans, extent_root, path);
468 469
		if (ret)
			BUG();
C
Chris Mason 已提交
470 471
		ret = update_block_group(trans, root, blocknr, num_blocks, 0);
		BUG_ON(ret);
472
	}
473 474
	btrfs_release_path(extent_root, path);
	btrfs_free_path(path);
475
	finish_current_insert(trans, extent_root);
476 477 478 479 480 481 482
	return ret;
}

/*
 * find all the blocks marked as pending in the radix tree and remove
 * them from the extent map
 */
483 484
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
			       btrfs_root *extent_root)
485 486
{
	int ret;
C
Chris Mason 已提交
487 488
	int wret;
	int err = 0;
C
Chris Mason 已提交
489
	unsigned long gang[4];
490
	int i;
C
Chris Mason 已提交
491 492 493 494 495
	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;
496 497

	while(1) {
C
Chris Mason 已提交
498 499
		ret = find_first_radix_bit(pending_radix, gang,
					   ARRAY_SIZE(gang));
500 501 502
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
C
Chris Mason 已提交
503 504 505 506
			wret = set_radix_bit(pinned_radix, gang[i]);
			BUG_ON(wret);
			wret = clear_radix_bit(pending_radix, gang[i]);
			BUG_ON(wret);
507
			wret = __free_extent(trans, extent_root,
C
Chris Mason 已提交
508
					     gang[i], 1, 0);
C
Chris Mason 已提交
509 510
			if (wret)
				err = wret;
511 512
		}
	}
C
Chris Mason 已提交
513
	return err;
514 515 516 517 518
}

/*
 * remove an extent from the root, returns 0 on success
 */
519 520
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, u64 blocknr, u64 num_blocks, int pin)
521
{
522
	struct btrfs_root *extent_root = root->fs_info->extent_root;
523 524
	int pending_ret;
	int ret;
525

526
	if (root == extent_root) {
C
Chris Mason 已提交
527
		pin_down_block(root, blocknr, 1);
528 529
		return 0;
	}
C
Chris Mason 已提交
530
	ret = __free_extent(trans, root, blocknr, num_blocks, pin);
C
Chris Mason 已提交
531
	pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
532 533 534 535 536 537 538
	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
539
 * ins->flags = BTRFS_EXTENT_ITEM_KEY
540 541 542
 * ins->offset == number of blocks
 * Any available blocks before search_start are skipped.
 */
543 544 545
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)
546
{
547
	struct btrfs_path *path;
C
Chris Mason 已提交
548
	struct btrfs_key key;
549 550 551
	int ret;
	u64 hole_size = 0;
	int slot = 0;
C
Chris Mason 已提交
552
	u64 last_block = 0;
C
Chris Mason 已提交
553
	u64 test_block;
554
	int start_found;
C
Chris Mason 已提交
555
	struct btrfs_leaf *l;
556
	struct btrfs_root * root = orig_root->fs_info->extent_root;
557
	struct btrfs_fs_info *info = root->fs_info;
558
	int total_needed = num_blocks;
559 560
	int total_found = 0;
	int fill_prealloc = 0;
C
Chris Mason 已提交
561
	int level;
562 563
	int update_block_group = 0;
	struct btrfs_block_group_cache *hint_block_group;
564

565 566 567 568
	path = btrfs_alloc_path();
	ins->flags = 0;
	btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);

C
Chris Mason 已提交
569
	level = btrfs_header_level(btrfs_buffer_header(root->node));
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
	/* find search start here */
	if (0 && search_start && num_blocks) {
		u64 used;
		ret = radix_tree_gang_lookup(&info->block_group_radix,
					     (void **)&hint_block_group,
					     search_start, 1);
		if (ret) {
			used = btrfs_block_group_used(&hint_block_group->item);
			if (used > (hint_block_group->key.offset * 9) / 10)
				search_start = 0;
			else if (search_start < hint_block_group->last_alloc)
				search_start = hint_block_group->last_alloc;
		} else {
			search_start = 0;
		}
	}
586 587 588
	if (num_blocks == 0) {
		fill_prealloc = 1;
		num_blocks = 1;
589
		total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3;
590
	}
591 592 593 594 595 596 597 598
	if (1 || !search_start) {
		trans->block_group = btrfs_find_block_group(root,
							    trans->block_group,
							    0);
		if (trans->block_group->last_alloc > search_start)
			search_start = trans->block_group->last_alloc;
		update_block_group = 1;
	}
599
check_failed:
600
	btrfs_init_path(path);
601 602 603
	ins->objectid = search_start;
	ins->offset = 0;
	start_found = 0;
604
	ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
C
Chris Mason 已提交
605 606
	if (ret < 0)
		goto error;
C
Chris Mason 已提交
607

608 609
	if (path->slots[0] > 0)
		path->slots[0]--;
610

611
	while (1) {
612 613
		l = btrfs_buffer_leaf(path->nodes[0]);
		slot = path->slots[0];
614
		if (slot >= btrfs_header_nritems(&l->header)) {
615 616 617 618
			if (fill_prealloc) {
				info->extent_tree_prealloc_nr = 0;
				total_found = 0;
			}
619
			ret = btrfs_next_leaf(root, path);
620 621
			if (ret == 0)
				continue;
C
Chris Mason 已提交
622 623
			if (ret < 0)
				goto error;
624 625
			if (!start_found) {
				ins->objectid = search_start;
626
				ins->offset = (u64)-1 - search_start;
627 628 629 630 631
				start_found = 1;
				goto check_pending;
			}
			ins->objectid = last_block > search_start ?
					last_block : search_start;
632
			ins->offset = (u64)-1 - ins->objectid;
633 634
			goto check_pending;
		}
C
Chris Mason 已提交
635
		btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
C
Chris Mason 已提交
636 637
		if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY)
			goto next;
C
Chris Mason 已提交
638
		if (key.objectid >= search_start) {
639
			if (start_found) {
640 641
				if (last_block < search_start)
					last_block = search_start;
C
Chris Mason 已提交
642
				hole_size = key.objectid - last_block;
C
Chris Mason 已提交
643
				if (hole_size >= num_blocks) {
644
					ins->objectid = last_block;
C
Chris Mason 已提交
645
					ins->offset = hole_size;
646 647
					goto check_pending;
				}
648
			}
649
		}
650
		start_found = 1;
C
Chris Mason 已提交
651
		last_block = key.objectid + key.offset;
C
Chris Mason 已提交
652
next:
653
		path->slots[0]++;
654 655 656 657 658 659
	}
	// 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
	 */
660
	btrfs_release_path(root, path);
661
	BUG_ON(ins->objectid < search_start);
662 663 664 665 666 667
	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 已提交
668
	for (test_block = ins->objectid;
669 670
	     test_block < ins->objectid + num_blocks; test_block++) {
		if (test_radix_bit(&info->pinned_radix, test_block)) {
C
Chris Mason 已提交
671
			search_start = test_block + 1;
672 673 674
			goto check_failed;
		}
	}
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
	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 已提交
703
			info->extent_tree_prealloc[nr] = test_block;
704 705 706 707 708 709 710
			total_found++;
			test_block++;
		}
		if (total_found < total_needed) {
			search_start = test_block;
			goto check_failed;
		}
C
Chris Mason 已提交
711 712
		info->extent_tree_prealloc_nr = total_found;
	}
713 714 715 716 717 718 719
	if (update_block_group) {
		ret = radix_tree_gang_lookup(&info->block_group_radix,
					     (void **)&trans->block_group,
					     ins->objectid, 1);
		if (ret) {
			trans->block_group->last_alloc = ins->objectid;
		}
720
	}
C
Chris Mason 已提交
721
	ins->offset = num_blocks;
722
	btrfs_free_path(path);
723
	return 0;
C
Chris Mason 已提交
724
error:
725 726
	btrfs_release_path(root, path);
	btrfs_free_path(path);
C
Chris Mason 已提交
727
	return ret;
728 729 730 731 732 733 734 735
}
/*
 * 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.
 */
736 737
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
		       struct btrfs_root *root, u64 owner,
738
		       u64 num_blocks, u64 search_start,
739
		       u64 search_end, struct btrfs_key *ins)
740 741 742
{
	int ret;
	int pending_ret;
743 744 745
	u64 super_blocks_used;
	struct btrfs_fs_info *info = root->fs_info;
	struct btrfs_root *extent_root = info->extent_root;
C
Chris Mason 已提交
746
	struct btrfs_extent_item extent_item;
747
	struct btrfs_key prealloc_key;
C
Chris Mason 已提交
748

C
Chris Mason 已提交
749
	btrfs_set_extent_refs(&extent_item, 1);
750
	btrfs_set_extent_owner(&extent_item, owner);
751

C
Chris Mason 已提交
752
	if (root == extent_root) {
753 754
		int nr;
		BUG_ON(info->extent_tree_prealloc_nr == 0);
C
Chris Mason 已提交
755 756
		BUG_ON(num_blocks != 1);
		ins->offset = 1;
757 758 759 760 761
		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 已提交
762 763 764
		ret = update_block_group(trans, root,
					 ins->objectid, ins->offset, 1);
		BUG_ON(ret);
765 766
		return 0;
	}
767
	/* do the real allocation */
768
	ret = find_free_extent(trans, root, num_blocks, search_start,
C
Chris Mason 已提交
769 770 771
			       search_end, ins);
	if (ret)
		return ret;
772

773 774 775 776 777 778
	/* 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;

779 780 781
	super_blocks_used = btrfs_super_blocks_used(info->disk_super);
	btrfs_set_super_blocks_used(info->disk_super, super_blocks_used +
				    num_blocks);
782 783
	ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
				sizeof(extent_item));
C
Chris Mason 已提交
784

785
	finish_current_insert(trans, extent_root);
C
Chris Mason 已提交
786
	pending_ret = del_pending_extents(trans, extent_root);
C
Chris Mason 已提交
787 788 789 790
	if (ret)
		return ret;
	if (pending_ret)
		return pending_ret;
C
Chris Mason 已提交
791
	ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
C
Chris Mason 已提交
792
	return 0;
793 794 795 796 797 798
}

/*
 * helper function to allocate a block for a given tree
 * returns the tree buffer or NULL.
 */
C
Chris Mason 已提交
799
struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
800
					   struct btrfs_root *root, u64 hint)
801
{
C
Chris Mason 已提交
802
	struct btrfs_key ins;
803
	int ret;
C
Chris Mason 已提交
804
	struct buffer_head *buf;
805

806
	ret = btrfs_alloc_extent(trans, root, root->root_key.objectid,
807
				 1, hint, (unsigned long)-1, &ins);
808 809 810 811
	if (ret) {
		BUG();
		return NULL;
	}
C
Chris Mason 已提交
812
	BUG_ON(ret);
813
	buf = btrfs_find_create_tree_block(root, ins.objectid);
814
	set_buffer_uptodate(buf);
815
	set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index);
816 817
	return buf;
}
818

819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
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);
837 838
		if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE)
			continue;
839 840 841 842 843 844 845 846 847 848 849 850 851
		/*
		 * 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 已提交
852 853 854 855
/*
 * helper function for drop_snapshot, this walks down the tree dropping ref
 * counts as it goes.
 */
856 857
static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
			  *root, struct btrfs_path *path, int *level)
C
Chris Mason 已提交
858
{
C
Chris Mason 已提交
859 860
	struct buffer_head *next;
	struct buffer_head *cur;
C
Chris Mason 已提交
861 862 863 864
	u64 blocknr;
	int ret;
	u32 refs;

865 866
	WARN_ON(*level < 0);
	WARN_ON(*level >= BTRFS_MAX_LEVEL);
C
Chris Mason 已提交
867
	ret = lookup_extent_ref(trans, root, bh_blocknr(path->nodes[*level]),
868
			       1, &refs);
C
Chris Mason 已提交
869 870 871
	BUG_ON(ret);
	if (refs > 1)
		goto out;
C
Chris Mason 已提交
872 873 874
	/*
	 * walk down to the last node level and free all the leaves
	 */
875
	while(*level >= 0) {
876 877
		WARN_ON(*level < 0);
		WARN_ON(*level >= BTRFS_MAX_LEVEL);
C
Chris Mason 已提交
878
		cur = path->nodes[*level];
C
Chris Mason 已提交
879 880
		if (btrfs_header_level(btrfs_buffer_header(cur)) != *level)
			WARN_ON(1);
881
		if (path->slots[*level] >=
C
Chris Mason 已提交
882
		    btrfs_header_nritems(btrfs_buffer_header(cur)))
C
Chris Mason 已提交
883
			break;
884 885 886 887 888
		if (*level == 0) {
			ret = drop_leaf_ref(trans, root, cur);
			BUG_ON(ret);
			break;
		}
C
Chris Mason 已提交
889 890
		blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur),
					      path->slots[*level]);
C
Chris Mason 已提交
891
		ret = lookup_extent_ref(trans, root, blocknr, 1, &refs);
892 893
		BUG_ON(ret);
		if (refs != 1) {
C
Chris Mason 已提交
894
			path->slots[*level]++;
895
			ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
C
Chris Mason 已提交
896 897 898 899
			BUG_ON(ret);
			continue;
		}
		next = read_tree_block(root, blocknr);
900
		WARN_ON(*level <= 0);
C
Chris Mason 已提交
901
		if (path->nodes[*level-1])
C
Chris Mason 已提交
902
			btrfs_block_release(root, path->nodes[*level-1]);
C
Chris Mason 已提交
903
		path->nodes[*level-1] = next;
C
Chris Mason 已提交
904
		*level = btrfs_header_level(btrfs_buffer_header(next));
C
Chris Mason 已提交
905 906 907
		path->slots[*level] = 0;
	}
out:
908 909
	WARN_ON(*level < 0);
	WARN_ON(*level >= BTRFS_MAX_LEVEL);
910
	ret = btrfs_free_extent(trans, root,
911
				bh_blocknr(path->nodes[*level]), 1, 1);
C
Chris Mason 已提交
912
	btrfs_block_release(root, path->nodes[*level]);
C
Chris Mason 已提交
913 914 915 916 917 918
	path->nodes[*level] = NULL;
	*level += 1;
	BUG_ON(ret);
	return 0;
}

C
Chris Mason 已提交
919 920 921 922 923
/*
 * 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
 */
924 925
static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
			*root, struct btrfs_path *path, int *level)
C
Chris Mason 已提交
926 927 928 929
{
	int i;
	int slot;
	int ret;
C
Chris Mason 已提交
930
	for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
C
Chris Mason 已提交
931
		slot = path->slots[i];
C
Chris Mason 已提交
932 933
		if (slot < btrfs_header_nritems(
		    btrfs_buffer_header(path->nodes[i])) - 1) {
C
Chris Mason 已提交
934 935 936 937
			path->slots[i]++;
			*level = i;
			return 0;
		} else {
938
			ret = btrfs_free_extent(trans, root,
939
						bh_blocknr(path->nodes[*level]),
940
						1, 1);
941
			BUG_ON(ret);
C
Chris Mason 已提交
942
			btrfs_block_release(root, path->nodes[*level]);
C
Chris Mason 已提交
943
			path->nodes[*level] = NULL;
C
Chris Mason 已提交
944 945 946 947 948 949
			*level = i + 1;
		}
	}
	return 1;
}

C
Chris Mason 已提交
950 951 952 953 954
/*
 * 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.
 */
955
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
C
Chris Mason 已提交
956
			*root, struct buffer_head *snap)
C
Chris Mason 已提交
957
{
958
	int ret = 0;
C
Chris Mason 已提交
959
	int wret;
C
Chris Mason 已提交
960
	int level;
961
	struct btrfs_path *path;
C
Chris Mason 已提交
962 963 964
	int i;
	int orig_level;

965 966 967
	path = btrfs_alloc_path();
	BUG_ON(!path);
	btrfs_init_path(path);
C
Chris Mason 已提交
968

C
Chris Mason 已提交
969
	level = btrfs_header_level(btrfs_buffer_header(snap));
C
Chris Mason 已提交
970
	orig_level = level;
971 972
	path->nodes[level] = snap;
	path->slots[level] = 0;
C
Chris Mason 已提交
973
	while(1) {
974
		wret = walk_down_tree(trans, root, path, &level);
C
Chris Mason 已提交
975
		if (wret > 0)
C
Chris Mason 已提交
976
			break;
C
Chris Mason 已提交
977 978 979
		if (wret < 0)
			ret = wret;

980
		wret = walk_up_tree(trans, root, path, &level);
C
Chris Mason 已提交
981
		if (wret > 0)
C
Chris Mason 已提交
982
			break;
C
Chris Mason 已提交
983 984
		if (wret < 0)
			ret = wret;
C
Chris Mason 已提交
985
	}
C
Chris Mason 已提交
986
	for (i = 0; i <= orig_level; i++) {
987 988
		if (path->nodes[i]) {
			btrfs_block_release(root, path->nodes[i]);
C
Chris Mason 已提交
989
		}
C
Chris Mason 已提交
990
	}
991
	btrfs_free_path(path);
C
Chris Mason 已提交
992
	return ret;
C
Chris Mason 已提交
993
}
C
Chris Mason 已提交
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

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;
1028
	u64 used;
C
Chris Mason 已提交
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058

	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));
1059 1060
		cache->last_alloc = cache->key.objectid;
		cache->first_free = cache->key.objectid;
C
Chris Mason 已提交
1061 1062 1063 1064 1065 1066 1067
		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);
1068 1069 1070 1071 1072 1073 1074
		used = btrfs_block_group_used(bi);
		if (used < (key.offset * 2) / 3) {
			radix_tree_tag_set(&root->fs_info->block_group_radix,
					   found_key.objectid +
					   found_key.offset - 1,
					   BTRFS_BLOCK_GROUP_AVAIL);
		}
C
Chris Mason 已提交
1075 1076 1077 1078 1079 1080 1081 1082
		if (key.objectid >=
		    btrfs_super_total_blocks(root->fs_info->disk_super))
			break;
	}

	btrfs_free_path(path);
	return 0;
}