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