disk-io.c 15.9 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>
8 9
#include "ctree.h"
#include "disk-io.h"
10
#include "transaction.h"
11
#include "btrfs_inode.h"
12

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
struct dev_lookup {
	u64 block_start;
	u64 num_blocks;
	struct block_device *bdev;
};

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 已提交
33
static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf)
34
{
C
Chris Mason 已提交
35
	struct btrfs_node *node = btrfs_buffer_node(buf);
36
	if (bh_blocknr(buf) != btrfs_header_blocknr(&node->header)) {
37
		BUG();
38
	}
39
	return 0;
40 41
}

42 43 44 45 46 47 48 49 50 51
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 已提交
52

53 54 55 56 57 58 59 60 61 62
	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 {
63
		if (buffer_mapped(bh) && bh_blocknr(bh) == blocknr) {
64 65 66 67 68 69 70 71
			ret = bh;
			get_bh(bh);
			goto out_unlock;
		}
		bh = bh->b_this_page;
	} while (bh != head);
out_unlock:
	unlock_page(page);
C
Chris Mason 已提交
72
	if (ret) {
C
Chris Mason 已提交
73
		touch_buffer(ret);
C
Chris Mason 已提交
74
	}
75 76 77 78
	page_cache_release(page);
	return ret;
}

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
static int map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh,
			     u64 logical)
{
	struct dev_lookup *lookup[2];
	char b[BDEVNAME_SIZE];

	int ret;

	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;
printk("logical mapping %Lu to %lu bdev  %s\n", logical, bh->b_blocknr, bdevname(bh->b_bdev, b));
	set_buffer_mapped(bh);
	ret = 0;
out:
	return ret;
}

106 107 108 109 110 111 112 113 114 115
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;
116
	int err;
117
	u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits);
C
Chris Mason 已提交
118

119 120 121 122 123 124 125 126 127 128
	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)) {
129 130
			err = map_bh_to_logical(root, bh, first_block);
			BUG_ON(err);
131
		}
132
		if (bh_blocknr(bh) == blocknr) {
133 134 135 136 137 138 139 140 141
			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 已提交
142 143
	if (ret)
		touch_buffer(ret);
144 145 146 147 148 149 150
	page_cache_release(page);
	return ret;
}

static int btree_get_block(struct inode *inode, sector_t iblock,
			   struct buffer_head *bh, int create)
{
151 152 153 154
	int err;
	struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root;
	err = map_bh_to_logical(root, bh, iblock);
	return err;
155 156
}

C
Chris Mason 已提交
157 158
int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len,
		    char *result)
C
Chris Mason 已提交
159 160 161 162 163 164 165 166
{
	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 已提交
167
	sg_init_one(&sg, data, len);
C
Chris Mason 已提交
168
	spin_lock(&root->fs_info->hash_lock);
C
Chris Mason 已提交
169
	ret = crypto_hash_digest(&desc, &sg, 1, result);
C
Chris Mason 已提交
170 171 172 173
	spin_unlock(&root->fs_info->hash_lock);
	if (ret) {
		printk("sha256 digest failed\n");
	}
C
Chris Mason 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186
	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 已提交
187
	if (verify) {
C
Chris Mason 已提交
188
		if (memcmp(bh->b_data, result, BTRFS_CSUM_SIZE)) {
189 190
			printk("checksum verify failed on %Lu\n",
			       bh_blocknr(bh));
C
Chris Mason 已提交
191 192 193 194
			return 1;
		}
	} else {
		node = btrfs_buffer_node(bh);
C
Chris Mason 已提交
195
		memcpy(node->header.csum, result, BTRFS_CSUM_SIZE);
C
Chris Mason 已提交
196
	}
C
Chris Mason 已提交
197 198 199
	return 0;
}

200
static int btree_writepage(struct page *page, struct writeback_control *wbc)
201
{
C
Chris Mason 已提交
202
	struct buffer_head *bh;
203
	struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
C
Chris Mason 已提交
204 205 206 207 208 209 210 211 212 213 214 215
	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);
216
	return block_write_full_page(page, btree_get_block, wbc);
217 218
}

219
static int btree_readpage(struct file * file, struct page * page)
220
{
221
	return block_read_full_page(page, btree_get_block);
222 223
}

224 225 226 227 228 229
static struct address_space_operations btree_aops = {
	.readpage	= btree_readpage,
	.writepage	= btree_writepage,
	.sync_page	= block_sync_page,
};

C
Chris Mason 已提交
230
struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
231
{
232
	struct buffer_head *bh = NULL;
233

234 235 236
	bh = btrfs_find_create_tree_block(root, blocknr);
	if (!bh)
		return bh;
237 238
	if (buffer_uptodate(bh))
		goto uptodate;
239 240 241 242 243 244 245 246
	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;
C
Chris Mason 已提交
247
		csum_tree_block(root, bh, 1);
248 249 250
	} else {
		unlock_buffer(bh);
	}
251
uptodate:
252
	if (check_tree_block(root, bh))
C
Chris Mason 已提交
253
		BUG();
254 255 256 257
	return bh;
fail:
	brelse(bh);
	return NULL;
258 259
}

260
int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
C
Chris Mason 已提交
261
		     struct buffer_head *buf)
262
{
C
Chris Mason 已提交
263
	WARN_ON(atomic_read(&buf->b_count) == 0);
C
Chris Mason 已提交
264
	mark_buffer_dirty(buf);
265 266 267
	return 0;
}

268
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
C
Chris Mason 已提交
269
		     struct buffer_head *buf)
270
{
C
Chris Mason 已提交
271
	WARN_ON(atomic_read(&buf->b_count) == 0);
C
Chris Mason 已提交
272
	clear_buffer_dirty(buf);
273 274 275
	return 0;
}

C
Chris Mason 已提交
276
static int __setup_root(int blocksize,
277 278
			struct btrfs_root *root,
			struct btrfs_fs_info *fs_info,
C
Chris Mason 已提交
279
			u64 objectid)
280
{
C
Chris Mason 已提交
281
	root->node = NULL;
282
	root->inode = NULL;
283
	root->commit_root = NULL;
C
Chris Mason 已提交
284
	root->blocksize = blocksize;
C
Chris Mason 已提交
285
	root->ref_cows = 0;
286
	root->fs_info = fs_info;
287 288
	root->objectid = objectid;
	root->last_trans = 0;
C
Chris Mason 已提交
289 290
	root->highest_inode = 0;
	root->last_inode_alloc = 0;
291 292 293 294 295
	memset(&root->root_key, 0, sizeof(root->root_key));
	memset(&root->root_item, 0, sizeof(root->root_item));
	return 0;
}

C
Chris Mason 已提交
296
static int find_and_setup_root(int blocksize,
297 298 299
			       struct btrfs_root *tree_root,
			       struct btrfs_fs_info *fs_info,
			       u64 objectid,
C
Chris Mason 已提交
300
			       struct btrfs_root *root)
301 302 303
{
	int ret;

C
Chris Mason 已提交
304
	__setup_root(blocksize, root, fs_info, objectid);
305 306 307 308 309 310 311
	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);
312 313 314
	return 0;
}

315 316 317 318 319 320 321
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 已提交
322
	u64 highest_inode;
323 324 325
	int ret = 0;

printk("read_fs_root looking for %Lu %Lu %u\n", location->objectid, location->offset, location->flags);
C
Chris Mason 已提交
326 327 328 329 330 331
	root = radix_tree_lookup(&fs_info->fs_roots_radix,
				 (unsigned long)location->objectid);
	if (root) {
printk("found %p in cache\n", root);
		return root;
	}
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
	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 已提交
380 381
	ret = radix_tree_insert(&fs_info->fs_roots_radix,
				(unsigned long)root->root_key.objectid,
382 383 384 385 386 387 388
				root);
	if (ret) {
printk("radix_tree_insert gives us %d\n", ret);
		brelse(root->node);
		kfree(root);
		return ERR_PTR(ret);
	}
C
Chris Mason 已提交
389 390 391 392 393 394
	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);
	}
395 396 397 398
printk("all worked\n");
	return root;
}

C
Chris Mason 已提交
399
struct btrfs_root *open_ctree(struct super_block *sb)
400
{
C
Chris Mason 已提交
401 402
	struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root),
						 GFP_NOFS);
403 404
	struct btrfs_root *dev_root = kmalloc(sizeof(struct btrfs_root),
						 GFP_NOFS);
C
Chris Mason 已提交
405 406 407 408
	struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root),
					       GFP_NOFS);
	struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info),
						GFP_NOFS);
409
	int ret;
C
Chris Mason 已提交
410
	struct btrfs_super_block *disk_super;
411
	struct dev_lookup *dev_lookup;
412

C
Chris Mason 已提交
413 414
	init_bit_radix(&fs_info->pinned_radix);
	init_bit_radix(&fs_info->pending_del_radix);
415
	INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS);
416
	INIT_RADIX_TREE(&fs_info->dev_radix, GFP_NOFS);
C
Chris Mason 已提交
417
	sb_set_blocksize(sb, 4096);
418 419 420
	fs_info->running_transaction = NULL;
	fs_info->tree_root = tree_root;
	fs_info->extent_root = extent_root;
421
	fs_info->dev_root = dev_root;
C
Chris Mason 已提交
422
	fs_info->sb = sb;
423 424
	fs_info->btree_inode = new_inode(sb);
	fs_info->btree_inode->i_ino = 1;
C
Chris Mason 已提交
425
	fs_info->btree_inode->i_nlink = 1;
426 427
	fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size;
	fs_info->btree_inode->i_mapping->a_ops = &btree_aops;
428 429 430
	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 已提交
431
	insert_inode_hash(fs_info->btree_inode);
432
	mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
C
Chris Mason 已提交
433
	fs_info->hash_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
C
Chris Mason 已提交
434 435
	spin_lock_init(&fs_info->hash_lock);
	if (!fs_info->hash_tfm || IS_ERR(fs_info->hash_tfm)) {
C
Chris Mason 已提交
436 437 438
		printk("failed to allocate sha256 hash\n");
		return NULL;
	}
C
Chris Mason 已提交
439
	mutex_init(&fs_info->trans_mutex);
C
Chris Mason 已提交
440
	mutex_init(&fs_info->fs_mutex);
441 442
	memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert));
	memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert));
443

444 445 446
	__setup_root(sb->s_blocksize, dev_root,
		     fs_info, BTRFS_DEV_TREE_OBJECTID);

C
Chris Mason 已提交
447 448
	__setup_root(sb->s_blocksize, tree_root,
		     fs_info, BTRFS_ROOT_TREE_OBJECTID);
449 450 451 452 453 454 455

	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;
	ret = radix_tree_insert(&fs_info->dev_radix, (u32)-2, dev_lookup);
	BUG_ON(ret);
C
Chris Mason 已提交
456 457 458
	fs_info->sb_buffer = read_tree_block(tree_root,
					     BTRFS_SUPER_INFO_OFFSET /
					     sb->s_blocksize);
459

460
	if (!fs_info->sb_buffer)
461 462
		return NULL;
	disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data;
463
	if (!btrfs_super_root(disk_super))
C
Chris Mason 已提交
464
		return NULL;
465

466 467 468 469 470 471 472 473
	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);
	ret = radix_tree_insert(&fs_info->dev_radix,
				dev_lookup->block_start +
				dev_lookup->num_blocks, dev_lookup);
	BUG_ON(ret);

474
	fs_info->disk_super = disk_super;
475 476
	dev_root->node = read_tree_block(tree_root,
					  btrfs_super_device_root(disk_super));
C
Chris Mason 已提交
477 478
	tree_root->node = read_tree_block(tree_root,
					  btrfs_super_root(disk_super));
479 480
	BUG_ON(!tree_root->node);

C
Chris Mason 已提交
481 482
	mutex_lock(&fs_info->fs_mutex);
	ret = find_and_setup_root(sb->s_blocksize, tree_root, fs_info,
C
Chris Mason 已提交
483
				  BTRFS_EXTENT_TREE_OBJECTID, extent_root);
484 485
	BUG_ON(ret);

486
	fs_info->generation = btrfs_super_generation(disk_super) + 1;
487 488 489 490
	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 已提交
491
	mutex_unlock(&fs_info->fs_mutex);
492
	return tree_root;
493 494
}

495
int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
C
Chris Mason 已提交
496
		      *root)
497
{
498
	struct buffer_head *bh = root->fs_info->sb_buffer;
C
Chris Mason 已提交
499

500
	btrfs_set_super_root(root->fs_info->disk_super,
501
			     bh_blocknr(root->fs_info->tree_root->node));
502
	lock_buffer(bh);
C
Chris Mason 已提交
503
	WARN_ON(atomic_read(&bh->b_count) < 1);
504
	clear_buffer_dirty(bh);
C
Chris Mason 已提交
505
	csum_tree_block(root, bh, 0);
506 507 508 509 510 511 512
	bh->b_end_io = end_buffer_write_sync;
	get_bh(bh);
	submit_bh(WRITE, bh);
	wait_on_buffer(bh);
	if (!buffer_uptodate(bh)) {
		WARN_ON(1);
		return -EIO;
C
Chris Mason 已提交
513 514 515 516
	}
	return 0;
}

C
Chris Mason 已提交
517 518 519 520 521 522 523 524 525 526 527 528 529 530
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;
}

531 532 533 534 535 536 537 538 539 540 541 542
int del_fs_roots(struct btrfs_fs_info *fs_info)
{
	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 已提交
543 544
		for (i = 0; i < ret; i++)
			free_fs_root(fs_info, gang[i]);
545 546 547
	}
	return 0;
}
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
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 +
					  lookup[i]->num_blocks);
			kfree(lookup[i]);
		}
	}
	return 0;
}
571

C
Chris Mason 已提交
572
int close_ctree(struct btrfs_root *root)
C
Chris Mason 已提交
573
{
574
	int ret;
575
	struct btrfs_trans_handle *trans;
576
	struct btrfs_fs_info *fs_info = root->fs_info;
577

578
	mutex_lock(&fs_info->fs_mutex);
C
Chris Mason 已提交
579 580 581 582 583 584
	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);
585
	BUG_ON(ret);
C
Chris Mason 已提交
586
	write_ctree_super(NULL, root);
587 588 589 590 591
	mutex_unlock(&fs_info->fs_mutex);

	if (fs_info->extent_root->node)
		btrfs_block_release(fs_info->extent_root,
				    fs_info->extent_root->node);
592 593 594
	if (fs_info->dev_root->node)
		btrfs_block_release(fs_info->dev_root,
				    fs_info->dev_root->node);
595 596 597 598 599 600 601
	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);
602 603

	free_dev_radix(fs_info);
604 605 606 607
	del_fs_roots(fs_info);
	kfree(fs_info->extent_root);
	kfree(fs_info->tree_root);
	kobject_unregister(&fs_info->kobj);
608 609 610
	return 0;
}

C
Chris Mason 已提交
611
void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
612
{
C
Chris Mason 已提交
613
	brelse(buf);
614 615
}