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

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

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

	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;
597
	dev_lookup->device_id = 0;
598 599
	ret = radix_tree_insert(&fs_info->dev_radix, (u32)-2, dev_lookup);
	BUG_ON(ret);
C
Chris Mason 已提交
600 601 602
	fs_info->sb_buffer = read_tree_block(tree_root,
					     BTRFS_SUPER_INFO_OFFSET /
					     sb->s_blocksize);
603

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

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

614 615 616
	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);
617 618
	dev_lookup->device_id = btrfs_super_device_id(disk_super);

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

624
	fs_info->disk_super = disk_super;
625

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

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

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

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

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

643
	fs_info->generation = btrfs_super_generation(disk_super) + 1;
644 645 646 647
	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 已提交
648
	mutex_unlock(&fs_info->fs_mutex);
649
	return tree_root;
650 651
}

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

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

C
Chris Mason 已提交
683 684 685 686 687 688 689 690 691 692 693 694 695 696
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 已提交
697
static int del_fs_roots(struct btrfs_fs_info *fs_info)
698 699 700 701 702 703 704 705 706 707 708
{
	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 已提交
709 710
		for (i = 0; i < ret; i++)
			free_fs_root(fs_info, gang[i]);
711 712 713
	}
	return 0;
}
714

715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
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 +
732
					  lookup[i]->num_blocks - 1);
733 734 735 736 737
			kfree(lookup[i]);
		}
	}
	return 0;
}
738

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

745
	mutex_lock(&fs_info->fs_mutex);
C
Chris Mason 已提交
746 747 748 749 750 751
	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);
752
	BUG_ON(ret);
C
Chris Mason 已提交
753
	write_ctree_super(NULL, root);
754 755 756 757 758
	mutex_unlock(&fs_info->fs_mutex);

	if (fs_info->extent_root->node)
		btrfs_block_release(fs_info->extent_root,
				    fs_info->extent_root->node);
759 760 761
	if (fs_info->dev_root->node)
		btrfs_block_release(fs_info->dev_root,
				    fs_info->dev_root->node);
762 763 764 765 766 767 768
	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);
769 770

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

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

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