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);
73 if (IS_ERR_OR_NULL(si)) {
79 *root_id = si->root_id;
85 static struct subvol_info *get_parent(struct btrfs_send *sctx, u64 root_id)
87 struct subvol_info *si_tmp;
88 struct subvol_info *si;
90 si_tmp = subvol_uuid_search(&sctx->sus, root_id, NULL, 0, NULL,
91 subvol_search_by_root_id);
92 if (IS_ERR_OR_NULL(si_tmp))
95 si = subvol_uuid_search(&sctx->sus, 0, si_tmp->parent_uuid, 0, NULL,
96 subvol_search_by_uuid);
102 static int find_good_parent(struct btrfs_send *sctx, u64 root_id, u64 *found)
105 struct subvol_info *parent = NULL;
106 struct subvol_info *parent2 = NULL;
107 struct subvol_info *best_parent = NULL;
108 u64 best_diff = (u64)-1;
111 parent = get_parent(sctx, root_id);
112 if (IS_ERR_OR_NULL(parent)) {
116 ret = PTR_ERR(parent);
120 for (i = 0; i < sctx->clone_sources_count; i++) {
121 if (sctx->clone_sources[i] == parent->root_id) {
122 best_parent = parent;
128 for (i = 0; i < sctx->clone_sources_count; i++) {
131 parent2 = get_parent(sctx, sctx->clone_sources[i]);
132 if (IS_ERR_OR_NULL(parent2))
134 if (parent2->root_id != parent->root_id) {
143 parent2 = subvol_uuid_search(&sctx->sus,
144 sctx->clone_sources[i], NULL, 0, NULL,
145 subvol_search_by_root_id);
146 if (IS_ERR_OR_NULL(parent2)) {
150 ret = PTR_ERR(parent2);
153 tmp = parent2->ctransid - parent->ctransid;
156 if (tmp < best_diff) {
158 free(best_parent->path);
161 best_parent = parent2;
177 *found = best_parent->root_id;
186 free(best_parent->path);
192 static int add_clone_source(struct btrfs_send *sctx, u64 root_id)
196 tmp = sctx->clone_sources;
197 sctx->clone_sources = realloc(sctx->clone_sources,
198 sizeof(*sctx->clone_sources) * (sctx->clone_sources_count + 1));
200 if (!sctx->clone_sources) {
204 sctx->clone_sources[sctx->clone_sources_count++] = root_id;
210 static int write_buf(int fd, const char *buf, size_t size)
218 wbytes = write(fd, buf + pos, size - pos);
221 error("failed to dump stream: %s", strerror(-ret));
226 error("failed to dump stream: %s", strerror(-ret));
237 static void* read_sent_data_copy(void *arg)
240 struct btrfs_send *sctx = (struct btrfs_send*)arg;
241 char buf[SEND_BUFFER_SIZE];
246 rbytes = read(sctx->send_fd, buf, sizeof(buf));
249 error("failed to read stream from kernel: %s",
257 ret = write_buf(sctx->dump_fd, buf, rbytes);
270 static void *read_sent_data(void *arg)
273 struct btrfs_send *sctx = (struct btrfs_send*)arg;
278 /* Source is a pipe, output is either file or stdout */
279 sbytes = splice(sctx->send_fd, NULL, sctx->dump_fd,
280 NULL, SEND_BUFFER_SIZE, SPLICE_F_MORE);
283 error("failed to read stream from kernel: %s",
300 static int do_send(struct btrfs_send *send, u64 parent_root_id,
301 int is_first_subvol, int is_last_subvol, const char *subvol,
306 struct btrfs_ioctl_send_args io_send;
309 int pipefd[2] = {-1, -1};
311 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
314 error("cannot open %s: %s", subvol, strerror(-ret));
321 error("pipe failed: %s", strerror(-ret));
325 memset(&io_send, 0, sizeof(io_send));
326 io_send.send_fd = pipefd[1];
327 send->send_fd = pipefd[0];
330 ret = pthread_create(&t_read, NULL, read_sent_data, send);
333 error("thread setup failed: %s", strerror(-ret));
337 io_send.flags = flags;
338 io_send.clone_sources = (__u64*)send->clone_sources;
339 io_send.clone_sources_count = send->clone_sources_count;
340 io_send.parent_root = parent_root_id;
341 if (!is_first_subvol)
342 io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER;
344 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
345 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
348 error("send ioctl failed with %d: %s", ret, strerror(-ret));
349 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
351 "Try upgrading your kernel or don't use -e.\n");
355 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
358 fprintf(stderr, "joining genl thread\n");
363 ret = pthread_join(t_read, &t_err);
366 error("pthread_join failed: %s", strerror(-ret));
370 ret = (long int)t_err;
371 error("failed to process send stream, ret=%ld (%s)",
372 (long int)t_err, strerror(-ret));
388 static int init_root_path(struct btrfs_send *sctx, const char *subvol)
395 ret = find_mount_root(subvol, &sctx->root_path);
397 error("failed to determine mount point for %s: %s",
398 subvol, strerror(-ret));
403 error("%s doesn't belong to btrfs mount point", subvol);
408 sctx->mnt_fd = open(sctx->root_path, O_RDONLY | O_NOATIME);
409 if (sctx->mnt_fd < 0) {
411 error("cannot open '%s': %s", sctx->root_path, strerror(-ret));
415 ret = subvol_uuid_search_init(sctx->mnt_fd, &sctx->sus);
417 error("failed to initialize subvol search: %s",
427 static int is_subvol_ro(struct btrfs_send *sctx, const char *subvol)
433 fd = openat(sctx->mnt_fd, subvol, O_RDONLY | O_NOATIME);
436 error("cannot open %s: %s", subvol, strerror(-ret));
440 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
443 error("failed to get flags for subvolume %s: %s",
444 subvol, strerror(-ret));
448 if (flags & BTRFS_SUBVOL_RDONLY)
460 static int set_root_info(struct btrfs_send *sctx, const char *subvol,
465 ret = init_root_path(sctx, subvol);
469 ret = get_root_id(sctx, subvol_strip_mountpoint(sctx->root_path, subvol),
472 error("cannot resolve rootid for %s", subvol);
480 static void free_send_info(struct btrfs_send *sctx)
482 if (sctx->mnt_fd >= 0) {
486 free(sctx->root_path);
487 sctx->root_path = NULL;
488 subvol_uuid_search_finit(&sctx->sus);
491 int cmd_send(int argc, char **argv)
495 char outname[PATH_MAX];
496 struct btrfs_send send;
498 char *mount_root = NULL;
499 char *snapshot_parent = NULL;
501 u64 parent_root_id = 0;
503 int new_end_cmd_semantic = 0;
506 memset(&send, 0, sizeof(send));
507 send.dump_fd = fileno(stdout);
511 enum { GETOPT_VAL_SEND_NO_DATA = 256 };
512 static const struct option long_options[] = {
513 { "verbose", no_argument, NULL, 'v' },
514 { "quiet", no_argument, NULL, 'q' },
515 { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
517 int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);
530 new_end_cmd_semantic = 1;
533 subvol = realpath(optarg, NULL);
536 error("realpath %s failed: %s\n", optarg, strerror(-ret));
540 ret = set_root_info(&send, subvol, &root_id);
544 ret = is_subvol_ro(&send, subvol);
549 error("cloned subvolume %s is not read-only", subvol);
553 ret = add_clone_source(&send, root_id);
555 error("cannot add clone source: %s", strerror(-ret));
560 free_send_info(&send);
564 if (arg_copy_path(outname, optarg, sizeof(outname))) {
565 error("output file path too long (%zu)", strlen(optarg));
571 if (snapshot_parent) {
572 error("you cannot have more than one parent (-p)");
576 snapshot_parent = realpath(optarg, NULL);
577 if (!snapshot_parent) {
579 error("realpath %s failed: %s", optarg, strerror(-ret));
583 ret = is_subvol_ro(&send, snapshot_parent);
588 error("parent subvolume %s is not read-only",
596 error("option -i was removed, use -c instead");
599 case GETOPT_VAL_SEND_NO_DATA:
600 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
604 error("send arguments invalid");
610 if (check_argc_min(argc - optind, 1))
611 usage(cmd_send_usage);
617 * Try to use an existing file first. Even if send runs as
618 * root, it might not have permissions to create file (eg. on a
619 * NFS) but it should still be able to use a pre-created file.
621 tmpfd = open(outname, O_WRONLY | O_TRUNC);
624 tmpfd = open(outname,
625 O_CREAT | O_WRONLY | O_TRUNC, 0600);
627 send.dump_fd = tmpfd;
628 if (send.dump_fd == -1) {
630 error("cannot create '%s': %s", outname, strerror(-ret));
635 if (isatty(send.dump_fd)) {
637 "not dumping send stream into a terminal, redirect it into a file");
642 /* use first send subvol to determine mount_root */
643 subvol = realpath(argv[optind], NULL);
646 error("unable to resolve %s", argv[optind]);
650 ret = init_root_path(&send, subvol);
654 if (snapshot_parent != NULL) {
655 ret = get_root_id(&send,
656 subvol_strip_mountpoint(send.root_path, snapshot_parent),
659 error("could not resolve rootid for %s", snapshot_parent);
663 ret = add_clone_source(&send, parent_root_id);
665 error("cannot add clone source: %s", strerror(-ret));
670 for (i = optind; i < argc; i++) {
672 subvol = realpath(argv[i], NULL);
675 error("unable to resolve %s", argv[i]);
679 ret = find_mount_root(subvol, &mount_root);
681 error("find_mount_root failed on %s: %s", subvol,
686 error("%s does not belong to btrfs mount point",
691 if (strcmp(send.root_path, mount_root) != 0) {
693 error("all subvolumes must be from the same filesystem");
698 ret = is_subvol_ro(&send, subvol);
703 error("subvolume %s is not read-only", subvol);
708 if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1)
710 fprintf(stderr, "Mode NO_FILE_DATA enabled\n");
712 for (i = optind; i < argc; i++) {
720 fprintf(stderr, "At subvol %s\n", subvol);
722 subvol = realpath(subvol, NULL);
725 error("realpath %s failed: %s", argv[i], strerror(-ret));
729 if (!full_send && !snapshot_parent) {
730 ret = set_root_info(&send, subvol, &root_id);
734 ret = find_good_parent(&send, root_id, &parent_root_id);
736 error("parent determination failed for %lld",
742 if (new_end_cmd_semantic) {
743 /* require new kernel */
744 is_first_subvol = (i == optind);
745 is_last_subvol = (i == argc - 1);
747 /* be compatible to old and new kernel */
751 ret = do_send(&send, parent_root_id, is_first_subvol,
752 is_last_subvol, subvol, send_flags);
756 if (!full_send && !snapshot_parent) {
757 /* done with this subvol, so add it to the clone sources */
758 ret = add_clone_source(&send, root_id);
760 error("cannot add clone source: %s", strerror(-ret));
763 free_send_info(&send);
771 free(snapshot_parent);
772 free(send.clone_sources);
773 free_send_info(&send);
777 const char * const cmd_send_usage[] = {
778 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
779 "Send the subvolume(s) to stdout.",
780 "Sends the subvolume(s) specified by <subvol> to stdout.",
781 "<subvol> should be read-only here.",
782 "By default, this will send the whole subvolume. To do an incremental",
783 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
784 "any additional local snapshots, use '-c <clone-src>' (multiple times",
785 "where applicable). You must not specify clone sources unless you",
786 "guarantee that these snapshots are exactly in the same state on both",
787 "sides, the sender and the receiver. It is allowed to omit the",
788 "'-p <parent>' option when '-c <clone-src>' options are given, in",
789 "which case 'btrfs send' will determine a suitable parent among the",
790 "clone sources itself.",
792 "-e If sending multiple subvols at once, use the new",
793 " format and omit the end-cmd between the subvols.",
794 "-p <parent> Send an incremental stream from <parent> to",
796 "-c <clone-src> Use this snapshot as a clone source for an ",
797 " incremental send (multiple allowed)",
798 "-f <outfile> Output is normally written to stdout. To write to",
799 " a file, use this option. An alternative would be to",
801 "--no-data send in NO_FILE_DATA mode, Note: the output stream",
802 " does not contain any file data and thus cannot be used",
803 " to transfer changes. This mode is faster and useful to",
804 " show the differences in metadata.",
805 "-v|--verbose enable verbose output to stderr, each occurrence of",
806 " this option increases verbosity",
807 "-q|--quiet suppress all messages, except errors",