]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/btrfs.c
Merge pull request #2712 from jsoref/spelling
[mirror_lxc.git] / src / lxc / storage / btrfs.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE 1
26 #endif
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <grp.h>
30 #include <libgen.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/ioctl.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/vfs.h>
38 #include <sys/wait.h>
39 #include <unistd.h>
40
41 #include "btrfs.h"
42 #include "config.h"
43 #include "log.h"
44 #include "rsync.h"
45 #include "storage.h"
46 #include "utils.h"
47
48 #ifndef HAVE_STRLCPY
49 #include "include/strlcpy.h"
50 #endif
51
52 #ifndef HAVE_STRLCAT
53 #include "include/strlcat.h"
54 #endif
55
56 lxc_log_define(btrfs, lxc);
57
58 /*
59 * Return the full path of objid under dirid. Let's say dirid is
60 * /lxc/c1/rootfs, and objid is /lxc/c1/rootfs/a/b/c. Then we will
61 * return a/b/c. If instead objid is for /lxc/c1/rootfs/a, we will
62 * simply return a.
63 */
64 char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid, char *name,
65 u16 name_len)
66 {
67 struct btrfs_ioctl_ino_lookup_args args;
68 int ret;
69 size_t len, retlen;
70 char *retpath;
71
72 memset(&args, 0, sizeof(args));
73 args.treeid = dir_id;
74 args.objectid = objid;
75
76 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
77 if (ret) {
78 SYSERROR("Failed to lookup path for %llu %llu %s",
79 (unsigned long long) dir_id,
80 (unsigned long long) objid,
81 name);
82 return NULL;
83 } else
84 INFO("Got path for %llu %llu - %s",
85 (unsigned long long) objid, (unsigned long long) dir_id,
86 name);
87
88 if (args.name[0]) {
89 /*
90 * we're in a subdirectory of ref_tree, the kernel ioctl
91 * puts a / in there for us
92 */
93 len = strlen(args.name) + name_len + 2;
94 retpath = malloc(len);
95 if (!retpath)
96 return NULL;
97
98 (void)strlcpy(retpath, args.name, len);
99 (void)strlcat(retpath, "/", len);
100
101 retlen = strlcat(retpath, name, len);
102 if (retlen >= len) {
103 ERROR("Failed to append name - %s", name);
104 free(retpath);
105 return NULL;
106 }
107 } else {
108 /* we're at the root of ref_tree */
109 len = name_len + 1;
110 retpath = malloc(len);
111 if (!retpath)
112 return NULL;
113
114 *retpath = '\0';
115
116 retlen = strlcat(retpath, name, len);
117 if (retlen >= len) {
118 ERROR("Failed to append name - %s", name);
119 free(retpath);
120 return NULL;
121 }
122 }
123
124 return retpath;
125 }
126
127 int btrfs_list_get_path_rootid(int fd, u64 *treeid)
128 {
129 int ret;
130 struct btrfs_ioctl_ino_lookup_args args;
131
132 memset(&args, 0, sizeof(args));
133 args.objectid = BTRFS_FIRST_FREE_OBJECTID;
134
135 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
136 if (ret < 0) {
137 SYSWARN("Can't perform the search");
138 return ret;
139 }
140
141 *treeid = args.treeid;
142 return 0;
143 }
144
145 bool is_btrfs_fs(const char *path)
146 {
147 int fd, ret;
148 struct btrfs_ioctl_space_args sargs;
149
150 /* Make sure this is a btrfs filesystem. */
151 fd = open(path, O_RDONLY);
152 if (fd < 0)
153 return false;
154
155 sargs.space_slots = 0;
156 sargs.total_spaces = 0;
157 ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, &sargs);
158 close(fd);
159 if (ret < 0)
160 return false;
161
162 return true;
163 }
164
165 /*
166 * Taken from btrfs toolsuite. Test if path is a subvolume.
167 * return 0; path exists but it is not a subvolume
168 * return 1; path exists and it is a subvolume
169 * return < 0; error
170 */
171 int is_btrfs_subvol(const char *path)
172 {
173 struct stat st;
174 struct statfs stfs;
175 int ret;
176
177 ret = stat(path, &st);
178 if (ret < 0)
179 return -errno;
180
181 if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode))
182 return 0;
183
184 ret = statfs(path, &stfs);
185 if (ret < 0)
186 return -errno;
187
188 return stfs.f_type == BTRFS_SUPER_MAGIC;
189 }
190
191 bool btrfs_detect(const char *path)
192 {
193 struct stat st;
194 int ret;
195
196 if (!strncmp(path, "btrfs:", 6))
197 return true;
198
199 if (!is_btrfs_fs(path))
200 return false;
201
202 /* make sure it's a subvolume */
203 ret = stat(path, &st);
204 if (ret < 0)
205 return false;
206
207 if (st.st_ino == 256 && S_ISDIR(st.st_mode))
208 return true;
209
210 return false;
211 }
212
213 int btrfs_mount(struct lxc_storage *bdev)
214 {
215 unsigned long mntflags;
216 char *mntdata;
217 const char *src;
218 int ret;
219
220 if (strcmp(bdev->type, "btrfs"))
221 return -22;
222
223 if (!bdev->src || !bdev->dest)
224 return -22;
225
226 if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
227 free(mntdata);
228 return -22;
229 }
230
231 src = lxc_storage_get_path(bdev->src, "btrfs");
232
233 ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
234 free(mntdata);
235 return ret;
236 }
237
238 int btrfs_umount(struct lxc_storage *bdev)
239 {
240 if (strcmp(bdev->type, "btrfs"))
241 return -22;
242
243 if (!bdev->src || !bdev->dest)
244 return -22;
245
246 return umount(bdev->dest);
247 }
248
249 static int btrfs_subvolume_create(const char *path)
250 {
251 int ret, saved_errno;
252 size_t retlen;
253 struct btrfs_ioctl_vol_args args;
254 char *p, *newfull;
255 int fd = -1;
256
257 newfull = strdup(path);
258 if (!newfull) {
259 errno = ENOMEM;
260 return -ENOMEM;
261 }
262
263 p = strrchr(newfull, '/');
264 if (!p) {
265 free(newfull);
266 errno = EINVAL;
267 return -EINVAL;
268 }
269 *p = '\0';
270
271 fd = open(newfull, O_RDONLY);
272 if (fd < 0) {
273 free(newfull);
274 return -errno;
275 }
276
277 memset(&args, 0, sizeof(args));
278 retlen = strlcpy(args.name, p + 1, BTRFS_SUBVOL_NAME_MAX);
279 if (retlen >= BTRFS_SUBVOL_NAME_MAX) {
280 free(newfull);
281 close(fd);
282 return -E2BIG;
283 }
284
285 ret = ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args);
286 saved_errno = errno;
287
288 close(fd);
289 free(newfull);
290 errno = saved_errno;
291 return ret;
292 }
293
294 int btrfs_same_fs(const char *orig, const char *new)
295 {
296 int fd_orig = -1, fd_new = -1, ret = -1;
297 struct btrfs_ioctl_fs_info_args orig_args, new_args;
298
299 fd_orig = open(orig, O_RDONLY);
300 if (fd_orig < 0) {
301 SYSERROR("Failed to open original rootfs %s", orig);
302 goto out;
303 }
304
305 ret = ioctl(fd_orig, BTRFS_IOC_FS_INFO, &orig_args);
306 if (ret < 0) {
307 SYSERROR("BTRFS_IOC_FS_INFO %s", orig);
308 goto out;
309 }
310
311 fd_new = open(new, O_RDONLY);
312 if (fd_new < 0) {
313 SYSERROR("Failed to open new container dir %s", new);
314 ret = -1;
315 goto out;
316 }
317
318 ret = ioctl(fd_new, BTRFS_IOC_FS_INFO, &new_args);
319 if (ret < 0) {
320 SYSERROR("BTRFS_IOC_FS_INFO %s", new);
321 goto out;
322 }
323
324 if (strncmp(orig_args.fsid, new_args.fsid, BTRFS_FSID_SIZE) != 0) {
325 ret = -1;
326 goto out;
327 }
328
329 ret = 0;
330
331 out:
332 if (fd_new != -1)
333 close(fd_new);
334
335 if (fd_orig != -1)
336 close(fd_orig);
337
338 return ret;
339 }
340
341 int btrfs_snapshot(const char *orig, const char *new)
342 {
343 size_t retlen;
344 struct btrfs_ioctl_vol_args_v2 args;
345 char *newdir, *newname;
346 char *newfull = NULL;
347 int saved_errno = -1;
348 int fd = -1, fddst = -1, ret = -1;
349
350 newfull = strdup(new);
351 if (!newfull)
352 goto out;
353
354 ret = rmdir(newfull);
355 if (ret < 0 && errno != ENOENT)
356 goto out;
357
358 newname = basename(newfull);
359 fd = open(orig, O_RDONLY);
360 if (fd < 0)
361 goto out;
362
363 newdir = dirname(newfull);
364 fddst = open(newdir, O_RDONLY);
365 if (fddst < 0)
366 goto out;
367
368 memset(&args, 0, sizeof(args));
369 args.fd = fd;
370 retlen = strlcpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX);
371 if (retlen >= BTRFS_SUBVOL_NAME_MAX)
372 goto out;
373
374 ret = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
375 saved_errno = errno;
376
377 out:
378 if (fddst != -1)
379 close(fddst);
380
381 if (fd != -1)
382 close(fd);
383
384 free(newfull);
385
386 if (saved_errno >= 0)
387 errno = saved_errno;
388
389 return ret;
390 }
391
392 int btrfs_snapshot_wrapper(void *data)
393 {
394 const char *src;
395 struct rsync_data_char *arg = data;
396
397 if (setgid(0) < 0) {
398 ERROR("Failed to setgid to 0");
399 return -1;
400 }
401
402 if (setgroups(0, NULL) < 0)
403 WARN("Failed to clear groups");
404
405 if (setuid(0) < 0) {
406 ERROR("Failed to setuid to 0");
407 return -1;
408 }
409
410 src = lxc_storage_get_path(arg->src, "btrfs");
411 return btrfs_snapshot(src, arg->dest);
412 }
413
414 int btrfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
415 const char *oldname, const char *cname,
416 const char *oldpath, const char *lxcpath, int snap,
417 uint64_t newsize, struct lxc_conf *conf)
418 {
419 const char *src;
420
421 if (!orig->dest || !orig->src)
422 return -1;
423
424 if (strcmp(orig->type, "btrfs") && snap) {
425 ERROR("btrfs snapshot from %s backing store is not supported",
426 orig->type);
427 return -1;
428 }
429
430 new->src = lxc_string_join(
431 "/",
432 (const char *[]){"btrfs:", *lxcpath != '/' ? lxcpath : ++lxcpath,
433 cname, "rootfs", NULL},
434 false);
435 if (!new->src) {
436 ERROR("Failed to create new rootfs path");
437 return -1;
438 }
439 TRACE("Constructed new rootfs path \"%s\"", new->src);
440
441 src = lxc_storage_get_path(new->src, "btrfs");
442 new->dest = strdup(src);
443 if (!new->dest) {
444 ERROR("Failed to duplicate string \"%s\"", src);
445 return -1;
446 }
447
448 if (orig->mntopts) {
449 new->mntopts = strdup(orig->mntopts);
450 if (!new->mntopts) {
451 ERROR("Failed to duplicate string \"%s\"",
452 orig->mntopts);
453 return -1;
454 }
455 }
456
457 return 0;
458 }
459
460 bool btrfs_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
461 struct lxc_storage *new, uint64_t newsize)
462 {
463 int ret;
464 struct rsync_data data = {0, 0};
465 char cmd_output[PATH_MAX] = {0};
466
467 ret = rmdir(new->dest);
468 if (ret < 0 && errno != ENOENT)
469 return false;
470
471 ret = btrfs_subvolume_create(new->dest);
472 if (ret < 0) {
473 SYSERROR("Failed to create btrfs subvolume \"%s\"", new->dest);
474 return false;
475 }
476
477 /* rsync the contents from source to target */
478 data.orig = orig;
479 data.new = new;
480
481 if (am_guest_unpriv()) {
482 ret = userns_exec_full(conf, lxc_storage_rsync_exec_wrapper,
483 &data, "lxc_storage_rsync_exec_wrapper");
484 if (ret < 0) {
485 ERROR("Failed to rsync from \"%s\" into \"%s\"",
486 orig->dest, new->dest);
487 return false;
488 }
489
490 return true;
491 }
492
493 ret = run_command(cmd_output, sizeof(cmd_output),
494 lxc_storage_rsync_exec_wrapper, (void *)&data);
495 if (ret < 0) {
496 ERROR("Failed to rsync from \"%s\" into \"%s\": %s", orig->dest,
497 new->dest, cmd_output);
498 return false;
499 }
500
501 return true;
502 }
503
504 bool btrfs_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
505 struct lxc_storage *new, uint64_t newsize)
506 {
507 int ret;
508
509 ret = rmdir(new->dest);
510 if (ret < 0 && errno != ENOENT)
511 return false;
512
513 if (am_guest_unpriv()) {
514 struct rsync_data_char args;
515
516 args.src = orig->src;
517 args.dest = new->dest;
518
519 ret = userns_exec_1(conf, btrfs_snapshot_wrapper, &args,
520 "btrfs_snapshot_wrapper");
521 if (ret < 0) {
522 ERROR("Failed to run \"btrfs_snapshot_wrapper\"");
523 return false;
524 }
525
526 TRACE("Created btrfs snapshot \"%s\" from \"%s\"", new->dest,
527 orig->dest);
528 return true;
529 }
530
531 ret = btrfs_snapshot(orig->src, new->dest);
532 if (ret < 0) {
533 SYSERROR("Failed to create btrfs snapshot \"%s\" from \"%s\"",
534 new->dest, orig->dest);
535 return false;
536 }
537
538 TRACE("Created btrfs snapshot \"%s\" from \"%s\"", new->dest, orig->dest);
539 return true;
540 }
541
542 static int btrfs_do_destroy_subvol(const char *path)
543 {
544 int ret, fd = -1;
545 size_t retlen;
546 struct btrfs_ioctl_vol_args args;
547 char *p, *newfull = strdup(path);
548
549 if (!newfull) {
550 ERROR("Out of memory");
551 return -1;
552 }
553
554 p = strrchr(newfull, '/');
555 if (!p) {
556 ERROR("Invalid path: %s", path);
557 free(newfull);
558 return -1;
559 }
560 *p = '\0';
561
562 fd = open(newfull, O_RDONLY);
563 if (fd < 0) {
564 SYSERROR("Failed to open %s", newfull);
565 free(newfull);
566 return -1;
567 }
568
569 memset(&args, 0, sizeof(args));
570 retlen = strlcpy(args.name, p+1, BTRFS_SUBVOL_NAME_MAX);
571 if (retlen >= BTRFS_SUBVOL_NAME_MAX) {
572 free(newfull);
573 close(fd);
574 return -E2BIG;
575 }
576
577 ret = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
578 INFO("IOCTL for destroying snapshot returned %d for %s", ret, path);
579 if (ret < 0 && errno == EPERM)
580 ERROR("Is the rootfs mounted with -o user_subvol_rm_allowed?");
581
582 free(newfull);
583 close(fd);
584 return ret;
585 }
586
587 static int get_btrfs_tree_idx(struct my_btrfs_tree *tree, u64 id)
588 {
589 int i;
590
591 if (!tree)
592 return -1;
593
594 for (i = 0; i < tree->num; i++)
595 if (tree->nodes[i].objid == id)
596 return i;
597
598 return -1;
599 }
600
601 static struct my_btrfs_tree *create_my_btrfs_tree(u64 id, const char *path,
602 int name_len)
603 {
604 struct my_btrfs_tree *tree;
605
606 tree = malloc(sizeof(struct my_btrfs_tree));
607 if (!tree)
608 return NULL;
609
610 tree->nodes = malloc(sizeof(struct mytree_node));
611 if (!tree->nodes) {
612 free(tree);
613 return NULL;
614 }
615
616 tree->num = 1;
617 tree->nodes[0].dirname = NULL;
618 tree->nodes[0].name = strdup(path);
619 if (!tree->nodes[0].name) {
620 free(tree->nodes);
621 free(tree);
622 return NULL;
623 }
624
625 tree->nodes[0].parentid = 0;
626 tree->nodes[0].objid = id;
627 return tree;
628 }
629
630 static bool update_tree_node(struct mytree_node *n, u64 id, u64 parent,
631 char *name, u16 name_len, char *dirname)
632 {
633 if (id)
634 n->objid = id;
635
636 if (parent)
637 n->parentid = parent;
638
639 if (name) {
640 n->name = malloc(name_len + 1);
641 if (!n->name)
642 return false;
643
644 (void)strlcpy(n->name, name, name_len + 1);
645 }
646
647 if (dirname) {
648 size_t len;
649
650 len = strlen(dirname);
651 n->dirname = malloc(len + 1);
652 if (!n->dirname) {
653 free(n->name);
654 return false;
655 }
656
657 (void)strlcpy(n->dirname, dirname, len + 1);
658 }
659
660 return true;
661 }
662
663 static bool add_btrfs_tree_node(struct my_btrfs_tree *tree, u64 id, u64 parent,
664 char *name, u16 name_len, char *dirname)
665 {
666 struct mytree_node *tmp;
667
668 int i = get_btrfs_tree_idx(tree, id);
669 if (i != -1)
670 return update_tree_node(&tree->nodes[i], id, parent, name,
671 name_len, dirname);
672
673 tmp = realloc(tree->nodes, (tree->num+1) * sizeof(struct mytree_node));
674 if (!tmp)
675 return false;
676
677 tree->nodes = tmp;
678 memset(&tree->nodes[tree->num], 0, sizeof(struct mytree_node));
679
680 if (!update_tree_node(&tree->nodes[tree->num], id, parent, name,
681 name_len, dirname))
682 return false;
683
684 tree->num++;
685 return true;
686 }
687
688 static void free_btrfs_tree(struct my_btrfs_tree *tree)
689 {
690 int i;
691
692 if (!tree)
693 return;
694
695 for (i = 0; i < tree->num; i++) {
696 free(tree->nodes[i].name);
697 free(tree->nodes[i].dirname);
698 }
699
700 free(tree->nodes);
701 free(tree);
702 }
703
704 /*
705 * Given a @tree of subvolumes under @path, ask btrfs to remove each
706 * subvolume
707 */
708 static bool do_remove_btrfs_children(struct my_btrfs_tree *tree, u64 root_id,
709 const char *path)
710 {
711 int i, ret;
712 char *newpath;
713 size_t len;
714
715 for (i = 0; i < tree->num; i++) {
716 if (tree->nodes[i].parentid == root_id) {
717 if (!tree->nodes[i].dirname) {
718 WARN("Odd condition: child objid with no name under %s", path);
719 continue;
720 }
721
722 len = strlen(path) + strlen(tree->nodes[i].dirname) + 2;
723 newpath = malloc(len);
724 if (!newpath) {
725 ERROR("Out of memory");
726 return false;
727 }
728
729 ret = snprintf(newpath, len, "%s/%s", path, tree->nodes[i].dirname);
730 if (ret < 0 || ret >= len) {
731 free(newpath);
732 return false;
733 }
734
735 if (!do_remove_btrfs_children(tree, tree->nodes[i].objid, newpath)) {
736 ERROR("Failed to prune %s", tree->nodes[i].name);
737 free(newpath);
738 return false;
739 }
740
741 if (btrfs_do_destroy_subvol(newpath) != 0) {
742 ERROR("Failed to remove %s", newpath);
743 free(newpath);
744 return false;
745 }
746
747 free(newpath);
748 }
749 }
750
751 return true;
752 }
753
754 static int btrfs_recursive_destroy(const char *path)
755 {
756 u64 root_id;
757 int fd;
758 struct btrfs_ioctl_search_args args;
759 struct btrfs_ioctl_search_key *sk = &args.key;
760 struct btrfs_ioctl_search_header sh;
761 struct btrfs_root_ref *ref;
762 struct my_btrfs_tree *tree;
763 int ret, e, i;
764 unsigned long off = 0;
765 u16 name_len;
766 char *name;
767 char *tmppath;
768 u64 dir_id;
769
770 fd = open(path, O_RDONLY);
771 if (fd < 0) {
772 ERROR("Failed to open %s", path);
773 return -1;
774 }
775
776 if (btrfs_list_get_path_rootid(fd, &root_id)) {
777 e = errno;
778 close(fd);
779 if (e == EPERM || e == EACCES) {
780 WARN("Will simply try removing");
781 goto ignore_search;
782 }
783
784 return -1;
785 }
786
787 tree = create_my_btrfs_tree(root_id, path, strlen(path));
788 if (!tree) {
789 ERROR("Out of memory");
790 close(fd);
791 return -1;
792 }
793
794 /* Walk all subvols looking for any under this id */
795 memset(&args, 0, sizeof(args));
796
797 /* search in the tree of tree roots */
798 sk->tree_id = 1;
799 sk->max_type = BTRFS_ROOT_REF_KEY;
800 sk->min_type = BTRFS_ROOT_ITEM_KEY;
801 sk->min_objectid = 0;
802 sk->max_objectid = (u64)-1;
803 sk->max_offset = (u64)-1;
804 sk->min_offset = 0;
805 sk->max_transid = (u64)-1;
806 sk->nr_items = 4096;
807
808 while(1) {
809 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
810 e = errno;
811 if (ret < 0) {
812 close(fd);
813 free_btrfs_tree(tree);
814 if (e == EPERM || e == EACCES) {
815 WARN("Can't perform the search under %s. "
816 "Will simply try removing", path);
817 goto ignore_search;
818 }
819
820 ERROR("Can't perform the search under %s", path);
821 return -1;
822 }
823
824 if (sk->nr_items == 0)
825 break;
826
827 off = 0;
828 for (i = 0; i < sk->nr_items; i++) {
829 memcpy(&sh, args.buf + off, sizeof(sh));
830 off += sizeof(sh);
831
832 /*
833 * A backref key with the name and dirid of the parent
834 * comes followed by the root ref key which has the
835 * name of the child subvol in question.
836 */
837 if (sh.objectid != root_id && sh.type == BTRFS_ROOT_BACKREF_KEY) {
838 ref = (struct btrfs_root_ref *)(args.buf + off);
839 name_len = btrfs_stack_root_ref_name_len(ref);
840 name = (char *)(ref + 1);
841 dir_id = btrfs_stack_root_ref_dirid(ref);
842 tmppath = get_btrfs_subvol_path(fd, sh.offset,
843 dir_id, name, name_len);
844
845 if (!add_btrfs_tree_node(tree, sh.objectid,
846 sh.offset, name,
847 name_len, tmppath)) {
848 ERROR("Out of memory");
849 free_btrfs_tree(tree);
850 free(tmppath);
851 close(fd);
852 return -1;
853 }
854
855 free(tmppath);
856 }
857
858 off += sh.len;
859
860 /*
861 * record the mins in sk so we can make sure the
862 * next search doesn't repeat this root
863 */
864 sk->min_objectid = sh.objectid;
865 sk->min_type = sh.type;
866 sk->min_offset = sh.offset;
867 }
868
869 sk->nr_items = 4096;
870 sk->min_offset++;
871
872 if (!sk->min_offset)
873 sk->min_type++;
874 else
875 continue;
876
877 if (sk->min_type > BTRFS_ROOT_BACKREF_KEY) {
878 sk->min_type = BTRFS_ROOT_ITEM_KEY;
879 sk->min_objectid++;
880 } else {
881 continue;
882 }
883
884 if (sk->min_objectid >= sk->max_objectid)
885 break;
886 }
887
888 close(fd);
889
890 /* now actually remove them */
891 if (!do_remove_btrfs_children(tree, root_id, path)) {
892 free_btrfs_tree(tree);
893 ERROR("Failed to prune");
894 return -1;
895 }
896
897 free_btrfs_tree(tree);
898
899 /* All child subvols have been removed, now remove this one */
900 ignore_search:
901 return btrfs_do_destroy_subvol(path);
902 }
903
904 bool btrfs_try_remove_subvol(const char *path)
905 {
906 if (!btrfs_detect(path))
907 return false;
908
909 return btrfs_recursive_destroy(path) == 0;
910 }
911
912 int btrfs_destroy(struct lxc_storage *orig)
913 {
914 const char *src;
915
916 src = lxc_storage_get_path(orig->src, "btrfs");
917
918 return btrfs_recursive_destroy(src);
919 }
920
921 int btrfs_create(struct lxc_storage *bdev, const char *dest, const char *n,
922 struct bdev_specs *specs)
923 {
924 int ret;
925 size_t len;
926
927
928 len = strlen(dest) + 1;
929 /* strlen("btrfs:") */
930 len += 6;
931
932 bdev->src = malloc(len);
933 if (!bdev->src) {
934 ERROR("Failed to allocate memory");
935 return -1;
936 }
937
938 ret = snprintf(bdev->src, len, "btrfs:%s", dest);
939 if (ret < 0 || (size_t)ret >= len) {
940 ERROR("Failed to create string");
941 return -1;
942 }
943
944 bdev->dest = strdup(dest);
945 if (!bdev->dest) {
946 ERROR("Failed to duplicate string \"%s\"", dest);
947 return -1;
948 }
949
950 ret = btrfs_subvolume_create(bdev->dest);
951 if (ret < 0)
952 SYSERROR("Failed to create btrfs subvolume \"%s\"", bdev->dest);
953
954 return ret;
955 }