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

Commit ccd467d6 authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse
Browse files

Btrfs: crash recovery fixes

parent f2654de4
Loading
Loading
Loading
Loading
+12 −1
Original line number Original line Diff line number Diff line
@@ -75,6 +75,17 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
	struct btrfs_node *cow_node;
	struct btrfs_node *cow_node;
	int ret;
	int ret;


	WARN_ON(!buffer_uptodate(buf));
	if (trans->transaction != root->fs_info->running_transaction) {
		printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid,
		       root->fs_info->running_transaction->transid);
		WARN_ON(1);
	}
	if (trans->transid != root->fs_info->generation) {
		printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid,
		       root->fs_info->generation);
		WARN_ON(1);
	}
	if (btrfs_header_generation(btrfs_buffer_header(buf)) ==
	if (btrfs_header_generation(btrfs_buffer_header(buf)) ==
				    trans->transid) {
				    trans->transid) {
		*cow_ret = buf;
		*cow_ret = buf;
@@ -107,7 +118,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
		btrfs_free_extent(trans, root, bh_blocknr(buf), 1, 1);
		btrfs_free_extent(trans, root, bh_blocknr(buf), 1, 1);
	}
	}
	btrfs_block_release(root, buf);
	btrfs_block_release(root, buf);
	mark_buffer_dirty(cow);
	btrfs_mark_buffer_dirty(cow);
	*cow_ret = cow;
	*cow_ret = cow;
	return 0;
	return 0;
}
}
+4 −8
Original line number Original line Diff line number Diff line
@@ -1013,18 +1013,13 @@ static inline void btrfs_memmove(struct btrfs_root *root,
	memmove(dst, src, nr);
	memmove(dst, src, nr);
}
}


static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh)
{
	WARN_ON(!atomic_read(&bh->b_count));
	mark_buffer_dirty(bh);
}

/* helper function to cast into the data area of the leaf. */
/* helper function to cast into the data area of the leaf. */
#define btrfs_item_ptr(leaf, slot, type) \
#define btrfs_item_ptr(leaf, slot, type) \
	((type *)(btrfs_leaf_data(leaf) + \
	((type *)(btrfs_leaf_data(leaf) + \
	btrfs_item_offset((leaf)->items + (slot))))
	btrfs_item_offset((leaf)->items + (slot))))


/* extent-tree.c */
/* extent-tree.c */
int btrfs_copy_pinned(struct btrfs_root *root, struct radix_tree_root *copy);
struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
							 btrfs_fs_info *info,
							 btrfs_fs_info *info,
							 u64 blocknr);
							 u64 blocknr);
@@ -1044,8 +1039,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		  struct buffer_head *buf);
		  struct buffer_head *buf);
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, u64 blocknr, u64 num_blocks, int pin);
		      *root, u64 blocknr, u64 num_blocks, int pin);
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
			       btrfs_root *root);
			       struct btrfs_root *root,
			       struct radix_tree_root *unpin_radix);
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
				struct btrfs_root *root,
				struct btrfs_root *root,
				u64 blocknr, u64 num_blocks);
				u64 blocknr, u64 num_blocks);
+14 −8
Original line number Original line Diff line number Diff line
@@ -270,14 +270,6 @@ struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
	return NULL;
	return NULL;
}
}


int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		     struct buffer_head *buf)
{
	WARN_ON(atomic_read(&buf->b_count) == 0);
	mark_buffer_dirty(buf);
	return 0;
}

int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		     struct buffer_head *buf)
		     struct buffer_head *buf)
{
{
@@ -621,6 +613,20 @@ int close_ctree(struct btrfs_root *root)
	return 0;
	return 0;
}
}


void btrfs_mark_buffer_dirty(struct buffer_head *bh)
{
	struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root;
	u64 transid = btrfs_header_generation(btrfs_buffer_header(bh));
	WARN_ON(!atomic_read(&bh->b_count));
	if (transid != root->fs_info->generation) {
		printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n",
			(unsigned long long)bh->b_blocknr,
			transid, root->fs_info->generation);
		WARN_ON(1);
	}
	mark_buffer_dirty(bh);
}

void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
{
{
	brelse(buf);
	brelse(buf);
+1 −0
Original line number Original line Diff line number Diff line
@@ -78,4 +78,5 @@ int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh,
int btrfs_releasepage(struct page *page, gfp_t flags);
int btrfs_releasepage(struct page *page, gfp_t flags);
void btrfs_btree_balance_dirty(struct btrfs_root *root);
void btrfs_btree_balance_dirty(struct btrfs_root *root);
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
void btrfs_mark_buffer_dirty(struct buffer_head *bh);
#endif
#endif
+33 −4
Original line number Original line Diff line number Diff line
@@ -523,6 +523,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
	}
	}
	return 0;
	return 0;
fail:
fail:
	WARN_ON(1);
	for (i =0; i < faili; i++) {
	for (i =0; i < faili; i++) {
		if (leaf) {
		if (leaf) {
			u64 disk_blocknr;
			u64 disk_blocknr;
@@ -572,7 +573,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
	bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
	bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
			    struct btrfs_block_group_item);
			    struct btrfs_block_group_item);
	memcpy(bi, &cache->item, sizeof(*bi));
	memcpy(bi, &cache->item, sizeof(*bi));
	mark_buffer_dirty(path->nodes[0]);
	btrfs_mark_buffer_dirty(path->nodes[0]);
	btrfs_release_path(extent_root, path);
	btrfs_release_path(extent_root, path);
fail:
fail:
	finish_current_insert(trans, extent_root);
	finish_current_insert(trans, extent_root);
@@ -739,8 +740,30 @@ static int try_remove_page(struct address_space *mapping, unsigned long index)
	return ret;
	return ret;
}
}


int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
int btrfs_copy_pinned(struct btrfs_root *root, struct radix_tree_root *copy)
			       btrfs_root *root)
{
	unsigned long gang[8];
	u64 last = 0;
	struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix;
	int ret;
	int i;

	while(1) {
		ret = find_first_radix_bit(pinned_radix, gang, last,
					   ARRAY_SIZE(gang));
		if (!ret)
			break;
		for (i = 0 ; i < ret; i++) {
			set_radix_bit(copy, gang[i]);
			last = gang[i] + 1;
		}
	}
	return 0;
}

int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
			       struct btrfs_root *root,
			       struct radix_tree_root *unpin_radix)
{
{
	unsigned long gang[8];
	unsigned long gang[8];
	struct inode *btree_inode = root->fs_info->btree_inode;
	struct inode *btree_inode = root->fs_info->btree_inode;
@@ -752,7 +775,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
	struct radix_tree_root *extent_radix = &root->fs_info->extent_map_radix;
	struct radix_tree_root *extent_radix = &root->fs_info->extent_map_radix;


	while(1) {
	while(1) {
		ret = find_first_radix_bit(pinned_radix, gang, 0,
		ret = find_first_radix_bit(unpin_radix, gang, 0,
					   ARRAY_SIZE(gang));
					   ARRAY_SIZE(gang));
		if (!ret)
		if (!ret)
			break;
			break;
@@ -760,6 +783,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
			first = gang[0];
			first = gang[0];
		for (i = 0; i < ret; i++) {
		for (i = 0; i < ret; i++) {
			clear_radix_bit(pinned_radix, gang[i]);
			clear_radix_bit(pinned_radix, gang[i]);
			clear_radix_bit(unpin_radix, gang[i]);
			block_group = btrfs_lookup_block_group(root->fs_info,
			block_group = btrfs_lookup_block_group(root->fs_info,
							       gang[i]);
							       gang[i]);
			if (block_group) {
			if (block_group) {
@@ -1309,6 +1333,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
	if (data) {
	if (data) {
		ret = find_free_extent(trans, root, 0, 0,
		ret = find_free_extent(trans, root, 0, 0,
				       search_end, 0, &prealloc_key, 0, 0, 0);
				       search_end, 0, &prealloc_key, 0, 0, 0);
		BUG_ON(ret);
		if (ret)
		if (ret)
			return ret;
			return ret;
		exclude_nr = info->extent_tree_prealloc_nr;
		exclude_nr = info->extent_tree_prealloc_nr;
@@ -1319,6 +1344,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
	ret = find_free_extent(trans, root, num_blocks, search_start,
	ret = find_free_extent(trans, root, num_blocks, search_start,
			       search_end, hint_block, ins,
			       search_end, hint_block, ins,
			       exclude_start, exclude_nr, data);
			       exclude_start, exclude_nr, data);
	BUG_ON(ret);
	if (ret)
	if (ret)
		return ret;
		return ret;


@@ -1334,10 +1360,12 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
	if (!data) {
	if (!data) {
		exclude_start = ins->objectid;
		exclude_start = ins->objectid;
		exclude_nr = ins->offset;
		exclude_nr = ins->offset;
		hint_block = exclude_start + exclude_nr;
		ret = find_free_extent(trans, root, 0, search_start,
		ret = find_free_extent(trans, root, 0, search_start,
				       search_end, hint_block,
				       search_end, hint_block,
				       &prealloc_key, exclude_start,
				       &prealloc_key, exclude_start,
				       exclude_nr, 0);
				       exclude_nr, 0);
		BUG_ON(ret);
		if (ret)
		if (ret)
			return ret;
			return ret;
	}
	}
@@ -1348,6 +1376,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
	ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
	ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
				sizeof(extent_item));
				sizeof(extent_item));


	BUG_ON(ret);
	finish_current_insert(trans, extent_root);
	finish_current_insert(trans, extent_root);
	pending_ret = del_pending_extents(trans, extent_root);
	pending_ret = del_pending_extents(trans, extent_root);
	if (ret) {
	if (ret) {
Loading