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