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