Thread (16 messages) 16 messages, 2 authors, 2021-09-14
STALE1754d
Revisions (2)
  1. v1 current
  2. v2 [diff vs current]

[PATCH 6/8] btrfs-progs: check/original: Implement removing received data for RW subvols

From: Nikolay Borisov <hidden>
Date: 2021-09-13 13:30:18
Subsystem: the rest · Maintainer: Linus Torvalds

Making a received subvolume RO should preclude doing an incremental send
of said subvolume since it can't be guaranteed that nothing changed in
the structure and this in turn has correctness implications for send.

There is a pending kernel change that implements this behavior and
ensures that in the future RO volumes which are switched to RW can't be
used for incremental send. However, old kernels won't have that patch
backported. To ensure there is a supported way for users to put their
subvolumes in sane state let's implement the same functionality in
progs.

Signed-off-by: Nikolay Borisov <redacted>
---
 check/main.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/check/main.c b/check/main.c
index 6369bdd90656..7a2296d00234 100644
--- a/check/main.c
+++ b/check/main.c
@@ -3544,6 +3544,7 @@ static int check_fs_root(struct btrfs_root *root,
 	int ret = 0;
 	int err = 0;
 	bool generation_err = false;
+	bool rw_received_err = false;
 	int wret;
 	int level;
 	u64 super_generation;
@@ -3658,6 +3659,46 @@ static int check_fs_root(struct btrfs_root *root,
 					sizeof(found_key)));
 	}
 
+	if (!((btrfs_root_flags(root_item) & BTRFS_ROOT_SUBVOL_RDONLY) ||
+			btrfs_is_empty_uuid(root_item->received_uuid))) {
+		error("Subvolume id: %llu is RW and has a received uuid",
+				root->root_key.objectid);
+		rw_received_err = true;
+		if (repair) {
+			struct btrfs_trans_handle *trans = btrfs_start_transaction(root, 2);
+			if (IS_ERR(trans))
+				return PTR_ERR(trans);
+
+			ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid,
+					BTRFS_UUID_KEY_RECEIVED_SUBVOL, root->root_key.objectid);
+
+			if (ret && ret != -ENOENT) {
+				btrfs_abort_transaction(trans, ret);
+				return ret;
+			}
+
+			memset(root_item->received_uuid, 0, BTRFS_UUID_SIZE);
+			btrfs_set_root_stransid(root_item, 0);
+			btrfs_set_root_rtransid(root_item, 0);
+			btrfs_set_stack_timespec_sec(&root_item->stime, 0);
+			btrfs_set_stack_timespec_nsec(&root_item->stime, 0);
+			btrfs_set_stack_timespec_sec(&root_item->rtime, 0);
+			btrfs_set_stack_timespec_nsec(&root_item->rtime, 0);
+
+			ret = btrfs_update_root(trans, gfs_info->tree_root, &root->root_key,
+					root_item);
+			if (ret < 0) {
+				btrfs_abort_transaction(trans, ret);
+				return ret;
+			}
+
+			btrfs_commit_transaction(trans, gfs_info->tree_root);
+			rw_received_err = false;
+			printf("Cleared received information for subvol: %llu\n",
+					root->root_key.objectid);
+		}
+	}
+
 	while (1) {
 		ctx.item_count++;
 		wret = walk_down_tree(root, &path, wc, &level, &nrefs);
@@ -3722,7 +3763,7 @@ static int check_fs_root(struct btrfs_root *root,
 
 	free_corrupt_blocks_tree(&corrupt_blocks);
 	gfs_info->corrupt_blocks = NULL;
-	if (!ret && generation_err)
+	if (!ret && (generation_err ||  rw_received_err))
 		ret = -1;
 	return ret;
 }
-- 
2.17.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help