btrfs-progs: fix regression preventing send -p with subvolumes mounted on "/"
[btrfs-progs-unstable/devel.git] / cmds-send.c
blobc5ecdaa11999017545c35b3605810b57e509c916
1 /*
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"
22 #include <unistd.h>
23 #include <stdint.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <pthread.h>
27 #include <math.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <libgen.h>
32 #include <mntent.h>
33 #include <assert.h>
34 #include <getopt.h>
35 #include <uuid/uuid.h>
36 #include <limits.h>
38 #include "ctree.h"
39 #include "ioctl.h"
40 #include "commands.h"
41 #include "list.h"
42 #include "utils.h"
44 #include "send.h"
45 #include "send-utils.h"
46 #include "help.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;
56 struct btrfs_send {
57 int send_fd;
58 int dump_fd;
59 int mnt_fd;
61 u64 *clone_sources;
62 u64 clone_sources_count;
64 char *root_path;
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)) {
75 if (!si)
76 return -ENOENT;
77 else
78 return PTR_ERR(si);
80 *root_id = si->root_id;
81 free(si->path);
82 free(si);
83 return 0;
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))
94 return si_tmp;
96 si = subvol_uuid_search(&sctx->sus, 0, si_tmp->parent_uuid, 0, NULL,
97 subvol_search_by_uuid);
98 free(si_tmp->path);
99 free(si_tmp);
100 return si;
103 static int find_good_parent(struct btrfs_send *sctx, u64 root_id, u64 *found)
105 int ret;
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;
110 int i;
112 parent = get_parent(sctx, root_id);
113 if (IS_ERR_OR_NULL(parent)) {
114 if (!parent)
115 ret = -ENOENT;
116 else
117 ret = PTR_ERR(parent);
118 goto out;
121 for (i = 0; i < sctx->clone_sources_count; i++) {
122 if (sctx->clone_sources[i] == parent->root_id) {
123 best_parent = parent;
124 parent = NULL;
125 goto out_found;
129 for (i = 0; i < sctx->clone_sources_count; i++) {
130 s64 tmp;
132 parent2 = get_parent(sctx, sctx->clone_sources[i]);
133 if (IS_ERR_OR_NULL(parent2))
134 continue;
135 if (parent2->root_id != parent->root_id) {
136 free(parent2->path);
137 free(parent2);
138 parent2 = NULL;
139 continue;
142 free(parent2->path);
143 free(parent2);
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)) {
148 if (!parent2)
149 ret = -ENOENT;
150 else
151 ret = PTR_ERR(parent2);
152 goto out;
154 tmp = parent2->ctransid - parent->ctransid;
155 if (tmp < 0)
156 tmp = -tmp;
157 if (tmp < best_diff) {
158 if (best_parent) {
159 free(best_parent->path);
160 free(best_parent);
162 best_parent = parent2;
163 parent2 = NULL;
164 best_diff = tmp;
165 } else {
166 free(parent2->path);
167 free(parent2);
168 parent2 = NULL;
172 if (!best_parent) {
173 ret = -ENOENT;
174 goto out;
177 out_found:
178 *found = best_parent->root_id;
179 ret = 0;
181 out:
182 if (parent) {
183 free(parent->path);
184 free(parent);
186 if (best_parent) {
187 free(best_parent->path);
188 free(best_parent);
190 return ret;
193 static int add_clone_source(struct btrfs_send *sctx, u64 root_id)
195 void *tmp;
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) {
202 free(tmp);
203 return -ENOMEM;
205 sctx->clone_sources[sctx->clone_sources_count++] = root_id;
207 return 0;
210 #if 0
211 static int write_buf(int fd, const char *buf, size_t size)
213 int ret;
214 size_t pos = 0;
216 while (pos < size) {
217 ssize_t wbytes;
219 wbytes = write(fd, buf + pos, size - pos);
220 if (wbytes < 0) {
221 ret = -errno;
222 error("failed to dump stream: %s", strerror(-ret));
223 goto out;
225 if (!wbytes) {
226 ret = -EIO;
227 error("failed to dump stream: %s", strerror(-ret));
228 goto out;
230 pos += wbytes;
232 ret = 0;
234 out:
235 return ret;
238 static void* read_sent_data_copy(void *arg)
240 int ret;
241 struct btrfs_send *sctx = (struct btrfs_send*)arg;
242 char buf[SEND_BUFFER_SIZE];
244 while (1) {
245 ssize_t rbytes;
247 rbytes = read(sctx->send_fd, buf, sizeof(buf));
248 if (rbytes < 0) {
249 ret = -errno;
250 error("failed to read stream from kernel: %s",
251 strerror(-ret));
252 goto out;
254 if (!rbytes) {
255 ret = 0;
256 goto out;
258 ret = write_buf(sctx->dump_fd, buf, rbytes);
259 if (ret < 0)
260 goto out;
263 out:
264 if (ret < 0)
265 exit(-ret);
267 return ERR_PTR(ret);
269 #endif
271 static void *read_sent_data(void *arg)
273 int ret;
274 struct btrfs_send *sctx = (struct btrfs_send*)arg;
276 while (1) {
277 ssize_t sbytes;
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);
282 if (sbytes < 0) {
283 ret = -errno;
284 error("failed to read stream from kernel: %s",
285 strerror(-ret));
286 goto out;
288 if (!sbytes) {
289 ret = 0;
290 goto out;
294 out:
295 if (ret < 0)
296 exit(-ret);
298 return ERR_PTR(ret);
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,
303 u64 flags)
305 int ret;
306 pthread_t t_read;
307 struct btrfs_ioctl_send_args io_send;
308 void *t_err = NULL;
309 int subvol_fd = -1;
310 int pipefd[2] = {-1, -1};
312 subvol_fd = openat(send->mnt_fd, subvol, O_RDONLY | O_NOATIME);
313 if (subvol_fd < 0) {
314 ret = -errno;
315 error("cannot open %s: %s", subvol, strerror(-ret));
316 goto out;
319 ret = pipe(pipefd);
320 if (ret < 0) {
321 ret = -errno;
322 error("pipe failed: %s", strerror(-ret));
323 goto out;
326 memset(&io_send, 0, sizeof(io_send));
327 io_send.send_fd = pipefd[1];
328 send->send_fd = pipefd[0];
330 if (!ret)
331 ret = pthread_create(&t_read, NULL, read_sent_data, send);
332 if (ret) {
333 ret = -ret;
334 error("thread setup failed: %s", strerror(-ret));
335 goto out;
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;
344 if (!is_last_subvol)
345 io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD;
346 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
347 if (ret < 0) {
348 ret = -errno;
349 error("send ioctl failed with %d: %s", ret, strerror(-ret));
350 if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol))
351 fprintf(stderr,
352 "Try upgrading your kernel or don't use -e.\n");
353 goto out;
355 if (g_verbose > 1)
356 fprintf(stderr, "BTRFS_IOC_SEND returned %d\n", ret);
358 if (g_verbose > 1)
359 fprintf(stderr, "joining genl thread\n");
361 close(pipefd[1]);
362 pipefd[1] = -1;
364 ret = pthread_join(t_read, &t_err);
365 if (ret) {
366 ret = -ret;
367 error("pthread_join failed: %s", strerror(-ret));
368 goto out;
370 if (t_err) {
371 ret = (long int)t_err;
372 error("failed to process send stream, ret=%ld (%s)",
373 (long int)t_err, strerror(-ret));
374 goto out;
377 ret = 0;
379 out:
380 if (subvol_fd != -1)
381 close(subvol_fd);
382 if (pipefd[0] != -1)
383 close(pipefd[0]);
384 if (pipefd[1] != -1)
385 close(pipefd[1]);
386 return ret;
389 static int init_root_path(struct btrfs_send *sctx, const char *subvol)
391 int ret = 0;
393 if (sctx->root_path)
394 goto out;
396 ret = find_mount_root(subvol, &sctx->root_path);
397 if (ret < 0) {
398 error("failed to determine mount point for %s: %s",
399 subvol, strerror(-ret));
400 ret = -EINVAL;
401 goto out;
403 if (ret > 0) {
404 error("%s doesn't belong to btrfs mount point", subvol);
405 ret = -EINVAL;
406 goto out;
409 sctx->mnt_fd = open(sctx->root_path, O_RDONLY | O_NOATIME);
410 if (sctx->mnt_fd < 0) {
411 ret = -errno;
412 error("cannot open '%s': %s", sctx->root_path, strerror(-ret));
413 goto out;
416 ret = subvol_uuid_search_init(sctx->mnt_fd, &sctx->sus);
417 if (ret < 0) {
418 error("failed to initialize subvol search: %s",
419 strerror(-ret));
420 goto out;
423 out:
424 return ret;
428 static int is_subvol_ro(struct btrfs_send *sctx, const char *subvol)
430 int ret;
431 u64 flags;
432 int fd = -1;
434 fd = openat(sctx->mnt_fd, subvol, O_RDONLY | O_NOATIME);
435 if (fd < 0) {
436 ret = -errno;
437 error("cannot open %s: %s", subvol, strerror(-ret));
438 goto out;
441 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
442 if (ret < 0) {
443 ret = -errno;
444 error("failed to get flags for subvolume %s: %s",
445 subvol, strerror(-ret));
446 goto out;
449 if (flags & BTRFS_SUBVOL_RDONLY)
450 ret = 1;
451 else
452 ret = 0;
454 out:
455 if (fd != -1)
456 close(fd);
458 return ret;
461 static int set_root_info(struct btrfs_send *sctx, const char *subvol,
462 u64 *root_id)
464 int ret;
466 ret = init_root_path(sctx, subvol);
467 if (ret < 0)
468 goto out;
470 ret = get_root_id(sctx, subvol_strip_mountpoint(sctx->root_path, subvol),
471 root_id);
472 if (ret < 0) {
473 error("cannot resolve rootid for %s", subvol);
474 goto out;
477 out:
478 return ret;
481 static void free_send_info(struct btrfs_send *sctx)
483 if (sctx->mnt_fd >= 0) {
484 close(sctx->mnt_fd);
485 sctx->mnt_fd = -1;
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)
494 char *subvol = NULL;
495 int ret;
496 char outname[PATH_MAX];
497 struct btrfs_send send;
498 u32 i;
499 char *mount_root = NULL;
500 char *snapshot_parent = NULL;
501 u64 root_id = 0;
502 u64 parent_root_id = 0;
503 int full_send = 1;
504 int new_end_cmd_semantic = 0;
505 u64 send_flags = 0;
507 memset(&send, 0, sizeof(send));
508 send.dump_fd = fileno(stdout);
509 outname[0] = 0;
511 while (1) {
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);
520 if (c < 0)
521 break;
523 switch (c) {
524 case 'v':
525 g_verbose++;
526 break;
527 case 'q':
528 g_verbose = 0;
529 break;
530 case 'e':
531 new_end_cmd_semantic = 1;
532 break;
533 case 'c':
534 subvol = realpath(optarg, NULL);
535 if (!subvol) {
536 ret = -errno;
537 error("realpath %s failed: %s\n", optarg, strerror(-ret));
538 goto out;
541 ret = set_root_info(&send, subvol, &root_id);
542 if (ret < 0)
543 goto out;
545 ret = is_subvol_ro(&send, subvol);
546 if (ret < 0)
547 goto out;
548 if (!ret) {
549 ret = -EINVAL;
550 error("cloned subvolume %s is not read-only", subvol);
551 goto out;
554 ret = add_clone_source(&send, root_id);
555 if (ret < 0) {
556 error("cannot add clone source: %s", strerror(-ret));
557 goto out;
559 free(subvol);
560 subvol = NULL;
561 free_send_info(&send);
562 full_send = 0;
563 break;
564 case 'f':
565 if (arg_copy_path(outname, optarg, sizeof(outname))) {
566 error("output file path too long (%zu)", strlen(optarg));
567 ret = 1;
568 goto out;
570 break;
571 case 'p':
572 if (snapshot_parent) {
573 error("you cannot have more than one parent (-p)");
574 ret = 1;
575 goto out;
577 snapshot_parent = realpath(optarg, NULL);
578 if (!snapshot_parent) {
579 ret = -errno;
580 error("realpath %s failed: %s", optarg, strerror(-ret));
581 goto out;
584 ret = is_subvol_ro(&send, snapshot_parent);
585 if (ret < 0)
586 goto out;
587 if (!ret) {
588 ret = -EINVAL;
589 error("parent subvolume %s is not read-only",
590 snapshot_parent);
591 goto out;
594 full_send = 0;
595 break;
596 case 'i':
597 error("option -i was removed, use -c instead");
598 ret = 1;
599 goto out;
600 case GETOPT_VAL_SEND_NO_DATA:
601 send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
602 break;
603 case '?':
604 default:
605 error("send arguments invalid");
606 ret = 1;
607 goto out;
611 if (check_argc_min(argc - optind, 1))
612 usage(cmd_send_usage);
614 if (outname[0]) {
615 int tmpfd;
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);
623 if (tmpfd < 0) {
624 if (errno == ENOENT)
625 tmpfd = open(outname,
626 O_CREAT | O_WRONLY | O_TRUNC, 0600);
628 send.dump_fd = tmpfd;
629 if (send.dump_fd == -1) {
630 ret = -errno;
631 error("cannot create '%s': %s", outname, strerror(-ret));
632 goto out;
636 if (isatty(send.dump_fd)) {
637 error(
638 "not dumping send stream into a terminal, redirect it into a file");
639 ret = 1;
640 goto out;
643 /* use first send subvol to determine mount_root */
644 subvol = realpath(argv[optind], NULL);
645 if (!subvol) {
646 ret = -errno;
647 error("unable to resolve %s", argv[optind]);
648 goto out;
651 ret = init_root_path(&send, subvol);
652 if (ret < 0)
653 goto out;
655 if (snapshot_parent != NULL) {
656 ret = get_root_id(&send,
657 subvol_strip_mountpoint(send.root_path, snapshot_parent),
658 &parent_root_id);
659 if (ret < 0) {
660 error("could not resolve rootid for %s", snapshot_parent);
661 goto out;
664 ret = add_clone_source(&send, parent_root_id);
665 if (ret < 0) {
666 error("cannot add clone source: %s", strerror(-ret));
667 goto out;
671 for (i = optind; i < argc; i++) {
672 free(subvol);
673 subvol = realpath(argv[i], NULL);
674 if (!subvol) {
675 ret = -errno;
676 error("unable to resolve %s", argv[i]);
677 goto out;
680 ret = find_mount_root(subvol, &mount_root);
681 if (ret < 0) {
682 error("find_mount_root failed on %s: %s", subvol,
683 strerror(-ret));
684 goto out;
686 if (ret > 0) {
687 error("%s does not belong to btrfs mount point",
688 subvol);
689 ret = -EINVAL;
690 goto out;
692 if (strcmp(send.root_path, mount_root) != 0) {
693 ret = -EINVAL;
694 error("all subvolumes must be from the same filesystem");
695 goto out;
697 free(mount_root);
699 ret = is_subvol_ro(&send, subvol);
700 if (ret < 0)
701 goto out;
702 if (!ret) {
703 ret = -EINVAL;
704 error("subvolume %s is not read-only", subvol);
705 goto out;
709 if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && g_verbose > 1)
710 if (g_verbose > 1)
711 fprintf(stderr, "Mode NO_FILE_DATA enabled\n");
713 for (i = optind; i < argc; i++) {
714 int is_first_subvol;
715 int is_last_subvol;
717 free(subvol);
718 subvol = argv[i];
720 if (g_verbose > 0)
721 fprintf(stderr, "At subvol %s\n", subvol);
723 subvol = realpath(subvol, NULL);
724 if (!subvol) {
725 ret = -errno;
726 error("realpath %s failed: %s", argv[i], strerror(-ret));
727 goto out;
730 if (!full_send && !snapshot_parent) {
731 ret = set_root_info(&send, subvol, &root_id);
732 if (ret < 0)
733 goto out;
735 ret = find_good_parent(&send, root_id, &parent_root_id);
736 if (ret < 0) {
737 error("parent determination failed for %lld",
738 root_id);
739 goto out;
743 if (new_end_cmd_semantic) {
744 /* require new kernel */
745 is_first_subvol = (i == optind);
746 is_last_subvol = (i == argc - 1);
747 } else {
748 /* be compatible to old and new kernel */
749 is_first_subvol = 1;
750 is_last_subvol = 1;
752 ret = do_send(&send, parent_root_id, is_first_subvol,
753 is_last_subvol, subvol, send_flags);
754 if (ret < 0)
755 goto out;
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);
760 if (ret < 0) {
761 error("cannot add clone source: %s", strerror(-ret));
762 goto out;
764 free_send_info(&send);
768 ret = 0;
770 out:
771 free(subvol);
772 free(snapshot_parent);
773 free(send.clone_sources);
774 free_send_info(&send);
775 return !!ret;
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.",
792 "\n",
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",
796 " <subvol>.",
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",
801 " use pipes.",
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",
809 NULL