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

Commit 271fd5d7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from Chris Mason:
 "The big ones here are a memory leak we introduced in rc1, and a
  scheduling while atomic if the transid on disk doesn't match the
  transid we expected.  This happens for corrupt blocks, or out of date
  disks.

  It also fixes up the ioctl definition for our ioctl to resolve logical
  inode numbers.  The __u32 was a merging error and doesn't match what
  we ship in the progs."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: avoid sleeping in verify_parent_transid while atomic
  Btrfs: fix crash in scrub repair code when device is missing
  btrfs: Fix mismatching struct members in ioctl.h
  Btrfs: fix page leak when allocing extent buffers
  Btrfs: Add properly locking around add_root_to_dirty_list
parents ce7e5d2d b9fab919
Loading
Loading
Loading
Loading
+19 −9
Original line number Original line Diff line number Diff line
@@ -220,10 +220,12 @@ struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
 */
 */
static void add_root_to_dirty_list(struct btrfs_root *root)
static void add_root_to_dirty_list(struct btrfs_root *root)
{
{
	spin_lock(&root->fs_info->trans_lock);
	if (root->track_dirty && list_empty(&root->dirty_list)) {
	if (root->track_dirty && list_empty(&root->dirty_list)) {
		list_add(&root->dirty_list,
		list_add(&root->dirty_list,
			 &root->fs_info->dirty_cowonly_roots);
			 &root->fs_info->dirty_cowonly_roots);
	}
	}
	spin_unlock(&root->fs_info->trans_lock);
}
}


/*
/*
@@ -723,7 +725,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,


		cur = btrfs_find_tree_block(root, blocknr, blocksize);
		cur = btrfs_find_tree_block(root, blocknr, blocksize);
		if (cur)
		if (cur)
			uptodate = btrfs_buffer_uptodate(cur, gen);
			uptodate = btrfs_buffer_uptodate(cur, gen, 0);
		else
		else
			uptodate = 0;
			uptodate = 0;
		if (!cur || !uptodate) {
		if (!cur || !uptodate) {
@@ -1358,7 +1360,12 @@ static noinline int reada_for_balance(struct btrfs_root *root,
		block1 = btrfs_node_blockptr(parent, slot - 1);
		block1 = btrfs_node_blockptr(parent, slot - 1);
		gen = btrfs_node_ptr_generation(parent, slot - 1);
		gen = btrfs_node_ptr_generation(parent, slot - 1);
		eb = btrfs_find_tree_block(root, block1, blocksize);
		eb = btrfs_find_tree_block(root, block1, blocksize);
		if (eb && btrfs_buffer_uptodate(eb, gen))
		/*
		 * if we get -eagain from btrfs_buffer_uptodate, we
		 * don't want to return eagain here.  That will loop
		 * forever
		 */
		if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
			block1 = 0;
			block1 = 0;
		free_extent_buffer(eb);
		free_extent_buffer(eb);
	}
	}
@@ -1366,7 +1373,7 @@ static noinline int reada_for_balance(struct btrfs_root *root,
		block2 = btrfs_node_blockptr(parent, slot + 1);
		block2 = btrfs_node_blockptr(parent, slot + 1);
		gen = btrfs_node_ptr_generation(parent, slot + 1);
		gen = btrfs_node_ptr_generation(parent, slot + 1);
		eb = btrfs_find_tree_block(root, block2, blocksize);
		eb = btrfs_find_tree_block(root, block2, blocksize);
		if (eb && btrfs_buffer_uptodate(eb, gen))
		if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
			block2 = 0;
			block2 = 0;
		free_extent_buffer(eb);
		free_extent_buffer(eb);
	}
	}
@@ -1504,8 +1511,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,


	tmp = btrfs_find_tree_block(root, blocknr, blocksize);
	tmp = btrfs_find_tree_block(root, blocknr, blocksize);
	if (tmp) {
	if (tmp) {
		if (btrfs_buffer_uptodate(tmp, 0)) {
		/* first we do an atomic uptodate check */
			if (btrfs_buffer_uptodate(tmp, gen)) {
		if (btrfs_buffer_uptodate(tmp, 0, 1) > 0) {
			if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
				/*
				/*
				 * we found an up to date block without
				 * we found an up to date block without
				 * sleeping, return
				 * sleeping, return
@@ -1523,8 +1531,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,
			free_extent_buffer(tmp);
			free_extent_buffer(tmp);
			btrfs_set_path_blocking(p);
			btrfs_set_path_blocking(p);


			/* now we're allowed to do a blocking uptodate check */
			tmp = read_tree_block(root, blocknr, blocksize, gen);
			tmp = read_tree_block(root, blocknr, blocksize, gen);
			if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
			if (tmp && btrfs_buffer_uptodate(tmp, gen, 0) > 0) {
				*eb_ret = tmp;
				*eb_ret = tmp;
				return 0;
				return 0;
			}
			}
@@ -1559,7 +1568,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
		 * and give up so that our caller doesn't loop forever
		 * and give up so that our caller doesn't loop forever
		 * on our EAGAINs.
		 * on our EAGAINs.
		 */
		 */
		if (!btrfs_buffer_uptodate(tmp, 0))
		if (!btrfs_buffer_uptodate(tmp, 0, 0))
			ret = -EIO;
			ret = -EIO;
		free_extent_buffer(tmp);
		free_extent_buffer(tmp);
	}
	}
@@ -4043,7 +4052,7 @@ again:
			tmp = btrfs_find_tree_block(root, blockptr,
			tmp = btrfs_find_tree_block(root, blockptr,
					    btrfs_level_size(root, level - 1));
					    btrfs_level_size(root, level - 1));


			if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
			if (tmp && btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
				free_extent_buffer(tmp);
				free_extent_buffer(tmp);
				break;
				break;
			}
			}
@@ -4166,7 +4175,8 @@ next:
				struct extent_buffer *cur;
				struct extent_buffer *cur;
				cur = btrfs_find_tree_block(root, blockptr,
				cur = btrfs_find_tree_block(root, blockptr,
					    btrfs_level_size(root, level - 1));
					    btrfs_level_size(root, level - 1));
				if (!cur || !btrfs_buffer_uptodate(cur, gen)) {
				if (!cur ||
				    btrfs_buffer_uptodate(cur, gen, 1) <= 0) {
					slot++;
					slot++;
					if (cur)
					if (cur)
						free_extent_buffer(cur);
						free_extent_buffer(cur);
+13 −5
Original line number Original line Diff line number Diff line
@@ -323,7 +323,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
 * in the wrong place.
 * in the wrong place.
 */
 */
static int verify_parent_transid(struct extent_io_tree *io_tree,
static int verify_parent_transid(struct extent_io_tree *io_tree,
				 struct extent_buffer *eb, u64 parent_transid)
				 struct extent_buffer *eb, u64 parent_transid,
				 int atomic)
{
{
	struct extent_state *cached_state = NULL;
	struct extent_state *cached_state = NULL;
	int ret;
	int ret;
@@ -331,6 +332,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
	if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
	if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
		return 0;
		return 0;


	if (atomic)
		return -EAGAIN;

	lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
	lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
			 0, &cached_state);
			 0, &cached_state);
	if (extent_buffer_uptodate(eb) &&
	if (extent_buffer_uptodate(eb) &&
@@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
		ret = read_extent_buffer_pages(io_tree, eb, start,
		ret = read_extent_buffer_pages(io_tree, eb, start,
					       WAIT_COMPLETE,
					       WAIT_COMPLETE,
					       btree_get_extent, mirror_num);
					       btree_get_extent, mirror_num);
		if (!ret && !verify_parent_transid(io_tree, eb, parent_transid))
		if (!ret && !verify_parent_transid(io_tree, eb,
						   parent_transid, 0))
			break;
			break;


		/*
		/*
@@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
	root->commit_root = NULL;
	root->commit_root = NULL;
	root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
	root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
				     blocksize, generation);
				     blocksize, generation);
	if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) {
	if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) {
		free_extent_buffer(root->node);
		free_extent_buffer(root->node);
		root->node = NULL;
		root->node = NULL;
		return -EIO;
		return -EIO;
@@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root)
	return 0;
	return 0;
}
}


int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
			  int atomic)
{
{
	int ret;
	int ret;
	struct inode *btree_inode = buf->pages[0]->mapping->host;
	struct inode *btree_inode = buf->pages[0]->mapping->host;
@@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
		return ret;
		return ret;


	ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf,
	ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf,
				    parent_transid);
				    parent_transid, atomic);
	if (ret == -EAGAIN)
		return ret;
	return !ret;
	return !ret;
}
}


+2 −1
Original line number Original line Diff line number Diff line
@@ -66,7 +66,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
			  int atomic);
int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len);
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len);
+1 −1
Original line number Original line Diff line number Diff line
@@ -6568,7 +6568,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
			goto skip;
			goto skip;
	}
	}


	if (!btrfs_buffer_uptodate(next, generation)) {
	if (!btrfs_buffer_uptodate(next, generation, 0)) {
		btrfs_tree_unlock(next);
		btrfs_tree_unlock(next);
		free_extent_buffer(next);
		free_extent_buffer(next);
		next = NULL;
		next = NULL;
+2 −2
Original line number Original line Diff line number Diff line
@@ -4120,6 +4120,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
			if (atomic_inc_not_zero(&exists->refs)) {
			if (atomic_inc_not_zero(&exists->refs)) {
				spin_unlock(&mapping->private_lock);
				spin_unlock(&mapping->private_lock);
				unlock_page(p);
				unlock_page(p);
				page_cache_release(p);
				mark_extent_buffer_accessed(exists);
				mark_extent_buffer_accessed(exists);
				goto free_eb;
				goto free_eb;
			}
			}
@@ -4199,8 +4200,7 @@ free_eb:
			unlock_page(eb->pages[i]);
			unlock_page(eb->pages[i]);
	}
	}


	if (!atomic_dec_and_test(&eb->refs))
	WARN_ON(!atomic_dec_and_test(&eb->refs));
		return exists;
	btrfs_release_extent_buffer(eb);
	btrfs_release_extent_buffer(eb);
	return exists;
	return exists;
}
}
Loading