2 * Copyright (C) 2012 Alexander Block. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
20 #include "kerncompat.h"
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
35 #include <uuid/uuid.h>
45 #include "send-utils.h"
48 #define SEND_BUFFER_SIZE SZ_64K
51 * Default is 1 for historical reasons, changing may break scripts that expect
52 * the 'At subvol' message.
54 static int g_verbose = 1;
62 u64 clone_sources_count;
65 struct subvol_uuid_search sus;
68 static int get_root_id(struct btrfs_send *sctx, const char *path, u64 *root_id)
70 struct subvol_info *si;
72 si = subvol_uuid_search(&sctx->sus, 0, NULL, 0, path,
73 subvol_search_by_path);
74 if (IS_ERR_OR_NULL(si)) {
80 *root_id = si->root_id;
86 static struct subvol_info *get_parent(struct btrfs_send *sctx, u64 root_id)
88 struct subvol_info *si_tmp;
89 struct subvol_info *si;
91 si_tmp = subvol_uuid_search(&sctx->sus, root_id, NULL, 0, NULL,
92 subvol_search_by_root_id);
93 if (IS_ERR_OR_NULL(si_tmp))
96 si = subvol_uuid_search(&sctx->sus, 0, si_tmp->parent_uuid, 0, NULL,
97 subvol_search_by_uuid);
103 static int find_good_parent(struct btrfs_send *sctx, u64 root_id, u64 *found)
106 struct subvol_info *parent = NULL;
107 struct subvol_info *parent2 = NULL;
108 struct subvol_info *best_parent = NULL;
109 u64 best_diff = (u64)-1;
112 parent = get_parent(sctx, root_id);
113 if (IS_ERR_OR_NULL(parent)) {
117 ret = PTR_ERR(parent);
121 for (i = 0; i < sctx->clone_sources_count; i++) {
122 if (sctx->clone_sources[i] == parent->root_id) {
123 best_parent = parent;
129 for (i = 0; i < sctx->clone_sources_count; i++) {
132 parent2 = get_parent(sctx, sctx->clone_sources[i]);
133 if (IS_ERR_OR_NULL(parent2))
135 if (parent2->root_id != parent->root_id) {
144 parent2 = subvol_uuid_search(&sctx->sus,
145 sctx->clone_sources[i], NULL, 0, NULL,
146 subvol_search_by_root_id);
147 if (IS_ERR_OR_NULL(parent2)) {
151 ret = PTR_ERR(parent2);
154 tmp = parent2->ctransid - parent->ctransid;
157 if (tmp < best_diff) {
159 free(best_parent->path);
162 best_parent = parent2;
178 *found = best_parent->root_id;
187 free(best_parent->path);
193 static int add_clone_source(struct btrfs_send *sctx, u64 root_id)
197 tmp = sctx->clone_sources;
198 sctx->clone_sources = realloc(sctx->clone_sources,
199 sizeof(*sctx->clone_sources) * (sctx->clone_sources_count + 1));
201 if (!sctx->clone_sources) {
205 sctx->clone_sources[sctx->clone_sources_count++] = root_id;
211 static int write_buf(int fd, const char *buf, size_t size)
219 wbytes = write(fd, buf + pos, size - pos);
222 error("failed to dump stream: %s", strerror(-ret));
227 error("failed to dump stream: %s", strerror(-ret));
238 static void* read_sent_data_copy(void *arg)
241 struct btrfs_send *sctx = (struct btrfs_send*)arg;
242 char buf[SEND_BUFFER_SIZE];
247 rbytes = read(sctx->send_fd, buf, sizeof(buf));
250 error("failed to read stream from kernel: %s",
258 ret = write_buf(sctx->dump_fd, buf, rbytes);
271 static void *read_sent_data(void *arg)
274 struct btrfs_send *sctx = (struct btrfs_send*)arg;
279 /* Source is a pipe, output is either file or stdout */
280 sbytes = splice(sctx->send_fd, NULL, sctx->dump_fd,
281 NULL, SEND_BUFFER_SIZE, SPLICE_F_MORE);
284 error("failed to read stream from kernel: %s",
301 static int do_send(struct btrfs_send *send, u64 parent_root_id,
302 int is_first_subvol, int is_last_subvol, const char *subvol,
307 struct btrfs_ioctl_send_args io_send;
310 int pipefd[2] = {-1, -1};
312 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
315 error("cannot open %s: %s", subvol, strerror(-ret));
322 error("pipe failed: %s", strerror(-ret));
326 memset(&io_send, 0, sizeof(io_send));
327 io_send.send_fd = pipefd[1];
328 send->send_fd = pipefd[0];
331 ret = pthread_create(&t_read, NULL, read_sent_data, send);
334 error("thread setup failed: %s", strerror(-ret));
338 io_send.flags = flags;
339 io_send.clone_sources = (__u64*)send->clone_sources;
340 io_send.clone_sources_count = send->clone_sources_count;
341 io_send.parent_root = parent_root_id;
342 if (!is_first_subvol)
343 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
345 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
346 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
349 error("send ioctl failed with %d: %s", ret, strerror(-ret));
350 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
352 "Try upgrading your kernel or don't use -e.\n");
356 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
359 fprintf(stderr, "joining genl thread\n");
364 ret = pthread_join(t_read, &t_err);
367 error("pthread_join failed: %s", strerror(-ret));
371 ret = (long int)t_err;
372 error("failed to process send stream, ret=%ld (%s)",
373 (long int)t_err, strerror(-ret));
389 static int init_root_path(struct btrfs_send *sctx, const char *subvol)
396 ret = find_mount_root(subvol, &sctx->root_path);
398 error("failed to determine mount point for %s: %s",
399 subvol, strerror(-ret));
404 error("%s doesn't belong to btrfs mount point", subvol);
409 sctx->mnt_fd = open(sctx->root_path, O_RDONLY | O_NOATIME);
410 if (sctx->mnt_fd < 0) {
412 error("cannot open '%s': %s", sctx->root_path, strerror(-ret));
416 ret = subvol_uuid_search_init(sctx->mnt_fd, &sctx->sus);
418 error("failed to initialize subvol search: %s",
428 static int is_subvol_ro(struct btrfs_send *sctx, const char *subvol)
434 fd = openat(sctx->mnt_fd, subvol, O_RDONLY | O_NOATIME);
437 error("cannot open %s: %s", subvol, strerror(-ret));
441 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
444 error("failed to get flags for subvolume %s: %s",
445 subvol, strerror(-ret));
449 if (flags & BTRFS_SUBVOL_RDONLY)
461 static int set_root_info(struct btrfs_send *sctx, const char *subvol,
466 ret = init_root_path(sctx, subvol);
470 ret = get_root_id(sctx, subvol_strip_mountpoint(sctx->root_path, subvol),
473 error("cannot resolve rootid for %s", subvol);
481 static void free_send_info(struct btrfs_send *sctx)
483 if (sctx->mnt_fd >= 0) {
487 free(sctx->root_path);
488 sctx->root_path = NULL;
489 subvol_uuid_search_finit(&sctx->sus);
492 int cmd_send(int argc, char **argv)
496 char outname[PATH_MAX];
497 struct btrfs_send send;
499 char *mount_root = NULL;
500 char *snapshot_parent = NULL;
502 u64 parent_root_id = 0;
504 int new_end_cmd_semantic = 0;
507 memset(&send, 0, sizeof(send));
508 send.dump_fd = fileno(stdout);
512 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
513 static const struct option long_options[] = {
514 { "verbose", no_argument, NULL, 'v' },
515 { "quiet", no_argument, NULL, 'q' },
516 { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
518 int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);
531 new_end_cmd_semantic = 1;
534 subvol = realpath(optarg, NULL);
537 error("realpath %s failed: %s\n", optarg, strerror(-ret));
541 ret = set_root_info(&send, subvol, &root_id);
545 ret = is_subvol_ro(&send, subvol);
550 error("cloned subvolume %s is not read-only", subvol);
554 ret = add_clone_source(&send, root_id);
556 error("cannot add clone source: %s", strerror(-ret));
561 free_send_info(&send);
565 if (arg_copy_path(outname, optarg, sizeof(outname))) {
566 error("output file path too long (%zu)", strlen(optarg));
572 if (snapshot_parent) {
573 error("you cannot have more than one parent (-p)");
577 snapshot_parent = realpath(optarg, NULL);
578 if (!snapshot_parent) {
580 error("realpath %s failed: %s", optarg, strerror(-ret));
584 ret = is_subvol_ro(&send, snapshot_parent);
589 error("parent subvolume %s is not read-only",
597 error("option -i was removed, use -c instead");
600 case GETOPT_VAL_SEND_NO_DATA:
601 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
605 error("send arguments invalid");
611 if (check_argc_min(argc - optind, 1))
612 usage(cmd_send_usage);
618 * Try to use an existing file first. Even if send runs as
619 * root, it might not have permissions to create file (eg. on a
620 * NFS) but it should still be able to use a pre-created file.
622 tmpfd = open(outname, O_WRONLY | O_TRUNC);
625 tmpfd = open(outname,
626 O_CREAT | O_WRONLY | O_TRUNC, 0600);
628 send.dump_fd = tmpfd;
629 if (send.dump_fd == -1) {
631 error("cannot create '%s': %s", outname, strerror(-ret));
636 if (isatty(send.dump_fd)) {
638 "not dumping send stream into a terminal, redirect it into a file");
643 /* use first send subvol to determine mount_root */
644 subvol = realpath(argv[optind], NULL);
647 error("unable to resolve %s", argv[optind]);
651 ret = init_root_path(&send, subvol);
655 if (snapshot_parent != NULL) {
656 ret = get_root_id(&send,
657 subvol_strip_mountpoint(send.root_path, snapshot_parent),
660 error("could not resolve rootid for %s", snapshot_parent);
664 ret = add_clone_source(&send, parent_root_id);
666 error("cannot add clone source: %s", strerror(-ret));
671 for (i = optind; i < argc; i++) {
673 subvol = realpath(argv[i], NULL);
676 error("unable to resolve %s", argv[i]);
680 ret = find_mount_root(subvol, &mount_root);
682 error("find_mount_root failed on %s: %s", subvol,
687 error("%s does not belong to btrfs mount point",
692 if (strcmp(send.root_path, mount_root) != 0) {
694 error("all subvolumes must be from the same filesystem");
699 ret = is_subvol_ro(&send, subvol);
704 error("subvolume %s is not read-only", subvol);
709 if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1)
711 fprintf(stderr, "Mode NO_FILE_DATA enabled\n");
713 for (i = optind; i < argc; i++) {
721 fprintf(stderr, "At subvol %s\n", subvol);
723 subvol = realpath(subvol, NULL);
726 error("realpath %s failed: %s", argv[i], strerror(-ret));
730 if (!full_send && !snapshot_parent) {
731 ret = set_root_info(&send, subvol, &root_id);
735 ret = find_good_parent(&send, root_id, &parent_root_id);
737 error("parent determination failed for %lld",
743 if (new_end_cmd_semantic) {
744 /* require new kernel */
745 is_first_subvol = (i == optind);
746 is_last_subvol = (i == argc - 1);
748 /* be compatible to old and new kernel */
752 ret = do_send(&send, parent_root_id, is_first_subvol,
753 is_last_subvol, subvol, send_flags);
757 if (!full_send && !snapshot_parent) {
758 /* done with this subvol, so add it to the clone sources */
759 ret = add_clone_source(&send, root_id);
761 error("cannot add clone source: %s", strerror(-ret));
764 free_send_info(&send);
772 free(snapshot_parent);
773 free(send.clone_sources);
774 free_send_info(&send);
778 const char * const cmd_send_usage[] = {
779 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
780 "Send the subvolume(s) to stdout.",
781 "Sends the subvolume(s) specified by <subvol> to stdout.",
782 "<subvol> should be read-only here.",
783 "By default, this will send the whole subvolume. To do an incremental",
784 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
785 "any additional local snapshots, use '-c <clone-src>' (multiple times",
786 "where applicable). You must not specify clone sources unless you",
787 "guarantee that these snapshots are exactly in the same state on both",
788 "sides, the sender and the receiver. It is allowed to omit the",
789 "'-p <parent>' option when '-c <clone-src>' options are given, in",
790 "which case 'btrfs send' will determine a suitable parent among the",
791 "clone sources itself.",
793 "-e If sending multiple subvols at once, use the new",
794 " format and omit the end-cmd between the subvols.",
795 "-p <parent> Send an incremental stream from <parent> to",
797 "-c <clone-src> Use this snapshot as a clone source for an ",
798 " incremental send (multiple allowed)",
799 "-f <outfile> Output is normally written to stdout. To write to",
800 " a file, use this option. An alternative would be to",
802 "--no-data send in NO_FILE_DATA mode, Note: the output stream",
803 " does not contain any file data and thus cannot be used",
804 " to transfer changes. This mode is faster and useful to",
805 " show the differences in metadata.",
806 "-v|--verbose enable verbose output to stderr, each occurrence of",
807 " this option increases verbosity",
808 "-q|--quiet suppress all messages, except errors",