Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f39d397 authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Create extent_buffer interface for large blocksizes

parent 50b78c24
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -23,4 +23,6 @@ modules_install:
clean:
	$(MAKE) -C $(KERNELDIR) M=`pwd` clean

tester:
	$(MAKE) -C $(KERNELDIR) M=`pwd` tree-defrag.o transaction.o sysfs.o super.o root-tree.o inode-map.o inode-item.o inode.o file-item.o file.o extent_map.o disk-io.o ctree.o dir-item.o extent-tree.o
endif
+817 −667

File changed.

Preview size limit exceeded, changes collapsed.

+315 −534

File changed.

Preview size limit exceeded, changes collapsed.

+56 −46
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
	int ret;
	char *ptr;
	struct btrfs_item *item;
	struct btrfs_leaf *leaf;
	struct extent_buffer *leaf;

	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
	if (ret == -EEXIST) {
@@ -49,11 +49,11 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
	if (ret < 0)
		return ERR_PTR(ret);
	WARN_ON(ret > 0);
	leaf = btrfs_buffer_leaf(path->nodes[0]);
	item = leaf->items + path->slots[0];
	leaf = path->nodes[0];
	item = btrfs_item_nr(leaf, path->slots[0]);
	ptr = btrfs_item_ptr(leaf, path->slots[0], char);
	BUG_ON(data_size > btrfs_item_size(item));
	ptr += btrfs_item_size(item) - data_size;
	BUG_ON(data_size > btrfs_item_size(leaf, item));
	ptr += btrfs_item_size(leaf, item) - data_size;
	return (struct btrfs_dir_item *)ptr;
}

@@ -65,12 +65,13 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
	int ret2 = 0;
	struct btrfs_path *path;
	struct btrfs_dir_item *dir_item;
	char *name_ptr;
	struct extent_buffer *leaf;
	unsigned long name_ptr;
	struct btrfs_key key;
	struct btrfs_disk_key disk_key;
	u32 data_size;

	key.objectid = dir;
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
	ret = btrfs_name_hash(name, name_len, &key.offset);
	BUG_ON(ret);
@@ -85,14 +86,16 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
		goto out;
	}

	btrfs_cpu_key_to_disk(&dir_item->location, location);
	btrfs_set_dir_type(dir_item, type);
	btrfs_set_dir_flags(dir_item, 0);
	btrfs_set_dir_name_len(dir_item, name_len);
	name_ptr = (char *)(dir_item + 1);
	leaf = path->nodes[0];
	btrfs_cpu_key_to_disk(&disk_key, location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, type);
	btrfs_set_dir_flags(leaf, dir_item, 0);
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	name_ptr = (unsigned long)(dir_item + 1);

	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);
	write_extent_buffer(leaf, name, name_ptr, name_len);
	btrfs_mark_buffer_dirty(leaf);

second_insert:
	/* FIXME, use some real flag for selecting the extra index */
@@ -110,13 +113,15 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
		ret2 = PTR_ERR(dir_item);
		goto out;
	}
	btrfs_cpu_key_to_disk(&dir_item->location, location);
	btrfs_set_dir_type(dir_item, type);
	btrfs_set_dir_flags(dir_item, 0);
	btrfs_set_dir_name_len(dir_item, name_len);
	name_ptr = (char *)(dir_item + 1);
	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);
	leaf = path->nodes[0];
	btrfs_cpu_key_to_disk(&disk_key, location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, type);
	btrfs_set_dir_flags(leaf, dir_item, 0);
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	name_ptr = (unsigned long)(dir_item + 1);
	write_extent_buffer(leaf, name, name_ptr, name_len);
	btrfs_mark_buffer_dirty(leaf);
out:
	btrfs_free_path(path);
	if (ret)
@@ -136,14 +141,15 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
	struct btrfs_key key;
	int ins_len = mod < 0 ? -1 : 0;
	int cow = mod != 0;
	struct btrfs_disk_key *found_key;
	struct btrfs_leaf *leaf;
	struct btrfs_key found_key;
	struct extent_buffer *leaf;

	key.objectid = dir;
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);

	ret = btrfs_name_hash(name, name_len, &key.offset);
	BUG_ON(ret);

	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
	if (ret < 0)
		return ERR_PTR(ret);
@@ -152,12 +158,13 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
			return NULL;
		path->slots[0]--;
	}
	leaf = btrfs_buffer_leaf(path->nodes[0]);
	found_key = &leaf->items[path->slots[0]].key;

	if (btrfs_disk_key_objectid(found_key) != dir ||
	    btrfs_disk_key_type(found_key) != BTRFS_DIR_ITEM_KEY ||
	    btrfs_disk_key_offset(found_key) != key.offset)
	leaf = path->nodes[0];
	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);

	if (found_key.objectid != dir ||
	    btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
	    found_key.offset != key.offset)
		return NULL;

	return btrfs_match_dir_item_name(root, path, name, name_len);
@@ -176,7 +183,6 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
	int cow = mod != 0;

	key.objectid = dir;
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
	key.offset = objectid;

@@ -193,21 +199,22 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
			      const char *name, int name_len)
{
	struct btrfs_dir_item *dir_item;
	char *name_ptr;
	unsigned long name_ptr;
	u32 total_len;
	u32 cur = 0;
	u32 this_len;
	struct btrfs_leaf *leaf;
	struct extent_buffer *leaf;

	leaf = btrfs_buffer_leaf(path->nodes[0]);
	leaf = path->nodes[0];
	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
	total_len = btrfs_item_size(leaf->items + path->slots[0]);
	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
	while(cur < total_len) {
		this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item);
		name_ptr = (char *)(dir_item + 1);
		this_len = sizeof(*dir_item) +
			btrfs_dir_name_len(leaf, dir_item);
		name_ptr = (unsigned long)(dir_item + 1);

		if (btrfs_dir_name_len(dir_item) == name_len &&
		    memcmp(name_ptr, name, name_len) == 0)
		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
			return dir_item;

		cur += this_len;
@@ -223,20 +230,23 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
			      struct btrfs_dir_item *di)
{

	struct btrfs_leaf *leaf;
	struct extent_buffer *leaf;
	u32 sub_item_len;
	u32 item_len;
	int ret = 0;

	leaf = btrfs_buffer_leaf(path->nodes[0]);
	sub_item_len = sizeof(*di) + btrfs_dir_name_len(di);
	item_len = btrfs_item_size(leaf->items + path->slots[0]);
	if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) {
	leaf = path->nodes[0];
	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di);
	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
	if (sub_item_len == item_len) {
		ret = btrfs_del_item(trans, root, path);
	} else {
		char *ptr = (char *)di;
		char *start = btrfs_item_ptr(leaf, path->slots[0], char);
		btrfs_memmove(root, leaf, ptr, ptr + sub_item_len,
		/* MARKER */
		unsigned long ptr = (unsigned long)di;
		unsigned long start;

		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
			item_len - (ptr + sub_item_len - start));
		ret = btrfs_truncate_item(trans, root, path,
					  item_len - sub_item_len);
+180 −211
Original line number Diff line number Diff line
@@ -23,138 +23,132 @@
#include <linux/swap.h>
#include <linux/radix-tree.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h> // for block_sync_page
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
#include "btrfs_inode.h"

u64 bh_blocknr(struct buffer_head *bh)
#if 0
static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
{
	return bh->b_blocknr;
}

static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf)
{
	struct btrfs_node *node = btrfs_buffer_node(buf);
	if (bh_blocknr(buf) != btrfs_header_blocknr(&node->header)) {
		printk(KERN_CRIT "bh_blocknr(buf) is %llu, header is %llu\n",
		       (unsigned long long)bh_blocknr(buf),
		       (unsigned long long)btrfs_header_blocknr(&node->header));
	if (extent_buffer_blocknr(buf) != btrfs_header_blocknr(buf)) {
		printk(KERN_CRIT "buf blocknr(buf) is %llu, header is %llu\n",
		       (unsigned long long)extent_buffer_blocknr(buf),
		       (unsigned long long)btrfs_header_blocknr(buf));
		return 1;
	}
	return 0;
}
#endif

struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr)
struct extent_buffer *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;

	struct inode *btree_inode = root->fs_info->btree_inode;
	return find_extent_buffer(&BTRFS_I(btree_inode)->extent_tree,
				   blocknr * root->sectorsize,
				   root->sectorsize, GFP_NOFS);
}

	page = find_lock_page(mapping, index);
	if (!page)
		return NULL;
struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
						 u64 blocknr)
{
	struct inode *btree_inode = root->fs_info->btree_inode;
	return alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree,
				   blocknr * root->sectorsize,
				   root->sectorsize, GFP_NOFS);
}

	if (!page_has_buffers(page))
		goto out_unlock;
struct extent_map *btree_get_extent(struct inode *inode, struct page *page,
				    size_t page_offset, u64 start, u64 end,
				    int create)
{
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
	struct extent_map *em;
	int ret;

	head = page_buffers(page);
	bh = head;
	do {
		if (buffer_mapped(bh) && bh_blocknr(bh) == blocknr) {
			ret = bh;
			get_bh(bh);
			goto out_unlock;
again:
	em = lookup_extent_mapping(em_tree, start, end);
	if (em) {
		goto out;
	}
		bh = bh->b_this_page;
	} while (bh != head);
out_unlock:
	unlock_page(page);
	page_cache_release(page);
	return ret;
	em = alloc_extent_map(GFP_NOFS);
	if (!em) {
		em = ERR_PTR(-ENOMEM);
		goto out;
	}
	em->start = 0;
	em->end = (i_size_read(inode) & ~((u64)PAGE_CACHE_SIZE -1)) - 1;
	em->block_start = 0;
	em->block_end = em->end;
	em->bdev = inode->i_sb->s_bdev;
	ret = add_extent_mapping(em_tree, em);
	if (ret == -EEXIST) {
		free_extent_map(em);
		em = NULL;
		goto again;
	} else if (ret) {
		em = ERR_PTR(ret);
	}
out:
	return em;
}

int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh,
			     u64 logical)
static int btree_writepage(struct page *page, struct writeback_control *wbc)
{
	if (logical == 0) {
		bh->b_bdev = NULL;
		bh->b_blocknr = 0;
		set_buffer_mapped(bh);
	} else {
		map_bh(bh, root->fs_info->sb, logical);
	struct extent_map_tree *tree;
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
	return extent_write_full_page(tree, page, btree_get_extent, wbc);
}
	return 0;
int btree_readpage(struct file *file, struct page *page)
{
	struct extent_map_tree *tree;
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
	return extent_read_full_page(tree, page, btree_get_extent);
}

struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root,
						 u64 blocknr)
static int btree_releasepage(struct page *page, gfp_t unused_gfp_flags)
{
	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;
	int err;
	u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits);

	page = find_or_create_page(mapping, index, GFP_NOFS);
	if (!page)
		return NULL;
	struct extent_map_tree *tree;
	int ret;

	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)) {
			err = btrfs_map_bh_to_logical(root, bh, first_block);
			BUG_ON(err);
		}
		if (bh_blocknr(bh) == blocknr) {
			ret = bh;
			get_bh(bh);
			goto out_unlock;
		}
		bh = bh->b_this_page;
		first_block++;
	} while (bh != head);
out_unlock:
	unlock_page(page);
	if (ret)
		touch_buffer(ret);
	BUG_ON(page->private != 1);
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
	ret = try_release_extent_mapping(tree, page);
	if (ret == 1) {
		ClearPagePrivate(page);
		set_page_private(page, 0);
		page_cache_release(page);
	}
	return ret;
}

static int btree_get_block(struct inode *inode, sector_t iblock,
			   struct buffer_head *bh, int create)
static void btree_invalidatepage(struct page *page, unsigned long offset)
{
	int err;
	struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root;
	err = btrfs_map_bh_to_logical(root, bh, iblock);
	return err;
	struct extent_map_tree *tree;
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
	extent_invalidatepage(tree, page, offset);
	btree_releasepage(page, GFP_NOFS);
}

int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len,
		    char *result)
{
	return 0;
#if 0
	u32 crc;
	crc = crc32c(0, data, len);
	memcpy(result, &crc, BTRFS_CRC32_SIZE);
	return 0;
#endif
}

static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh,
#if 0
static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
			   int verify)
{
	return 0;
	char result[BTRFS_CRC32_SIZE];
	int ret;
	struct btrfs_node *node;
@@ -176,7 +170,9 @@ static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh,
	}
	return 0;
}
#endif

#if 0
static int btree_writepage(struct page *page, struct writeback_control *wbc)
{
	struct buffer_head *bh;
@@ -195,87 +191,65 @@ static int btree_writepage(struct page *page, struct writeback_control *wbc)
	} while (bh != head);
	return block_write_full_page(page, btree_get_block, wbc);
}

static int btree_readpage(struct file * file, struct page * page)
{
	return block_read_full_page(page, btree_get_block);
}
#endif

static struct address_space_operations btree_aops = {
	.readpage	= btree_readpage,
	.writepage	= btree_writepage,
	.releasepage	= btree_releasepage,
	.invalidatepage = btree_invalidatepage,
	.sync_page	= block_sync_page,
};

int readahead_tree_block(struct btrfs_root *root, u64 blocknr)
{
	struct buffer_head *bh = NULL;
	struct extent_buffer *buf = NULL;
	struct inode *btree_inode = root->fs_info->btree_inode;
	int ret = 0;

	bh = btrfs_find_create_tree_block(root, blocknr);
	if (!bh)
	buf = btrfs_find_create_tree_block(root, blocknr);
	if (!buf)
		return 0;
	if (buffer_uptodate(bh)) {
		ret = 1;
		goto done;
	}
	if (test_set_buffer_locked(bh)) {
		ret = 1;
		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);
		ret = 1;
	}
done:
	brelse(bh);
	read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
				 buf, 0);
	free_extent_buffer(buf);
	return ret;
}

struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr)
{
	struct buffer_head *bh = NULL;

	bh = btrfs_find_create_tree_block(root, blocknr);
	if (!bh)
		return bh;
	if (buffer_uptodate(bh))
		goto uptodate;
	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);
	}
uptodate:
	if (!buffer_checked(bh)) {
		csum_tree_block(root, bh, 1);
		set_buffer_checked(bh);
	}
	if (check_tree_block(root, bh))
		goto fail;
	return bh;
fail:
	brelse(bh);
	struct extent_buffer *buf = NULL;
	struct inode *btree_inode = root->fs_info->btree_inode;

	buf = btrfs_find_create_tree_block(root, blocknr);
	if (!buf)
		return NULL;
	read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
				 buf, 1);
	return buf;
}

int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		     struct buffer_head *buf)
		     struct extent_buffer *buf)
{
	WARN_ON(atomic_read(&buf->b_count) == 0);
	lock_buffer(buf);
	clear_buffer_dirty(buf);
	unlock_buffer(buf);
	struct inode *btree_inode = root->fs_info->btree_inode;
	clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf);
	return 0;
}

int wait_on_tree_block_writeback(struct btrfs_root *root,
				 struct extent_buffer *buf)
{
	struct inode *btree_inode = root->fs_info->btree_inode;
	wait_on_extent_buffer_writeback(&BTRFS_I(btree_inode)->extent_tree,
					buf);
	return 0;
}

int set_tree_block_dirty(struct btrfs_root *root, struct extent_buffer *buf)
{
	struct inode *btree_inode = root->fs_info->btree_inode;
	set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf);
	return 0;
}

@@ -287,7 +261,9 @@ static int __setup_root(int blocksize,
	root->node = NULL;
	root->inode = NULL;
	root->commit_root = NULL;
	root->blocksize = blocksize;
	root->sectorsize = blocksize;
	root->nodesize = blocksize;
	root->leafsize = blocksize;
	root->ref_cows = 0;
	root->fs_info = fs_info;
	root->objectid = objectid;
@@ -332,7 +308,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
	struct btrfs_root *root;
	struct btrfs_root *tree_root = fs_info->tree_root;
	struct btrfs_path *path;
	struct btrfs_leaf *l;
	struct extent_buffer *l;
	u64 highest_inode;
	int ret = 0;

@@ -361,11 +337,10 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
			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),
	l = path->nodes[0];
	read_extent_buffer(l, &root->root_item,
	       btrfs_item_ptr_offset(l, path->slots[0]),
	       sizeof(root->root_item));
	memcpy(&root->root_key, location, sizeof(*location));
	ret = 0;
out:
	btrfs_release_path(root, path);
@@ -406,21 +381,21 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
				(unsigned long)root->root_key.objectid,
				root);
	if (ret) {
		brelse(root->node);
		free_extent_buffer(root->node);
		kfree(root);
		return ERR_PTR(ret);
	}

	ret = btrfs_set_root_name(root, name, namelen);
	if (ret) {
		brelse(root->node);
		free_extent_buffer(root->node);
		kfree(root);
		return ERR_PTR(ret);
	}

	ret = btrfs_sysfs_add_root(root);
	if (ret) {
		brelse(root->node);
		free_extent_buffer(root->node);
		kfree(root->name);
		kfree(root);
		return ERR_PTR(ret);
@@ -471,6 +446,9 @@ struct btrfs_root *open_ctree(struct super_block *sb)
	fs_info->btree_inode->i_nlink = 1;
	fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size;
	fs_info->btree_inode->i_mapping->a_ops = &btree_aops;
	extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree,
			     fs_info->btree_inode->i_mapping,
			     GFP_NOFS);
	fs_info->do_barriers = 1;
	fs_info->closing = 0;

@@ -493,10 +471,14 @@ struct btrfs_root *open_ctree(struct super_block *sb)

	if (!fs_info->sb_buffer)
		goto fail_iput;
	disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data;
	fs_info->disk_super = disk_super;
	memcpy(&fs_info->super_copy, disk_super, sizeof(fs_info->super_copy));

	read_extent_buffer(fs_info->sb_buffer, &fs_info->super_copy, 0,
			   sizeof(fs_info->super_copy));

	read_extent_buffer(fs_info->sb_buffer, fs_info->fsid,
			   (unsigned long)btrfs_super_fsid(fs_info->sb_buffer),
			   BTRFS_FSID_SIZE);
	disk_super = &fs_info->super_copy;
	if (!btrfs_super_root(disk_super))
		goto fail_sb_buffer;

@@ -530,9 +512,9 @@ struct btrfs_root *open_ctree(struct super_block *sb)
	return tree_root;

fail_tree_root:
	btrfs_block_release(tree_root, tree_root->node);
	free_extent_buffer(tree_root->node);
fail_sb_buffer:
	btrfs_block_release(tree_root, fs_info->sb_buffer);
	free_extent_buffer(fs_info->sb_buffer);
fail_iput:
	iput(fs_info->btree_inode);
fail:
@@ -546,31 +528,13 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root)
{
	int ret;
	struct buffer_head *bh = root->fs_info->sb_buffer;
	struct extent_buffer *super = root->fs_info->sb_buffer;
	struct inode *btree_inode = root->fs_info->btree_inode;

	lock_buffer(bh);
	WARN_ON(atomic_read(&bh->b_count) < 1);
	clear_buffer_dirty(bh);
	csum_tree_block(root, bh, 0);
	bh->b_end_io = end_buffer_write_sync;
	get_bh(bh);
	if (root->fs_info->do_barriers)
		ret = submit_bh(WRITE_BARRIER, bh);
	else
		ret = submit_bh(WRITE, bh);
	if (ret == -EOPNOTSUPP) {
		get_bh(bh);
		lock_buffer(bh);
		set_buffer_uptodate(bh);
		root->fs_info->do_barriers = 0;
		ret = submit_bh(WRITE, bh);
	}
	wait_on_buffer(bh);
	if (!buffer_uptodate(bh)) {
		WARN_ON(1);
		return -EIO;
	}
	return 0;
	set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, super);
	ret = sync_page_range_nolock(btree_inode, btree_inode->i_mapping,
				     super->start, super->len);
	return ret;
}

int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
@@ -581,9 +545,9 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
	if (root->inode)
		iput(root->inode);
	if (root->node)
		brelse(root->node);
		free_extent_buffer(root->node);
	if (root->commit_root)
		brelse(root->commit_root);
		free_extent_buffer(root->commit_root);
	if (root->name)
		kfree(root->name);
	kfree(root);
@@ -629,12 +593,10 @@ int close_ctree(struct btrfs_root *root)
	mutex_unlock(&fs_info->fs_mutex);

	if (fs_info->extent_root->node)
		btrfs_block_release(fs_info->extent_root,
				    fs_info->extent_root->node);
		free_extent_buffer(fs_info->extent_root->node);
	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);
		free_extent_buffer(fs_info->tree_root->node);
	free_extent_buffer(fs_info->sb_buffer);
	truncate_inode_pages(fs_info->btree_inode->i_mapping, 0);
	iput(fs_info->btree_inode);

@@ -645,25 +607,32 @@ int close_ctree(struct btrfs_root *root)
	return 0;
}

void btrfs_mark_buffer_dirty(struct buffer_head *bh)
int btrfs_buffer_uptodate(struct extent_buffer *buf)
{
	struct inode *btree_inode = buf->pages[0]->mapping->host;
	return extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, buf);
}

int btrfs_set_buffer_uptodate(struct extent_buffer *buf)
{
	struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root;
	u64 transid = btrfs_header_generation(btrfs_buffer_header(bh));
	struct inode *btree_inode = buf->pages[0]->mapping->host;
	return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree,
					  buf);
}

	WARN_ON(!atomic_read(&bh->b_count));
void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
{
	struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
	u64 transid = btrfs_header_generation(buf);
	struct inode *btree_inode = root->fs_info->btree_inode;

	if (transid != root->fs_info->generation) {
		printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n",
			(unsigned long long)bh->b_blocknr,
			(unsigned long long)extent_buffer_blocknr(buf),
			transid, root->fs_info->generation);
		WARN_ON(1);
	}
	mark_buffer_dirty(bh);
}

void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
{
	brelse(buf);
	set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf);
}

void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
Loading