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