* [PATCH] btrfs-progs: make receive work inside of subvolumes
@ 2015-06-10 19:05 Josef Bacik
2015-06-11 17:02 ` David Sterba
0 siblings, 1 reply; 2+ messages in thread
From: Josef Bacik @ 2015-06-10 19:05 UTC (permalink / raw)
To: linux-btrfs
Kind of a big feature of btrfs is being able to have a default subvol. However
the receive code generates the paths to the subvols from the root of the fs,
even in the case of a default subvol. So instead figure out if we're inside of
a subvol, either because we have a different default or we've chroot'ed and are
using -m. Then strip this extra path off of the subvol we find so we can look
up our parent properly. Thanks
Reported-by: Neil Horman <nhorman@redhat.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
---
cmds-receive.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 87 insertions(+), 2 deletions(-)
diff --git a/cmds-receive.c b/cmds-receive.c
index 28ae8e9..9925b47 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -61,6 +61,7 @@ struct btrfs_receive
char *root_path;
char *dest_dir_path; /* relative to root_path */
char *full_subvol_path;
+ char *full_root_path;
int dest_dir_chroot;
struct subvol_info *cur_subvol;
@@ -240,6 +241,45 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
goto out;
}
+ /*
+ * The path is resolved from the root subvol, but we could be in some
+ * subvolume under the root subvolume, so try and adjust the path to be
+ * relative to our root path.
+ */
+ if (r->full_root_path) {
+ size_t root_len, sub_len;
+
+ root_len = strlen(r->full_root_path);
+ sub_len = strlen(parent_subvol->path);
+
+ /* First make sure the parent subvol is actually in our path */
+ if (sub_len < root_len ||
+ strstr(parent_subvol->path, r->full_root_path) == NULL) {
+ fprintf(stderr, "ERROR: parent subvol is not reachable"
+ " from inside the root subvol.\n");
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (sub_len == root_len) {
+ parent_subvol->path[0] = '/';
+ parent_subvol->path[1] = '\0';
+ } else {
+ /*
+ * root path is foo/bar
+ * subvol path is foo/bar/baz
+ *
+ * we need to have baz be the path, so we need to move
+ * the bit after foo/bar/, so path + root_len + 1, and
+ * move the part we care about, so sub_len - root_len -
+ * 1.
+ */
+ memmove(parent_subvol->path,
+ parent_subvol->path + root_len + 1,
+ sub_len - root_len - 1);
+ parent_subvol->path[sub_len - root_len - 1] = '\0';
+ }
+ }
/*if (rs_args.ctransid > rs_args.rtransid) {
if (!r->force) {
ret = -EINVAL;
@@ -250,8 +290,11 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
}
}*/
- args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
- O_RDONLY | O_NOATIME);
+ if (strlen(parent_subvol->path) == 0)
+ args_v2.fd = dup(r->mnt_fd);
+ else
+ args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
+ O_RDONLY | O_NOATIME);
if (args_v2.fd < 0) {
ret = -errno;
if (errno != ENOENT)
@@ -816,8 +859,10 @@ static struct btrfs_send_ops send_ops = {
static int do_receive(struct btrfs_receive *r, const char *tomnt,
char *realmnt, int r_fd, u64 max_errors)
{
+ u64 subvol_id;
int ret;
char *dest_dir_full_path;
+ char *root_subvol_path;
int end = 0;
dest_dir_full_path = realpath(tomnt, NULL);
@@ -863,6 +908,42 @@ static int do_receive(struct btrfs_receive *r, const char *tomnt,
goto out;
}
+ /*
+ * If we use -m or a default subvol we want to resolve the path to the
+ * subvolume we're sitting in so that we can adjust the paths of any
+ * subvols we want to receive in.
+ */
+ ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
+ if (ret) {
+ fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
+ ret);
+ goto out;
+ }
+
+ root_subvol_path = malloc(BTRFS_PATH_NAME_MAX);
+ if (!root_subvol_path) {
+ ret = -ENOMEM;
+ fprintf(stderr, "ERROR: couldn't allocate buffer for the root "
+ "subvol path\n");
+ goto out;
+ }
+
+ ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
+ BTRFS_PATH_NAME_MAX, subvol_id);
+ if (ret) {
+ fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
+ goto out;
+ }
+
+ /*
+ * Ok we're inside of a subvol off of the root subvol, we need to
+ * actually set full_root_path.
+ */
+ if (strlen(root_subvol_path))
+ r->full_root_path = root_subvol_path;
+ else
+ free(root_subvol_path);
+
if (r->dest_dir_chroot) {
if (chroot(dest_dir_full_path)) {
ret = -errno;
@@ -940,6 +1021,10 @@ out:
close(r->dest_dir_fd);
r->dest_dir_fd = -1;
}
+ if (r->full_root_path) {
+ free(r->full_root_path);
+ r->full_root_path = NULL;
+ }
return ret;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] btrfs-progs: make receive work inside of subvolumes
2015-06-10 19:05 [PATCH] btrfs-progs: make receive work inside of subvolumes Josef Bacik
@ 2015-06-11 17:02 ` David Sterba
0 siblings, 0 replies; 2+ messages in thread
From: David Sterba @ 2015-06-11 17:02 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs
On Wed, Jun 10, 2015 at 03:05:51PM -0400, Josef Bacik wrote:
> Kind of a big feature of btrfs is being able to have a default subvol. However
> the receive code generates the paths to the subvols from the root of the fs,
> even in the case of a default subvol. So instead figure out if we're inside of
> a subvol, either because we have a different default or we've chroot'ed and are
> using -m. Then strip this extra path off of the subvol we find so we can look
> up our parent properly. Thanks
>
> Reported-by: Neil Horman <nhorman@redhat.com>
> Signed-off-by: Josef Bacik <jbacik@fb.com>
Applied, thanks.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2015-06-11 17:02 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-10 19:05 [PATCH] btrfs-progs: make receive work inside of subvolumes Josef Bacik
2015-06-11 17:02 ` David Sterba
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.