linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: junlion@tormail.org
To: Alex Lyakas <alex.btrfs@zadarastorage.com>
Cc: linux-btrfs@vger.kernel.org
Subject: Re: Incremental btrfs receive in opposite direction fails
Date: Sun, 30 Dec 2012 06:40:08 +0000	[thread overview]
Message-ID: <1TpCWu-000Fz2-6t@internal.tormail.org> (raw)
In-Reply-To: <CAOcd+r3OjBAGbRN-cSbL7tQP=tTRYakZO3fm9gA_oqSz6KXuYw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1235 bytes --]

On 2012-12-29 15:00 +0200, Alex Lyakas wrote:
> There is no special repo, but you may want, in addition to the patch
> you mentioned, apply this one as well:
> https://patchwork.kernel.org/patch/1604391/

Very useful! Somehow a few lines got wrapped though.

> > Is there a way for me to directly change the received_uuid of
> > /mnt/bak/.snap to make it identical to the UUID of /.snap? This looks
> > like the easiest way if I only need to do it once.
> There is no implemented way, but since you debugged this far, you can
> put up some code that sends BTRFS_IOC_SET_RECEIVED_SUBVOL, which is
> the one setting the received_uuid (and some other small stuff, please
> check the kernel code for it).

Ah, BTRFS_IOC_SET_RECEIVED_SUBVOL. Thanks for pointing me in the right
direction. After some hacking, it worked without eating my data... These
are the two commands to run before the failing one:

btrfs subvolume snapshot /mnt/bak/.snap /mnt/bak/.snap-mangled
uu / .snap /mnt/bak/.snap-mangled

... where uu is my crude little received_uuid and stransid display and
adjustment tool. I've attached its source.

Would be cool if someone modified btrfs send/receive to handle this use
case automatically, but it's too difficult for me.

[-- Attachment #2: unwrapped__btrfs-progs-Fix-the-receive-code-pathing.patch --]
[-- Type: text/x-diff, Size: 4603 bytes --]

diff --git a/cmds-receive.c b/cmds-receive.c
index a8be6fa..40d2e48 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -52,11 +52,13 @@ static int g_verbose = 0;
 struct btrfs_receive
 {
 	int mnt_fd;
+	int dest_dir_fd;
 
 	int write_fd;
 	char *write_path;
 
 	char *root_path;
+	char *dest_dir_path; /* relative to root_path */
 	char *full_subvol_path;
 
 	struct subvol_info *cur_subvol;
@@ -150,8 +152,11 @@ static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
 	r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
 	r->parent_subvol = NULL;
 
-	r->cur_subvol->path = strdup(path);
-	r->full_subvol_path = path_cat(r->root_path, path);
+	if (strlen(r->dest_dir_path) == 0)
+		r->cur_subvol->path = strdup(path);
+	else
+		r->cur_subvol->path = path_cat(r->dest_dir_path, path);
+	r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
 
 	fprintf(stderr, "At subvol %s\n", path);
 
@@ -167,7 +172,7 @@ static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
 
 	memset(&args_v1, 0, sizeof(args_v1));
 	strcpy(args_v1.name, path);
-	ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
+	ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
 	if (ret < 0) {
 		ret = -errno;
 		fprintf(stderr, "ERROR: creating subvolume %s failed. "
@@ -195,8 +200,11 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
 	r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
 	r->parent_subvol = NULL;
 
-	r->cur_subvol->path = strdup(path);
-	r->full_subvol_path = path_cat(r->root_path, path);
+	if (strlen(r->dest_dir_path) == 0)
+		r->cur_subvol->path = strdup(path);
+	else
+		r->cur_subvol->path = path_cat(r->dest_dir_path, path);
+	r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
 
 	fprintf(stderr, "At snapshot %s\n", path);
 
@@ -243,7 +251,7 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
 		goto out;
 	}
 
-	ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
+	ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
 	close(args_v2.fd);
 	if (ret < 0) {
 		ret = -errno;
@@ -790,17 +798,48 @@ struct btrfs_send_ops send_ops = {
 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
 {
 	int ret;
+	char *dest_dir_full_path;
 	int end = 0;
 
-	r->root_path = strdup(tomnt);
-	r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
+	dest_dir_full_path = realpath(tomnt, NULL);
+	if (!dest_dir_full_path) {
+		ret = -errno;
+		fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
+				strerror(-ret));
+		goto out;
+	}
+	r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
+	if (r->dest_dir_fd < 0) {
+		ret = -errno;
+		fprintf(stderr, "ERROR: failed to open destination directory %s. %s\n",
+			    dest_dir_full_path, strerror(-ret));
+		goto out;
+	}
+
+	ret = find_mount_root(dest_dir_full_path, &r->root_path);
+	if (ret < 0) {
+		ret = -EINVAL;
+		fprintf(stderr, "ERROR: failed to determine mount point "
+				"for %s\n", dest_dir_full_path);
+		goto out;
+	}
+	r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
 	if (r->mnt_fd < 0) {
 		ret = -errno;
-		fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
+		fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
 				strerror(-ret));
 		goto out;
 	}
 
+	/*
+	 * find_mount_root returns a root_path that is a subpath of
+	 * dest_dir_full_path. Now get the other part of root_path,
+	 * which is the destination dir relative to root_path.
+	 */
+	r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
+	if (r->dest_dir_path[0] == '/')
+		r->dest_dir_path++;
+
 	ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
 	if (ret < 0)
 		return ret;
diff --git a/cmds-send.c b/cmds-send.c
index 9b47e70..c408bc7 100644
--- a/cmds-send.c
+++ b/cmds-send.c
@@ -81,6 +81,14 @@ int find_mount_root(const char *path, char **mount_root)
 		}
 	}
 
+	if (!longest_match) {
+		fprintf(stderr, "ERROR: Failed to find mount root for path %s.\n",
+			    path);
+		fprintf(stderr, "Please make sure that you have a valid \
+			/etc/mtab file.\n");
+		return -ENOENT;
+	}
+
 	*mount_root = realpath(longest_match, NULL);
 	free(longest_match);
 
diff --git a/send-utils.h b/send-utils.h
index da407eb..a3e038b 100644
--- a/send-utils.h
+++ b/send-utils.h
@@ -65,5 +65,6 @@ void subvol_uuid_search_add(struct subvol_uuid_search *s,
 char *path_cat(const char *p1, const char *p2);
 char *path_cat3(const char *p1, const char *p2, const char *p3);
 
+int find_mount_root(const char *path, char **mount_root);
 
 #endif /* SEND_UTILS_H_ */

[-- Attachment #3: uu.c --]
[-- Type: text/x-c, Size: 2697 bytes --]

/*
git clone https://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-progs.git
cd btrfs-progs
make
gcc -O2 -luuid -o uu send-utils.o rbtree.o btrfs-list.o /path/to/this/file/uu.c
*/

#define _GNU_SOURCE

#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <uuid/uuid.h>
#include <sys/ioctl.h>

#include "ctree.h"
#include "ioctl.h"
#include "send-utils.h"

#define CLEAR(var) memset(&var, 0, sizeof(var))


int main(int argc, char **argv) {
	int ret, fd;
	struct subvol_uuid_search sus;
	struct btrfs_ioctl_received_subvol_args rs_args;
	struct subvol_info *si;
	char uuidbuf[37], parent_uuidbuf[37], received_uuidbuf[37];


	if (argc != 3 && argc != 4) {
		printf("usage: uu srcmnt srcsub_reltosrcmnt [dstsub_abs]\n");
		exit(1);
	}

	printf("opening srcmnt %s\n", argv[1]);
	fd = open(argv[1], O_RDONLY | O_NOATIME);
	if (fd < 0) {
		printf("failed to open srcmnt %s! %s\n", argv[1], strerror(errno));
		exit(2);
	}

	puts("initializing sub search");
	CLEAR(sus);
	ret = subvol_uuid_search_init(fd, &sus);
	if (ret < 0) {
		printf("failed to initialize sub search! %s\n", strerror(-ret));
		exit(3);
	}
	
	printf("searching srcsub %s\n", argv[2]);
	si = subvol_uuid_search(&sus, 0, NULL, 0, argv[2], subvol_search_by_path);
	if (!si) {
		puts("srcsub not found!");
		exit(4);
	}

	uuid_unparse(si->uuid,                   uuidbuf);
	uuid_unparse(si->parent_uuid,     parent_uuidbuf);
	uuid_unparse(si->received_uuid, received_uuidbuf);

	printf("\nsrcsub found:\n"
	       "         uuid=%s\n"
	       "  parent_uuid=%s\n"
	       "received_uuid=%s\n"
	       "ctransid=%Lu otransid=%Lu stransid=%Lu rtransid=%Lu\n\n",
	       uuidbuf, parent_uuidbuf, received_uuidbuf,
	       (unsigned long long)(si->ctransid),
	       (unsigned long long)(si->otransid),
	       (unsigned long long)(si->stransid),
	       (unsigned long long)(si->rtransid));

	if (argc == 3)
		goto done;

	printf("opening dst subvol %s\n", argv[3]);
	fd = open(argv[3], O_RDONLY | O_NOATIME);
	if (fd < 0) {
		printf("failed to open dst subvol %s. %s\n", argv[3], strerror(errno));
		exit(5);
	}

	printf("\nhere we go with BTRFS_IOC_SET_RECEIVED_SUBVOL:\n"
	       "dstsub.received_uuid = srcsub.uuid == %s\n"
	       "dstsub.stransid = srcsub.ctransid == %Lu\n\n",
	       uuidbuf, (unsigned long long)(si->ctransid));

	CLEAR(rs_args);
	memcpy(rs_args.uuid, si->uuid, BTRFS_UUID_SIZE);
	rs_args.stransid = si->ctransid;

	ret = ioctl(fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
	if (ret < 0) {
		printf("BTRFS_IOC_SET_RECEIVED_SUBVOL failed: %s", strerror(-ret));
		exit(6);
	}

done:
	printf("done.\n");
	exit(0);
}

  reply	other threads:[~2012-12-30  6:39 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-28 22:42 Incremental btrfs receive in opposite direction fails junlion
2012-12-29 13:00 ` Alex Lyakas
2012-12-30  6:40   ` junlion [this message]
2013-01-02 16:57     ` Jan Schmidt
2013-01-02 20:56       ` Jun Lion
     [not found]       ` <20130102205351.GA2242@localhost>
2013-01-02 22:19         ` junlion

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1TpCWu-000Fz2-6t@internal.tormail.org \
    --to=junlion@tormail.org \
    --cc=alex.btrfs@zadarastorage.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).