|
@@ -1305,6 +1305,7 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
|
|
|
struct extent_buffer *eb;
|
|
|
struct btrfs_root_item *root_item;
|
|
|
struct btrfs_key root_key;
|
|
|
+ u64 last_snap = 0;
|
|
|
int ret;
|
|
|
|
|
|
root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
|
|
@@ -1320,6 +1321,7 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
|
|
|
BTRFS_TREE_RELOC_OBJECTID);
|
|
|
BUG_ON(ret);
|
|
|
|
|
|
+ last_snap = btrfs_root_last_snapshot(&root->root_item);
|
|
|
btrfs_set_root_last_snapshot(&root->root_item,
|
|
|
trans->transid - 1);
|
|
|
} else {
|
|
@@ -1345,6 +1347,12 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
|
|
|
memset(&root_item->drop_progress, 0,
|
|
|
sizeof(struct btrfs_disk_key));
|
|
|
root_item->drop_level = 0;
|
|
|
+ /*
|
|
|
+ * abuse rtransid, it is safe because it is impossible to
|
|
|
+ * receive data into a relocation tree.
|
|
|
+ */
|
|
|
+ btrfs_set_root_rtransid(root_item, last_snap);
|
|
|
+ btrfs_set_root_otransid(root_item, trans->transid);
|
|
|
}
|
|
|
|
|
|
btrfs_tree_unlock(eb);
|
|
@@ -2272,8 +2280,12 @@ void free_reloc_roots(struct list_head *list)
|
|
|
static noinline_for_stack
|
|
|
int merge_reloc_roots(struct reloc_control *rc)
|
|
|
{
|
|
|
+ struct btrfs_trans_handle *trans;
|
|
|
struct btrfs_root *root;
|
|
|
struct btrfs_root *reloc_root;
|
|
|
+ u64 last_snap;
|
|
|
+ u64 otransid;
|
|
|
+ u64 objectid;
|
|
|
LIST_HEAD(reloc_roots);
|
|
|
int found = 0;
|
|
|
int ret = 0;
|
|
@@ -2307,12 +2319,44 @@ again:
|
|
|
} else {
|
|
|
list_del_init(&reloc_root->root_list);
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * we keep the old last snapshod transid in rtranid when we
|
|
|
+ * created the relocation tree.
|
|
|
+ */
|
|
|
+ last_snap = btrfs_root_rtransid(&reloc_root->root_item);
|
|
|
+ otransid = btrfs_root_otransid(&reloc_root->root_item);
|
|
|
+ objectid = reloc_root->root_key.offset;
|
|
|
+
|
|
|
ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1);
|
|
|
if (ret < 0) {
|
|
|
if (list_empty(&reloc_root->root_list))
|
|
|
list_add_tail(&reloc_root->root_list,
|
|
|
&reloc_roots);
|
|
|
goto out;
|
|
|
+ } else if (!ret) {
|
|
|
+ /*
|
|
|
+ * recover the last snapshot tranid to avoid
|
|
|
+ * the space balance break NOCOW.
|
|
|
+ */
|
|
|
+ root = read_fs_root(rc->extent_root->fs_info,
|
|
|
+ objectid);
|
|
|
+ if (IS_ERR(root))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (btrfs_root_refs(&root->root_item) == 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ trans = btrfs_join_transaction(root);
|
|
|
+ BUG_ON(IS_ERR(trans));
|
|
|
+
|
|
|
+ /* Check if the fs/file tree was snapshoted or not. */
|
|
|
+ if (btrfs_root_last_snapshot(&root->root_item) ==
|
|
|
+ otransid - 1)
|
|
|
+ btrfs_set_root_last_snapshot(&root->root_item,
|
|
|
+ last_snap);
|
|
|
+
|
|
|
+ btrfs_end_transaction(trans, root);
|
|
|
}
|
|
|
}
|
|
|
|