disk-io.c 20.0 KB
Newer Older
C
Chris Mason 已提交
1 2
#include <linux/module.h>
#include <linux/fs.h>
3
#include <linux/blkdev.h>
C
Chris Mason 已提交
4 5
#include <linux/crypto.h>
#include <linux/scatterlist.h>
C
Chris Mason 已提交
6
#include <linux/swap.h>
7
#include <linux/radix-tree.h>
C
Chris Mason 已提交
8
#include <linux/writeback.h>
9 10
#include "ctree.h"
#include "disk-io.h"
11
#include "transaction.h"
12
#include "btrfs_inode.h"
13

14 15 16
struct dev_lookup {
	u64 block_start;
	u64 num_blocks;
17
	u64 device_id;
18 19 20
	struct block_device *bdev;
};

21 22
int btrfs_insert_dev_radix(struct btrfs_root *root,
			   struct block_device *bdev,
23
			   u64 device_id,
24 25 26 27 28 29 30 31 32 33 34 35
			   u64 block_start,
			   u64 num_blocks)
{
	struct dev_lookup *lookup;
	int ret;

	lookup = kmalloc(sizeof(*lookup), GFP_NOFS);
	if (!lookup)
		return -ENOMEM;
	lookup->block_start = block_start;
	lookup->num_blocks = num_blocks;
	lookup->bdev = bdev;
36
	lookup->device_id = device_id;
37 38 39 40 41 42

	ret = radix_tree_insert(&root->fs_info->dev_radix, block_start +
				num_blocks - 1, lookup);
	return ret;
}

43 44 45 46 47 48 49 50 51 52 53 54 55 56
u64 bh_blocknr(struct buffer_head *bh)
{
	int blkbits = bh->b_page->mapping->host->i_blkbits;
	u64 blocknr = bh->b_page->index << (PAGE_CACHE_SHIFT - blkbits);
	unsigned long offset;

	if (PageHighMem(bh->b_page))
		offset = (unsigned long)bh->b_data;
	else
		offset = bh->b_data - (char *)page_address(bh->b_page);
	blocknr += offset >> (PAGE_CACHE_SHIFT - blkbits);
	return blocknr;
}

C
Chris Mason 已提交
57
static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf)
58
{
C
Chris Mason 已提交
59
	struct btrfs_node *node = btrfs_buffer_node(buf);
60
	if (bh_blocknr(buf) != btrfs_header_blocknr(&node->header)) {
61 62
		printk(KERN_CRIT "bh_blocknr(buf) is %Lu, header is %Lu\n",
		       bh_blocknr(buf), btrfs_header_blocknr(&node->header));
63
		BUG();
64
	}
65
	return 0;
66 67
}

68 69 70 71 72 73 74 75 76 77
struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr)
{
	struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
	int blockbits = root->fs_info->sb->s_blocksize_bits;
	unsigned long index = blocknr >> (PAGE_CACHE_SHIFT - blockbits);
	struct page *page;
	struct buffer_head *bh;
	struct buffer_head *head;
	struct buffer_head *ret = NULL;

C
Chris Mason 已提交
78

79 80 81 82 83 84 85 86 87 88
	page = find_lock_page(mapping, index);
	if (!page)
		return NULL;

	if (!page_has_buffers(page))
		goto out_unlock;

	head = page_buffers(page);
	bh = head;
	do {
89
		if (buffer_mapped(bh) && bh_blocknr(bh) == blocknr) {
90 91 92 93 94 95 96 97 98 99 100 101
			ret = bh;
			get_bh(bh);
			goto out_unlock;
		}
		bh = bh->b_this_page;
	} while (bh != head);
out_unlock:
	unlock_page(page);
	page_cache_release(page);
	return ret;
}

102
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh,
103 104 105 106 107 108
			     u64 logical)
{
	struct dev_lookup *lookup[2];

	int ret;

109 110 111 112 113 114
	if (logical == 0) {
		bh->b_bdev = NULL;
		bh->b_blocknr = 0;
		set_buffer_mapped(bh);
		return 0;
	}
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
	root = root->fs_info->dev_root;
	ret = radix_tree_gang_lookup(&root->fs_info->dev_radix,
				     (void **)lookup,
				     (unsigned long)logical,
				     ARRAY_SIZE(lookup));
	if (ret == 0 || lookup[0]->block_start > logical ||
	    lookup[0]->block_start + lookup[0]->num_blocks <= logical) {
		ret = -ENOENT;
		goto out;
	}
	bh->b_bdev = lookup[0]->bdev;
	bh->b_blocknr = logical - lookup[0]->block_start;
	set_buffer_mapped(bh);
	ret = 0;
out:
	return ret;
}

133 134 135 136 137 138 139 140 141 142
struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root,
						 u64 blocknr)
{
	struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
	int blockbits = root->fs_info->sb->s_blocksize_bits;
	unsigned long index = blocknr >> (PAGE_CACHE_SHIFT - blockbits);
	struct page *page;
	struct buffer_head *bh;
	struct buffer_head *head;
	struct buffer_head *ret = NULL;
143
	int err;
144
	u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits);
C
Chris Mason 已提交
145

146 147 148 149 150 151 152 153 154 155
	page = grab_cache_page(mapping, index);
	if (!page)
		return NULL;

	if (!page_has_buffers(page))
		create_empty_buffers(page, root->fs_info->sb->s_blocksize, 0);
	head = page_buffers(page);
	bh = head;
	do {
		if (!buffer_mapped(bh)) {
156
			err = btrfs_map_bh_to_logical(root, bh, first_block);
157
			BUG_ON(err);
158
		}
159
		if (bh_blocknr(bh) == blocknr) {
160 161 162 163 164 165 166 167 168
			ret = bh;
			get_bh(bh);
			goto out_unlock;
		}
		bh = bh->b_this_page;
		first_block++;
	} while (bh != head);
out_unlock:
	unlock_page(page);
C
Chris Mason 已提交
169 170
	if (ret)
		touch_buffer(ret);
171 172 173 174 175 176 177
	page_cache_release(page);
	return ret;
}

static int btree_get_block(struct inode *inode, sector_t iblock,
			   struct buffer_head *bh, int create)
{
178 179
	int err;
	struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root;
180
	err = btrfs_map_bh_to_logical(root, bh, iblock);
181
	return err;
182 183
}

C
Chris Mason 已提交
184 185
int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len,
		    char *result)
C
Chris Mason 已提交
186 187 188 189 190 191 192 193
{
	struct scatterlist sg;
	struct crypto_hash *tfm = root->fs_info->hash_tfm;
	struct hash_desc desc;
	int ret;

	desc.tfm = tfm;
	desc.flags = 0;
C
Chris Mason 已提交
194
	sg_init_one(&sg, data, len);
C
Chris Mason 已提交
195
	spin_lock(&root->fs_info->hash_lock);
C
Chris Mason 已提交
196
	ret = crypto_hash_digest(&desc, &sg, 1, result);
C
Chris Mason 已提交
197 198 199 200
	spin_unlock(&root->fs_info->hash_lock);
	if (ret) {
		printk("sha256 digest failed\n");
	}
C
Chris Mason 已提交
201 202 203 204 205 206 207 208 209 210 211 212 213
	return ret;
}
static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh,
			   int verify)
{
	char result[BTRFS_CSUM_SIZE];
	int ret;
	struct btrfs_node *node;

	ret = btrfs_csum_data(root, bh->b_data + BTRFS_CSUM_SIZE,
			      bh->b_size - BTRFS_CSUM_SIZE, result);
	if (ret)
		return ret;
C
Chris Mason 已提交
214
	if (verify) {
C
Chris Mason 已提交
215
		if (memcmp(bh->b_data, result, BTRFS_CSUM_SIZE)) {
216 217
			printk("checksum verify failed on %Lu\n",
			       bh_blocknr(bh));
C
Chris Mason 已提交
218 219 220 221
			return 1;
		}
	} else {
		node = btrfs_buffer_node(bh);
C
Chris Mason 已提交
222
		memcpy(node->header.csum, result, BTRFS_CSUM_SIZE);
C
Chris Mason 已提交
223
	}
C
Chris Mason 已提交
224 225 226
	return 0;
}

227
static int btree_writepage(struct page *page, struct writeback_control *wbc)
228
{
C
Chris Mason 已提交
229
	struct buffer_head *bh;
230
	struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
C
Chris Mason 已提交
231 232 233 234 235 236 237 238 239 240 241 242
	struct buffer_head *head;
	if (!page_has_buffers(page)) {
		create_empty_buffers(page, root->fs_info->sb->s_blocksize,
					(1 << BH_Dirty)|(1 << BH_Uptodate));
	}
	head = page_buffers(page);
	bh = head;
	do {
		if (buffer_dirty(bh))
			csum_tree_block(root, bh, 0);
		bh = bh->b_this_page;
	} while (bh != head);
243
	return block_write_full_page(page, btree_get_block, wbc);
244 245
}

246
static int btree_readpage(struct file * file, struct page * page)
247
{
248
	return block_read_full_page(page, btree_get_block);
249 250
}

251 252 253 254 255 256
static struct address_space_operations btree_aops = {
	.readpage	= btree_readpage,
	.writepage	= btree_writepage,
	.sync_page	= block_sync_page,
};

C
Chris Mason 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
int readahead_tree_block(struct btrfs_root *root, u64 blocknr)
{
	struct buffer_head *bh = NULL;

	bh = btrfs_find_create_tree_block(root, blocknr);
	if (!bh)
		return 0;
	if (buffer_uptodate(bh))
		goto done;
	if (test_set_buffer_locked(bh))
		goto done;
	if (!buffer_uptodate(bh)) {
		get_bh(bh);
		bh->b_end_io = end_buffer_read_sync;
		submit_bh(READ, bh);
	} else {
		unlock_buffer(bh);
	}
done:
	brelse(bh);
	return 0;
}

C
Chris Mason 已提交
280
struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
281
{
282
	struct buffer_head *bh = NULL;
283

284 285 286
	bh = btrfs_find_create_tree_block(root, blocknr);
	if (!bh)
		return bh;
287 288
	if (buffer_uptodate(bh))
		goto uptodate;
289 290 291 292 293 294 295 296 297 298 299
	lock_buffer(bh);
	if (!buffer_uptodate(bh)) {
		get_bh(bh);
		bh->b_end_io = end_buffer_read_sync;
		submit_bh(READ, bh);
		wait_on_buffer(bh);
		if (!buffer_uptodate(bh))
			goto fail;
	} else {
		unlock_buffer(bh);
	}
300
uptodate:
C
Chris Mason 已提交
301 302 303 304
	if (!buffer_checked(bh)) {
		csum_tree_block(root, bh, 1);
		set_buffer_checked(bh);
	}
305
	if (check_tree_block(root, bh))
C
Chris Mason 已提交
306
		BUG();
307 308 309 310
	return bh;
fail:
	brelse(bh);
	return NULL;
311 312
}

313
int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
C
Chris Mason 已提交
314
		     struct buffer_head *buf)
315
{
C
Chris Mason 已提交
316
	WARN_ON(atomic_read(&buf->b_count) == 0);
C
Chris Mason 已提交
317
	mark_buffer_dirty(buf);
318 319 320
	return 0;
}

321
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
C
Chris Mason 已提交
322
		     struct buffer_head *buf)
323
{
C
Chris Mason 已提交
324
	WARN_ON(atomic_read(&buf->b_count) == 0);
C
Chris Mason 已提交
325
	clear_buffer_dirty(buf);
326 327 328
	return 0;
}

C
Chris Mason 已提交
329
static int __setup_root(int blocksize,
330 331
			struct btrfs_root *root,
			struct btrfs_fs_info *fs_info,
C
Chris Mason 已提交
332
			u64 objectid)
333
{
C
Chris Mason 已提交
334
	root->node = NULL;
335
	root->inode = NULL;
336
	root->commit_root = NULL;
C
Chris Mason 已提交
337
	root->blocksize = blocksize;
C
Chris Mason 已提交
338
	root->ref_cows = 0;
339
	root->fs_info = fs_info;
340 341
	root->objectid = objectid;
	root->last_trans = 0;
C
Chris Mason 已提交
342 343
	root->highest_inode = 0;
	root->last_inode_alloc = 0;
344 345
	memset(&root->root_key, 0, sizeof(root->root_key));
	memset(&root->root_item, 0, sizeof(root->root_item));
346
	root->root_key.objectid = objectid;
347 348 349
	return 0;
}

C
Chris Mason 已提交
350
static int find_and_setup_root(int blocksize,
351 352 353
			       struct btrfs_root *tree_root,
			       struct btrfs_fs_info *fs_info,
			       u64 objectid,
C
Chris Mason 已提交
354
			       struct btrfs_root *root)
355 356 357
{
	int ret;

C
Chris Mason 已提交
358
	__setup_root(blocksize, root, fs_info, objectid);
359 360 361 362 363 364 365
	ret = btrfs_find_last_root(tree_root, objectid,
				   &root->root_item, &root->root_key);
	BUG_ON(ret);

	root->node = read_tree_block(root,
				     btrfs_root_blocknr(&root->root_item));
	BUG_ON(!root->node);
366 367 368
	return 0;
}

369 370 371 372 373 374 375
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
				      struct btrfs_key *location)
{
	struct btrfs_root *root;
	struct btrfs_root *tree_root = fs_info->tree_root;
	struct btrfs_path *path;
	struct btrfs_leaf *l;
C
Chris Mason 已提交
376
	u64 highest_inode;
377 378 379
	int ret = 0;

printk("read_fs_root looking for %Lu %Lu %u\n", location->objectid, location->offset, location->flags);
C
Chris Mason 已提交
380 381 382 383 384 385
	root = radix_tree_lookup(&fs_info->fs_roots_radix,
				 (unsigned long)location->objectid);
	if (root) {
printk("found %p in cache\n", root);
		return root;
	}
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
	root = kmalloc(sizeof(*root), GFP_NOFS);
	if (!root) {
printk("failed1\n");
		return ERR_PTR(-ENOMEM);
	}
	if (location->offset == (u64)-1) {
		ret = find_and_setup_root(fs_info->sb->s_blocksize,
					  fs_info->tree_root, fs_info,
					  location->objectid, root);
		if (ret) {
printk("failed2\n");
			kfree(root);
			return ERR_PTR(ret);
		}
		goto insert;
	}

	__setup_root(fs_info->sb->s_blocksize, root, fs_info,
		     location->objectid);

	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
	if (ret != 0) {
printk("internal search_slot gives us %d\n", ret);
		if (ret > 0)
			ret = -ENOENT;
		goto out;
	}
	l = btrfs_buffer_leaf(path->nodes[0]);
	memcpy(&root->root_item,
	       btrfs_item_ptr(l, path->slots[0], struct btrfs_root_item),
	       sizeof(root->root_item));
	memcpy(&root->root_key, location, sizeof(*location));
	ret = 0;
out:
	btrfs_release_path(root, path);
	btrfs_free_path(path);
	if (ret) {
		kfree(root);
		return ERR_PTR(ret);
	}
	root->node = read_tree_block(root,
				     btrfs_root_blocknr(&root->root_item));
	BUG_ON(!root->node);
insert:
printk("inserting %p\n", root);
	root->ref_cows = 1;
C
Chris Mason 已提交
434 435
	ret = radix_tree_insert(&fs_info->fs_roots_radix,
				(unsigned long)root->root_key.objectid,
436 437 438 439 440 441 442
				root);
	if (ret) {
printk("radix_tree_insert gives us %d\n", ret);
		brelse(root->node);
		kfree(root);
		return ERR_PTR(ret);
	}
C
Chris Mason 已提交
443 444 445 446 447 448
	ret = btrfs_find_highest_inode(root, &highest_inode);
	if (ret == 0) {
		root->highest_inode = highest_inode;
		root->last_inode_alloc = highest_inode;
printk("highest inode is %Lu\n", highest_inode);
	}
449 450 451 452
printk("all worked\n");
	return root;
}

453 454 455
static int btrfs_open_disk(struct btrfs_root *root, u64 device_id,
			   u64 block_start, u64 num_blocks,
			   char *filename, int name_len)
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
{
	char *null_filename;
	struct block_device *bdev;
	int ret;

	null_filename = kmalloc(name_len + 1, GFP_NOFS);
	if (!null_filename)
		return -ENOMEM;
	memcpy(null_filename, filename, name_len);
	null_filename[name_len] = '\0';

	bdev = open_bdev_excl(null_filename, O_RDWR, root->fs_info->sb);
	if (IS_ERR(bdev)) {
		ret = PTR_ERR(bdev);
		goto out;
	}
	set_blocksize(bdev, root->fs_info->sb->s_blocksize);
473 474
	ret = btrfs_insert_dev_radix(root, bdev, device_id,
				     block_start, num_blocks);
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
	BUG_ON(ret);
	ret = 0;
out:
	kfree(null_filename);
	return ret;
}

static int read_device_info(struct btrfs_root *root)
{
	struct btrfs_path *path;
	int ret;
	struct btrfs_key key;
	struct btrfs_leaf *leaf;
	struct btrfs_device_item *dev_item;
	int nritems;
	int slot;

	root = root->fs_info->dev_root;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
	key.objectid = 0;
	key.offset = 0;
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_DEV_ITEM_KEY);

	mutex_lock(&root->fs_info->fs_mutex);
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	leaf = btrfs_buffer_leaf(path->nodes[0]);
	nritems = btrfs_header_nritems(&leaf->header);
	while(1) {
		slot = path->slots[0];
		if (slot >= nritems) {
			ret = btrfs_next_leaf(root, path);
			if (ret)
				break;
			leaf = btrfs_buffer_leaf(path->nodes[0]);
			nritems = btrfs_header_nritems(&leaf->header);
			slot = path->slots[0];
		}
		btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key);
		if (btrfs_key_type(&key) != BTRFS_DEV_ITEM_KEY) {
			path->slots[0]++;
			continue;
		}
		dev_item = btrfs_item_ptr(leaf, slot, struct btrfs_device_item);
printk("found key %Lu %Lu\n", key.objectid, key.offset);
523 524 525 526 527 528 529 530
		if (btrfs_device_id(dev_item) !=
		    btrfs_super_device_id(root->fs_info->disk_super)) {
			ret = btrfs_open_disk(root, btrfs_device_id(dev_item),
					      key.objectid, key.offset,
					      (char *)(dev_item + 1),
					      btrfs_device_pathlen(dev_item));
			BUG_ON(ret);
		}
531 532 533 534 535 536 537
		path->slots[0]++;
	}
	btrfs_free_path(path);
	mutex_unlock(&root->fs_info->fs_mutex);
	return 0;
}

C
Chris Mason 已提交
538
struct btrfs_root *open_ctree(struct super_block *sb)
539
{
C
Chris Mason 已提交
540 541
	struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root),
						 GFP_NOFS);
542 543
	struct btrfs_root *dev_root = kmalloc(sizeof(struct btrfs_root),
						 GFP_NOFS);
C
Chris Mason 已提交
544 545 546 547
	struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root),
					       GFP_NOFS);
	struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info),
						GFP_NOFS);
548
	int ret;
C
Chris Mason 已提交
549
	struct btrfs_super_block *disk_super;
550
	struct dev_lookup *dev_lookup;
551

C
Chris Mason 已提交
552 553
	init_bit_radix(&fs_info->pinned_radix);
	init_bit_radix(&fs_info->pending_del_radix);
554
	init_bit_radix(&fs_info->extent_map_radix);
555
	INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS);
556
	INIT_RADIX_TREE(&fs_info->dev_radix, GFP_NOFS);
C
Chris Mason 已提交
557
	INIT_RADIX_TREE(&fs_info->block_group_radix, GFP_KERNEL);
C
Chris Mason 已提交
558
	INIT_RADIX_TREE(&fs_info->block_group_data_radix, GFP_KERNEL);
C
Chris Mason 已提交
559
	INIT_LIST_HEAD(&fs_info->trans_list);
C
Chris Mason 已提交
560
	sb_set_blocksize(sb, 4096);
561 562 563
	fs_info->running_transaction = NULL;
	fs_info->tree_root = tree_root;
	fs_info->extent_root = extent_root;
564
	fs_info->dev_root = dev_root;
C
Chris Mason 已提交
565
	fs_info->sb = sb;
566 567
	fs_info->btree_inode = new_inode(sb);
	fs_info->btree_inode->i_ino = 1;
C
Chris Mason 已提交
568
	fs_info->btree_inode->i_nlink = 1;
569 570
	fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size;
	fs_info->btree_inode->i_mapping->a_ops = &btree_aops;
571
	fs_info->do_barriers = 1;
572 573
	fs_info->extent_tree_insert_nr = 0;
	fs_info->extent_tree_prealloc_nr = 0;
574 575 576
	BTRFS_I(fs_info->btree_inode)->root = tree_root;
	memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
	       sizeof(struct btrfs_key));
C
Chris Mason 已提交
577
	insert_inode_hash(fs_info->btree_inode);
578
	mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
C
Chris Mason 已提交
579
	fs_info->hash_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
C
Chris Mason 已提交
580 581
	spin_lock_init(&fs_info->hash_lock);
	if (!fs_info->hash_tfm || IS_ERR(fs_info->hash_tfm)) {
C
Chris Mason 已提交
582 583 584
		printk("failed to allocate sha256 hash\n");
		return NULL;
	}
C
Chris Mason 已提交
585
	mutex_init(&fs_info->trans_mutex);
C
Chris Mason 已提交
586
	mutex_init(&fs_info->fs_mutex);
587

588 589 590
	__setup_root(sb->s_blocksize, dev_root,
		     fs_info, BTRFS_DEV_TREE_OBJECTID);

C
Chris Mason 已提交
591 592
	__setup_root(sb->s_blocksize, tree_root,
		     fs_info, BTRFS_ROOT_TREE_OBJECTID);
593 594 595 596 597

	dev_lookup = kmalloc(sizeof(*dev_lookup), GFP_NOFS);
	dev_lookup->block_start = 0;
	dev_lookup->num_blocks = (u32)-2;
	dev_lookup->bdev = sb->s_bdev;
598
	dev_lookup->device_id = 0;
599 600
	ret = radix_tree_insert(&fs_info->dev_radix, (u32)-2, dev_lookup);
	BUG_ON(ret);
C
Chris Mason 已提交
601 602 603
	fs_info->sb_buffer = read_tree_block(tree_root,
					     BTRFS_SUPER_INFO_OFFSET /
					     sb->s_blocksize);
604

605
	if (!fs_info->sb_buffer)
606 607
		return NULL;
	disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data;
608
	if (!btrfs_super_root(disk_super))
C
Chris Mason 已提交
609
		return NULL;
610

611 612 613 614
	i_size_write(fs_info->btree_inode,
		     btrfs_super_total_blocks(disk_super) <<
		     fs_info->btree_inode->i_blkbits);

615 616 617
	radix_tree_delete(&fs_info->dev_radix, (u32)-2);
	dev_lookup->block_start = btrfs_super_device_block_start(disk_super);
	dev_lookup->num_blocks = btrfs_super_device_num_blocks(disk_super);
618 619
	dev_lookup->device_id = btrfs_super_device_id(disk_super);

620 621
	ret = radix_tree_insert(&fs_info->dev_radix,
				dev_lookup->block_start +
622
				dev_lookup->num_blocks - 1, dev_lookup);
623 624
	BUG_ON(ret);

625
	fs_info->disk_super = disk_super;
626

627 628
	dev_root->node = read_tree_block(tree_root,
					  btrfs_super_device_root(disk_super));
629 630 631 632

	ret = read_device_info(dev_root);
	BUG_ON(ret);

C
Chris Mason 已提交
633 634
	tree_root->node = read_tree_block(tree_root,
					  btrfs_super_root(disk_super));
635 636
	BUG_ON(!tree_root->node);

C
Chris Mason 已提交
637 638
	mutex_lock(&fs_info->fs_mutex);
	ret = find_and_setup_root(sb->s_blocksize, tree_root, fs_info,
C
Chris Mason 已提交
639
				  BTRFS_EXTENT_TREE_OBJECTID, extent_root);
640 641
	BUG_ON(ret);

C
Chris Mason 已提交
642 643
	btrfs_read_block_groups(extent_root);

644
	fs_info->generation = btrfs_super_generation(disk_super) + 1;
645 646 647 648
	memset(&fs_info->kobj, 0, sizeof(fs_info->kobj));
	kobj_set_kset_s(fs_info, btrfs_subsys);
	kobject_set_name(&fs_info->kobj, "%s", sb->s_id);
	kobject_register(&fs_info->kobj);
C
Chris Mason 已提交
649
	mutex_unlock(&fs_info->fs_mutex);
650
	return tree_root;
651 652
}

653
int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
C
Chris Mason 已提交
654
		      *root)
655
{
656
	int ret;
657
	struct buffer_head *bh = root->fs_info->sb_buffer;
C
Chris Mason 已提交
658

659
	btrfs_set_super_root(root->fs_info->disk_super,
660
			     bh_blocknr(root->fs_info->tree_root->node));
661
	lock_buffer(bh);
C
Chris Mason 已提交
662
	WARN_ON(atomic_read(&bh->b_count) < 1);
663
	clear_buffer_dirty(bh);
C
Chris Mason 已提交
664
	csum_tree_block(root, bh, 0);
665 666
	bh->b_end_io = end_buffer_write_sync;
	get_bh(bh);
667 668 669 670 671 672 673 674 675
	if (root->fs_info->do_barriers)
		ret = submit_bh(WRITE_BARRIER, bh);
	else
		ret = submit_bh(WRITE, bh);
	if (ret == -EOPNOTSUPP) {
		set_buffer_uptodate(bh);
		root->fs_info->do_barriers = 0;
		ret = submit_bh(WRITE, bh);
	}
676 677 678 679
	wait_on_buffer(bh);
	if (!buffer_uptodate(bh)) {
		WARN_ON(1);
		return -EIO;
C
Chris Mason 已提交
680 681 682 683
	}
	return 0;
}

C
Chris Mason 已提交
684 685 686 687 688 689 690 691 692 693 694 695 696 697
static int free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
{
	radix_tree_delete(&fs_info->fs_roots_radix,
			  (unsigned long)root->root_key.objectid);
	if (root->inode)
		iput(root->inode);
	if (root->node)
		brelse(root->node);
	if (root->commit_root)
		brelse(root->commit_root);
	kfree(root);
	return 0;
}

C
Chris Mason 已提交
698
static int del_fs_roots(struct btrfs_fs_info *fs_info)
699 700 701 702 703 704 705 706 707 708 709
{
	int ret;
	struct btrfs_root *gang[8];
	int i;

	while(1) {
		ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
					     (void **)gang, 0,
					     ARRAY_SIZE(gang));
		if (!ret)
			break;
C
Chris Mason 已提交
710 711
		for (i = 0; i < ret; i++)
			free_fs_root(fs_info, gang[i]);
712 713 714
	}
	return 0;
}
715

716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
static int free_dev_radix(struct btrfs_fs_info *fs_info)
{
	struct dev_lookup *lookup[8];
	struct block_device *super_bdev = fs_info->sb->s_bdev;
	int ret;
	int i;
	while(1) {
		ret = radix_tree_gang_lookup(&fs_info->dev_radix,
					     (void **)lookup, 0,
					     ARRAY_SIZE(lookup));
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
			if (lookup[i]->bdev != super_bdev)
				close_bdev_excl(lookup[i]->bdev);
			radix_tree_delete(&fs_info->dev_radix,
					  lookup[i]->block_start +
733
					  lookup[i]->num_blocks - 1);
734 735 736 737 738
			kfree(lookup[i]);
		}
	}
	return 0;
}
739

C
Chris Mason 已提交
740
int close_ctree(struct btrfs_root *root)
C
Chris Mason 已提交
741
{
742
	int ret;
743
	struct btrfs_trans_handle *trans;
744
	struct btrfs_fs_info *fs_info = root->fs_info;
745

746
	mutex_lock(&fs_info->fs_mutex);
C
Chris Mason 已提交
747 748 749 750 751 752
	trans = btrfs_start_transaction(root, 1);
	btrfs_commit_transaction(trans, root);
	/* run commit again to  drop the original snapshot */
	trans = btrfs_start_transaction(root, 1);
	btrfs_commit_transaction(trans, root);
	ret = btrfs_write_and_wait_transaction(NULL, root);
753
	BUG_ON(ret);
C
Chris Mason 已提交
754
	write_ctree_super(NULL, root);
755 756 757 758 759
	mutex_unlock(&fs_info->fs_mutex);

	if (fs_info->extent_root->node)
		btrfs_block_release(fs_info->extent_root,
				    fs_info->extent_root->node);
760 761 762
	if (fs_info->dev_root->node)
		btrfs_block_release(fs_info->dev_root,
				    fs_info->dev_root->node);
763 764 765 766 767 768 769
	if (fs_info->tree_root->node)
		btrfs_block_release(fs_info->tree_root,
				    fs_info->tree_root->node);
	btrfs_block_release(root, fs_info->sb_buffer);
	crypto_free_hash(fs_info->hash_tfm);
	truncate_inode_pages(fs_info->btree_inode->i_mapping, 0);
	iput(fs_info->btree_inode);
770 771

	free_dev_radix(fs_info);
C
Chris Mason 已提交
772
	btrfs_free_block_groups(root->fs_info);
773 774 775 776
	del_fs_roots(fs_info);
	kfree(fs_info->extent_root);
	kfree(fs_info->tree_root);
	kobject_unregister(&fs_info->kobj);
777 778 779
	return 0;
}

C
Chris Mason 已提交
780
void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
781
{
C
Chris Mason 已提交
782
	brelse(buf);
783 784
}

C
Chris Mason 已提交
785 786 787 788
void btrfs_btree_balance_dirty(struct btrfs_root *root)
{
	balance_dirty_pages_ratelimited(root->fs_info->btree_inode->i_mapping);
}