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
);
513 enum { GETOPT_VAL_SEND_NO_DATA
= 256 };
514 static const struct option long_options
[] = {
515 { "verbose", no_argument
, NULL
, 'v' },
516 { "quiet", no_argument
, NULL
, 'q' },
517 { "no-data", no_argument
, NULL
, GETOPT_VAL_SEND_NO_DATA
}
519 int c
= getopt_long(argc
, argv
, "vqec:f:i:p:", long_options
, NULL
);
532 new_end_cmd_semantic
= 1;
535 subvol
= realpath(optarg
, NULL
);
538 error("realpath %s failed: %s\n", optarg
, strerror(-ret
));
542 ret
= set_root_info(&send
, subvol
, &root_id
);
546 ret
= is_subvol_ro(&send
, subvol
);
551 error("cloned subvolume %s is not read-only", subvol
);
555 ret
= add_clone_source(&send
, root_id
);
557 error("cannot add clone source: %s", strerror(-ret
));
562 free_send_info(&send
);
566 if (arg_copy_path(outname
, optarg
, sizeof(outname
))) {
567 error("output file path too long (%zu)", strlen(optarg
));
573 if (snapshot_parent
) {
574 error("you cannot have more than one parent (-p)");
578 snapshot_parent
= realpath(optarg
, NULL
);
579 if (!snapshot_parent
) {
581 error("realpath %s failed: %s", optarg
, strerror(-ret
));
585 ret
= is_subvol_ro(&send
, snapshot_parent
);
590 error("parent subvolume %s is not read-only",
598 error("option -i was removed, use -c instead");
601 case GETOPT_VAL_SEND_NO_DATA
:
602 send_flags
|= BTRFS_SEND_FLAG_NO_FILE_DATA
;
606 error("send arguments invalid");
612 if (check_argc_min(argc
- optind
, 1))
613 usage(cmd_send_usage
);
619 * Try to use an existing file first. Even if send runs as
620 * root, it might not have permissions to create file (eg. on a
621 * NFS) but it should still be able to use a pre-created file.
623 tmpfd
= open(outname
, O_WRONLY
| O_TRUNC
);
626 tmpfd
= open(outname
,
627 O_CREAT
| O_WRONLY
| O_TRUNC
, 0600);
629 send
.dump_fd
= tmpfd
;
630 if (send
.dump_fd
== -1) {
632 error("cannot create '%s': %s", outname
, strerror(-ret
));
637 if (isatty(send
.dump_fd
)) {
639 "not dumping send stream into a terminal, redirect it into a file");
644 /* use first send subvol to determine mount_root */
645 subvol
= realpath(argv
[optind
], NULL
);
648 error("unable to resolve %s", argv
[optind
]);
652 ret
= init_root_path(&send
, subvol
);
656 if (snapshot_parent
!= NULL
) {
657 ret
= get_root_id(&send
,
658 subvol_strip_mountpoint(send
.root_path
, snapshot_parent
),
661 error("could not resolve rootid for %s", snapshot_parent
);
665 ret
= add_clone_source(&send
, parent_root_id
);
667 error("cannot add clone source: %s", strerror(-ret
));
672 for (i
= optind
; i
< argc
; i
++) {
674 subvol
= realpath(argv
[i
], NULL
);
677 error("unable to resolve %s", argv
[i
]);
681 ret
= find_mount_root(subvol
, &mount_root
);
683 error("find_mount_root failed on %s: %s", subvol
,
688 error("%s does not belong to btrfs mount point",
693 if (strcmp(send
.root_path
, mount_root
) != 0) {
695 error("all subvolumes must be from the same filesystem");
700 ret
= is_subvol_ro(&send
, subvol
);
705 error("subvolume %s is not read-only", subvol
);
710 if ((send_flags
& BTRFS_SEND_FLAG_NO_FILE_DATA
) && g_verbose
> 1)
712 fprintf(stderr
, "Mode NO_FILE_DATA enabled\n");
714 for (i
= optind
; i
< argc
; i
++) {
722 fprintf(stderr
, "At subvol %s\n", subvol
);
724 subvol
= realpath(subvol
, NULL
);
727 error("realpath %s failed: %s", argv
[i
], strerror(-ret
));
731 if (!full_send
&& !snapshot_parent
) {
732 ret
= set_root_info(&send
, subvol
, &root_id
);
736 ret
= find_good_parent(&send
, root_id
, &parent_root_id
);
738 error("parent determination failed for %lld",
744 if (new_end_cmd_semantic
) {
745 /* require new kernel */
746 is_first_subvol
= (i
== optind
);
747 is_last_subvol
= (i
== argc
- 1);
749 /* be compatible to old and new kernel */
753 ret
= do_send(&send
, parent_root_id
, is_first_subvol
,
754 is_last_subvol
, subvol
, send_flags
);
758 if (!full_send
&& !snapshot_parent
) {
759 /* done with this subvol, so add it to the clone sources */
760 ret
= add_clone_source(&send
, root_id
);
762 error("cannot add clone source: %s", strerror(-ret
));
765 free_send_info(&send
);
773 free(snapshot_parent
);
774 free(send
.clone_sources
);
775 free_send_info(&send
);
779 const char * const cmd_send_usage
[] = {
780 "btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
781 "Send the subvolume(s) to stdout.",
782 "Sends the subvolume(s) specified by <subvol> to stdout.",
783 "<subvol> should be read-only here.",
784 "By default, this will send the whole subvolume. To do an incremental",
785 "send, use '-p <parent>'. If you want to allow btrfs to clone from",
786 "any additional local snapshots, use '-c <clone-src>' (multiple times",
787 "where applicable). You must not specify clone sources unless you",
788 "guarantee that these snapshots are exactly in the same state on both",
789 "sides, the sender and the receiver. It is allowed to omit the",
790 "'-p <parent>' option when '-c <clone-src>' options are given, in",
791 "which case 'btrfs send' will determine a suitable parent among the",
792 "clone sources itself.",
794 "-e If sending multiple subvols at once, use the new",
795 " format and omit the end-cmd between the subvols.",
796 "-p <parent> Send an incremental stream from <parent> to",
798 "-c <clone-src> Use this snapshot as a clone source for an ",
799 " incremental send (multiple allowed)",
800 "-f <outfile> Output is normally written to stdout. To write to",
801 " a file, use this option. An alternative would be to",
803 "--no-data send in NO_FILE_DATA mode, Note: the output stream",
804 " does not contain any file data and thus cannot be used",
805 " to transfer changes. This mode is faster and useful to",
806 " show the differences in metadata.",
807 "-v|--verbose enable verbose output to stderr, each occurrence of",
808 " this option increases verbosity",
809 "-q|--quiet suppress all messages, except errors",