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