diff mbox series

[v2] btrfs-progs: receive: self-contained mode

Message ID f8ae1ad668a50d0b09c2f3e36e87b1ef9381f002.1720041219.git.boris@bur.io (mailing list archive)
State New, archived
Headers show
Series [v2] btrfs-progs: receive: self-contained mode | expand

Commit Message

Boris Burkov July 3, 2024, 9:15 p.m. UTC
Currently receive detects the case where it is mounted with -o subvolid
and resolves the path to the mounted subvolume from the root subvolume.
This path is then used to find the absolute paths for sources of
data/metadata for snapshots and reflinks.

Another interpretation of a sendstream is more divorced from the source
filesystem and aims to interpret it in a more self contained way, using
the filesystem as visible to the user. Think usecases in a chroot, user
namespace, mount namespace, etc. applying a generically crafted
sendstream that will apply successfully in the local context.

For such receives, the complexity of resolving this path is unhelpful.
First of all, the backref resolution using inode->subvol resolution uses
CAP_SYS_ADMIN, so it cannot be done in a user namespace. Even if you
could overcome this technically, and the receiving user had permissions
higher up the chain of dirs/subvols back to the root subvol, it's still
unhelpful if you want to do reflinks/snapshots relative to the paths in
the receiving subvolume, not the global paths.

Therefore, provide an option for such a self contained mode:
--self-contained

Signed-off-by: Boris Burkov <boris@bur.io>
---
Changelog
v2:
- actually add the SELF_CONTAINED option to the enum; re-test
  a non hacked up version for once.. Sorry!

 cmds/receive.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/cmds/receive.c b/cmds/receive.c
index 412bc8afe..d0862271c 100644
--- a/cmds/receive.c
+++ b/cmds/receive.c
@@ -82,6 +82,8 @@  struct btrfs_receive
 
 	bool force_decompress;
 
+	bool self_contained;
+
 #if COMPRESSION_ZSTD
 	/* Reuse stream objects for encoded_write decompression fallback */
 	ZSTD_DStream *zstd_dstream;
@@ -1518,11 +1520,13 @@  static int do_receive(struct btrfs_receive *rctx, const char *tomnt,
 	}
 
 	root_subvol_path[0] = 0;
-	ret = btrfs_subvolid_resolve(rctx->mnt_fd, root_subvol_path,
-				     PATH_MAX, subvol_id);
-	if (ret) {
-		error("cannot resolve our subvol path");
-		goto out;
+	if (!rctx->self_contained) {
+		ret = btrfs_subvolid_resolve(rctx->mnt_fd, root_subvol_path,
+					     PATH_MAX, subvol_id);
+		if (ret) {
+			error("cannot resolve our subvol path");
+			goto out;
+		}
 	}
 
 	/*
@@ -1645,6 +1649,9 @@  static const char * const cmd_receive_usage[] = {
 		"this file system is mounted."),
 	OPTLINE("--force-decompress", "if the stream contains compressed data, always "
 		"decompress it instead of writing it with encoded I/O"),
+	OPTLINE("--self-contained", "don't resolve snapshot and reflink sources "
+		"relative to the true FS root, only use what is visible to the fs "
+		"as mounted."),
 	OPTLINE("--dump", "dump stream metadata, one line per operation, "
 		"does not require the MOUNT parameter"),
 	OPTLINE("-v", "deprecated, alias for global -v option"),
@@ -1705,6 +1712,7 @@  static int cmd_receive(const struct cmd_struct *cmd, int argc, char **argv)
 		enum {
 			GETOPT_VAL_DUMP = GETOPT_VAL_FIRST,
 			GETOPT_VAL_FORCE_DECOMPRESS,
+			GETOPT_VAL_SELF_CONTAINED,
 		};
 		static const struct option long_opts[] = {
 			{ "max-errors", required_argument, NULL, 'E' },
@@ -1712,6 +1720,7 @@  static int cmd_receive(const struct cmd_struct *cmd, int argc, char **argv)
 			{ "dump", no_argument, NULL, GETOPT_VAL_DUMP },
 			{ "quiet", no_argument, NULL, 'q' },
 			{ "force-decompress", no_argument, NULL, GETOPT_VAL_FORCE_DECOMPRESS },
+			{ "self-contained", no_argument, NULL, GETOPT_VAL_SELF_CONTAINED },
 			{ NULL, 0, NULL, 0 }
 		};
 
@@ -1757,6 +1766,9 @@  static int cmd_receive(const struct cmd_struct *cmd, int argc, char **argv)
 		case GETOPT_VAL_FORCE_DECOMPRESS:
 			rctx.force_decompress = true;
 			break;
+		case GETOPT_VAL_SELF_CONTAINED:
+			rctx.self_contained = true;
+			break;
 		default:
 			usage_unknown_option(cmd, argv);
 		}