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