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

Commit 3fd0a558 authored by Yan, Zheng's avatar Yan, Zheng Committed by Chris Mason
Browse files

Btrfs: Metadata ENOSPC handling for balance



This patch adds metadata ENOSPC handling for the balance code.
It is consisted by following major changes:

1. Avoid COW tree leave in the phrase of merging tree.

2. Handle interaction with snapshot creation.

3. make the backref cache can live across transactions.

Signed-off-by: default avatarYan Zheng <zheng.yan@oracle.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent efa56464
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -447,6 +447,9 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,

	update_ref_for_cow(trans, root, buf, cow, &last_ref);

	if (root->ref_cows)
		btrfs_reloc_cow_block(trans, root, buf, cow);

	if (buf == root->node) {
		WARN_ON(parent && parent != buf);
		if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
+10 −1
Original line number Diff line number Diff line
@@ -2205,7 +2205,8 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref);
int btrfs_drop_snapshot(struct btrfs_root *root,
			struct btrfs_block_rsv *block_rsv, int update_ref);
int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
			struct btrfs_root *root,
			struct extent_buffer *node,
@@ -2479,4 +2480,12 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
			    struct btrfs_root *root);
int btrfs_recover_relocation(struct btrfs_root *root);
int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len);
void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
			   struct btrfs_root *root, struct extent_buffer *buf,
			   struct extent_buffer *cow);
void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
			      struct btrfs_pending_snapshot *pending,
			      u64 *bytes_to_reserve);
void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
			      struct btrfs_pending_snapshot *pending);
#endif
+9 −14
Original line number Diff line number Diff line
@@ -5875,7 +5875,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
 * also make sure backrefs for the shared block and all lower level
 * blocks are properly updated.
 */
int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
int btrfs_drop_snapshot(struct btrfs_root *root,
			struct btrfs_block_rsv *block_rsv, int update_ref)
{
	struct btrfs_path *path;
	struct btrfs_trans_handle *trans;
@@ -5894,6 +5895,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
	BUG_ON(!wc);

	trans = btrfs_start_transaction(tree_root, 0);
	if (block_rsv)
		trans->block_rsv = block_rsv;

	if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
		level = btrfs_header_level(root->node);
@@ -5981,24 +5984,16 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
		}

		BUG_ON(wc->level == 0);
		if (trans->transaction->in_commit ||
		    trans->transaction->delayed_refs.flushing) {
		if (btrfs_should_end_transaction(trans, tree_root)) {
			ret = btrfs_update_root(trans, tree_root,
						&root->root_key,
						root_item);
			BUG_ON(ret);

			btrfs_end_transaction(trans, tree_root);
			btrfs_end_transaction_throttle(trans, tree_root);
			trans = btrfs_start_transaction(tree_root, 0);
			if (IS_ERR(trans))
				return PTR_ERR(trans);
		} else {
			unsigned long update;
			update = trans->delayed_ref_updates;
			trans->delayed_ref_updates = 0;
			if (update)
				btrfs_run_delayed_refs(trans, tree_root,
						       update);
			if (block_rsv)
				trans->block_rsv = block_rsv;
		}
	}
	btrfs_release_path(root, path);
@@ -6026,7 +6021,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
		kfree(root);
	}
out:
	btrfs_end_transaction(trans, tree_root);
	btrfs_end_transaction_throttle(trans, tree_root);
	kfree(wc);
	btrfs_free_path(path);
	return err;
+1144 −737

File changed.

Preview size limit exceeded, changes collapsed.

+4 −2
Original line number Diff line number Diff line
@@ -853,6 +853,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
		goto fail;
	}

	btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
	btrfs_orphan_pre_snapshot(trans, pending, &to_reserve);

	if (to_reserve > 0) {
@@ -924,6 +925,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
	pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
	BUG_ON(IS_ERR(pending->snap));

	btrfs_reloc_post_snapshot(trans, pending);
	btrfs_orphan_post_snapshot(trans, pending);
fail:
	kfree(new_root_item);
@@ -1213,9 +1215,9 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)

		if (btrfs_header_backref_rev(root->node) <
		    BTRFS_MIXED_BACKREF_REV)
			btrfs_drop_snapshot(root, 0);
			btrfs_drop_snapshot(root, NULL, 0);
		else
			btrfs_drop_snapshot(root, 1);
			btrfs_drop_snapshot(root, NULL, 1);
	}
	return 0;
}