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"
47 #define SEND_BUFFER_SIZE (64 * 1024)
50 * Default is 1 for historical reasons, changing may break scripts that expect
51 * the 'At subvol' message.
53 static int g_verbose = 1;
61 u64 clone_sources_count;
64 struct subvol_uuid_search sus;
67 static int get_root_id(struct btrfs_send *sctx, const char *path, u64 *root_id)
69 struct subvol_info *si;
71 si = subvol_uuid_search(&sctx->sus, 0, NULL, 0, path,
72 subvol_search_by_path);
75 *root_id = si->root_id;
81 static struct subvol_info *get_parent(struct btrfs_send *sctx, u64 root_id)
83 struct subvol_info *si_tmp;
84 struct subvol_info *si;
86 si_tmp = subvol_uuid_search(&sctx->sus, root_id, NULL, 0, NULL,
87 subvol_search_by_root_id);
91 si = subvol_uuid_search(&sctx->sus, 0, si_tmp->parent_uuid, 0, NULL,
92 subvol_search_by_uuid);
98 static int find_good_parent(struct btrfs_send *sctx, u64 root_id, u64 *found)
101 struct subvol_info *parent = NULL;
102 struct subvol_info *parent2 = NULL;
103 struct subvol_info *best_parent = NULL;
104 u64 best_diff = (u64)-1;
107 parent = get_parent(sctx, root_id);
113 for (i = 0; i < sctx->clone_sources_count; i++) {
114 if (sctx->clone_sources[i] == parent->root_id) {
115 best_parent = parent;
121 for (i = 0; i < sctx->clone_sources_count; i++) {
124 parent2 = get_parent(sctx, sctx->clone_sources[i]);
127 if (parent2->root_id != parent->root_id) {
136 parent2 = subvol_uuid_search(&sctx->sus,
137 sctx->clone_sources[i], NULL, 0, NULL,
138 subvol_search_by_root_id);
144 tmp = parent2->ctransid - parent->ctransid;
147 if (tmp < best_diff) {
149 free(best_parent->path);
152 best_parent = parent2;
168 *found = best_parent->root_id;
177 free(best_parent->path);
183 static int add_clone_source(struct btrfs_send *sctx, u64 root_id)
187 tmp = sctx->clone_sources;
188 sctx->clone_sources = realloc(sctx->clone_sources,
189 sizeof(*sctx->clone_sources) * (sctx->clone_sources_count + 1));
191 if (!sctx->clone_sources) {
195 sctx->clone_sources[sctx->clone_sources_count++] = root_id;
201 static int write_buf(int fd, const char *buf, size_t size)
209 wbytes = write(fd, buf + pos, size - pos);
212 error("failed to dump stream: %s", strerror(-ret));
217 error("failed to dump stream: %s", strerror(-ret));
228 static void* read_sent_data_copy(void *arg)
231 struct btrfs_send *sctx = (struct btrfs_send*)arg;
232 char buf[SEND_BUFFER_SIZE];
237 rbytes = read(sctx->send_fd, buf, sizeof(buf));
240 error("failed to read stream from kernel: %s",
248 ret = write_buf(sctx->dump_fd, buf, rbytes);
261 static void *read_sent_data(void *arg)
264 struct btrfs_send *sctx = (struct btrfs_send*)arg;
269 /* Source is a pipe, output is either file or stdout */
270 sbytes = splice(sctx->send_fd, NULL, sctx->dump_fd,
271 NULL, SEND_BUFFER_SIZE, SPLICE_F_MORE);
274 error("failed to read stream from kernel: %s",
291 static int do_send(struct btrfs_send *send, u64 parent_root_id,
292 int is_first_subvol, int is_last_subvol, const char *subvol,
297 struct btrfs_ioctl_send_args io_send;
300 int pipefd[2] = {-1, -1};
302 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
305 error("cannot open %s: %s", subvol, strerror(-ret));
312 error("pipe failed: %s", strerror(-ret));
316 memset(&io_send, 0, sizeof(io_send));
317 io_send.send_fd = pipefd[1];
318 send->send_fd = pipefd[0];
321 ret = pthread_create(&t_read, NULL, read_sent_data, send);
324 error("thread setup failed: %s", strerror(-ret));
328 io_send.flags = flags;
329 io_send.clone_sources = (__u64*)send->clone_sources;
330 io_send.clone_sources_count = send->clone_sources_count;
331 io_send.parent_root = parent_root_id;
332 if (!is_first_subvol)
333 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
335 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
336 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
339 error("send ioctl failed with %d: %s", ret, strerror(-ret));
340 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
342 "Try upgrading your kernel or don't use -e.\n");
346 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
349 fprintf(stderr, "joining genl thread\n");
354 ret = pthread_join(t_read, &t_err);
357 error("pthread_join failed: %s", strerror(-ret));
361 ret = (long int)t_err;
362 error("failed to process send stream, ret=%ld (%s)",
363 (long int)t_err, strerror(-ret));
379 static int init_root_path(struct btrfs_send *sctx, const char *subvol)
386 ret = find_mount_root(subvol, &sctx->root_path);
388 error("failed to determine mount point for %s: %s",
389 subvol, strerror(-ret));
394 error("%s doesn't belong to btrfs mount point", subvol);
399 sctx->mnt_fd = open(sctx->root_path, O_RDONLY | O_NOATIME);
400 if (sctx->mnt_fd < 0) {
402 error("cannot open '%s': %s", sctx->root_path, strerror(-ret));
406 ret = subvol_uuid_search_init(sctx->mnt_fd, &sctx->sus);
408 error("failed to initialize subvol search: %s",
418 static int is_subvol_ro(struct btrfs_send *sctx, const char *subvol)
424 fd = openat(sctx->mnt_fd, subvol, O_RDONLY | O_NOATIME);
427 error("cannot open %s: %s", subvol, strerror(-ret));
431 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
434 error("failed to get flags for subvolume %s: %s",
435 subvol, strerror(-ret));
439 if (flags & BTRFS_SUBVOL_RDONLY)
451 static int set_root_info(struct btrfs_send *sctx, const char *subvol,
456 ret = init_root_path(sctx, subvol);
460 ret = get_root_id(sctx, subvol_strip_mountpoint(sctx->root_path, subvol),
463 error("cannot resolve rootid for %s", subvol);
471 static void free_send_info(struct btrfs_send *sctx)
473 if (sctx->mnt_fd >= 0) {
477 free(sctx->root_path);
478 sctx->root_path = NULL;
479 subvol_uuid_search_finit(&sctx->sus);
482 int cmd_send(int argc, char **argv)
486 char outname[PATH_MAX];
487 struct btrfs_send send;
489 char *mount_root = NULL;
490 char *snapshot_parent = NULL;
492 u64 parent_root_id = 0;
494 int new_end_cmd_semantic = 0;
497 memset(&send, 0, sizeof(send));
498 send.dump_fd = fileno(stdout);
502 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
503 static const struct option long_options[] = {
504 { "verbose", no_argument, NULL, 'v' },
505 { "quiet", no_argument, NULL, 'q' },
506 { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
508 int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);
521 new_end_cmd_semantic = 1;
524 subvol = realpath(optarg, NULL);
527 error("realpath %s failed: %s\n", optarg, strerror(-ret));
531 ret = set_root_info(&send, subvol, &root_id);
535 ret = is_subvol_ro(&send, subvol);
540 error("cloned subvolume %s is not read-only", subvol);
544 ret = add_clone_source(&send, root_id);
546 error("cannot add clone source: %s", strerror(-ret));
551 free_send_info(&send);
555 if (arg_copy_path(outname, optarg, sizeof(outname))) {
556 error("output file path too long (%zu)", strlen(optarg));
562 if (snapshot_parent) {
563 error("you cannot have more than one parent (-p)");
567 snapshot_parent = realpath(optarg, NULL);
568 if (!snapshot_parent) {
570 error("realpath %s failed: %s", optarg, strerror(-ret));
574 ret = is_subvol_ro(&send, snapshot_parent);
579 error("parent subvolume %s is not read-only",
587 error("option -i was removed, use -c instead");
590 case GETOPT_VAL_SEND_NO_DATA:
591 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
595 error("send arguments invalid");
601 if (check_argc_min(argc - optind, 1))
602 usage(cmd_send_usage);
608 * Try to use an existing file first. Even if send runs as
609 * root, it might not have permissions to create file (eg. on a
610 * NFS) but it should still be able to use a pre-created file.
612 tmpfd = open(outname, O_WRONLY | O_TRUNC);
615 tmpfd = open(outname,
616 O_CREAT | O_WRONLY | O_TRUNC, 0600);
618 send.dump_fd = tmpfd;
619 if (send.dump_fd == -1) {
621 error("cannot create '%s': %s", outname, strerror(-ret));
626 if (isatty(send.dump_fd)) {
628 "not dumping send stream into a terminal, redirect it into a file");
633 /* use first send subvol to determine mount_root */
634 subvol = realpath(argv[optind], NULL);
637 error("unable to resolve %s", argv[optind]);
641 ret = init_root_path(&send, subvol);
645 if (snapshot_parent != NULL) {
646 ret = get_root_id(&send,
647 subvol_strip_mountpoint(send.root_path, snapshot_parent),
650 error("could not resolve rootid for %s", snapshot_parent);
654 ret = add_clone_source(&send, parent_root_id);
656 error("cannot add clone source: %s", strerror(-ret));
661 for (i = optind; i < argc; i++) {
663 subvol = realpath(argv[i], NULL);
666 error("unable to resolve %s", argv[i]);
670 ret = find_mount_root(subvol, &mount_root);
672 error("find_mount_root failed on %s: %s", subvol,
677 error("%s does not belong to btrfs mount point",
682 if (strcmp(send.root_path, mount_root) != 0) {
684 error("all subvolumes must be from the same filesystem");
689 ret = is_subvol_ro(&send, subvol);
694 error("subvolume %s is not read-only", subvol);
699 if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1)
701 fprintf(stderr, "Mode NO_FILE_DATA enabled\n");
703 for (i = optind; i < argc; i++) {
711 fprintf(stderr, "At subvol %s\n", subvol);
713 subvol = realpath(subvol, NULL);
716 error("realpath %s failed: %s", argv[i], strerror(-ret));
720 if (!full_send && !snapshot_parent) {
721 ret = set_root_info(&send, subvol, &root_id);
725 ret = find_good_parent(&send, root_id, &parent_root_id);
727 error("parent determination failed for %lld",
733 if (new_end_cmd_semantic) {
734 /* require new kernel */
735 is_first_subvol = (i == optind);
736 is_last_subvol = (i == argc - 1);
738 /* be compatible to old and new kernel */
742 ret = do_send(&send, parent_root_id, is_first_subvol,
743 is_last_subvol, subvol, send_flags);
747 if (!full_send && !snapshot_parent) {
748 /* done with this subvol, so add it to the clone sources */
749 ret = add_clone_source(&send, root_id);
751 error("cannot add clone source: %s", strerror(-ret));
754 free_send_info(&send);
762 free(snapshot_parent);
763 free(send.clone_sources);
764 free_send_info(&send);
768 const char * const cmd_send_usage[] = {
769 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
770 "Send the subvolume(s) to stdout.",
771 "Sends the subvolume(s) specified by <subvol> to stdout.",
772 "<subvol> should be read-only here.",
773 "By default, this will send the whole subvolume. To do an incremental",
774 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
775 "any additional local snapshots, use '-c <clone-src>' (multiple times",
776 "where applicable). You must not specify clone sources unless you",
777 "guarantee that these snapshots are exactly in the same state on both",
778 "sides, the sender and the receiver. It is allowed to omit the",
779 "'-p <parent>' option when '-c <clone-src>' options are given, in",
780 "which case 'btrfs send' will determine a suitable parent among the",
781 "clone sources itself.",
783 "-e If sending multiple subvols at once, use the new",
784 " format and omit the end-cmd between the subvols.",
785 "-p <parent> Send an incremental stream from <parent> to",
787 "-c <clone-src> Use this snapshot as a clone source for an ",
788 " incremental send (multiple allowed)",
789 "-f <outfile> Output is normally written to stdout. To write to",
790 " a file, use this option. An alternative would be to",
792 "--no-data send in NO_FILE_DATA mode, Note: the output stream",
793 " does not contain any file data and thus cannot be used",
794 " to transfer changes. This mode is faster and useful to",
795 " show the differences in metadata.",
796 "-v|--verbose enable verbose output to stderr, each occurrence of",
797 " this option increases verbosity",
798 "-q|--quiet suppress all messages, except errors",