From patchwork Sun Dec 30 06:40:08 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: junlion@tormail.org X-Patchwork-Id: 1919581 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 19E63DF23A for ; Sun, 30 Dec 2012 06:50:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752611Ab2L3Gjx (ORCPT ); Sun, 30 Dec 2012 01:39:53 -0500 Received: from outgoing.tormail.org ([82.221.96.22]:44876 "EHLO outgoing.tormail.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751328Ab2L3Gjv (ORCPT ); Sun, 30 Dec 2012 01:39:51 -0500 Received: from localhost ([127.0.0.1] helo=internal.tormail.org) by outgoing.tormail.org with esmtp (Exim 4.72) (envelope-from ) id 1TpCYm-00036q-K8; Sun, 30 Dec 2012 09:39:49 +0300 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tormail.org; s=tm; h=Message-Id:X-TorMail-User:In-Reply-To:Content-Type:MIME-Version:References:Subject:Cc:To:From:Date; bh=1R7ZP0/jv47s7iDL0AlTjltOkJh4KLuKzeybiYFzjLY=; b=gclut7I+avsjqbhJv8Jyk06w/k/kiJzRcDxa5VmXa/gRgB3tFSP33eb7iwUK3bYpn1HNNkx1QZMx1Sfmtz2bQPSIwGDH0lxXaG3/bE+OecLVdSKjz9fkqrZEgLi27gqLn1zCjTeXMeRepZOLtgdb/vWOWYWa1lJsSJ1EqiA/j28=; Received: from junlion by internal.tormail.org with local (Exim 4.63) (envelope-from ) id 1TpCWu-000Fz2-6t; Sun, 30 Dec 2012 06:37:53 +0000 Date: Sun, 30 Dec 2012 06:40:08 +0000 From: junlion@tormail.org To: Alex Lyakas Cc: linux-btrfs@vger.kernel.org Subject: Re: Incremental btrfs receive in opposite direction fails References: <1ToibV-0001fD-SN@internal.tormail.org> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-TorMail-User: junlion Message-Id: <1TpCWu-000Fz2-6t@internal.tormail.org> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org 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. 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_ */