2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Daniel Lezcano <daniel.lezcano at free.fr>
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.
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.
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
34 #include <sys/ioctl.h>
36 #include <sys/types.h>
49 #include "include/strlcpy.h"
53 #include "include/strlcat.h"
56 lxc_log_define(btrfs
, lxc
);
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
64 char *get_btrfs_subvol_path(int fd
, u64 dir_id
, u64 objid
, char *name
,
67 struct btrfs_ioctl_ino_lookup_args args
;
72 memset(&args
, 0, sizeof(args
));
74 args
.objectid
= objid
;
76 ret
= ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
);
78 SYSERROR("Failed to lookup path for %llu %llu %s",
79 (unsigned long long) dir_id
,
80 (unsigned long long) objid
,
84 INFO("Got path for %llu %llu - %s",
85 (unsigned long long) objid
, (unsigned long long) dir_id
,
90 * we're in a subdirectory of ref_tree, the kernel ioctl
91 * puts a / in there for us
93 len
= strlen(args
.name
) + name_len
+ 2;
94 retpath
= malloc(len
);
98 (void)strlcpy(retpath
, args
.name
, len
);
99 (void)strlcat(retpath
, "/", len
);
101 retlen
= strlcat(retpath
, name
, len
);
103 ERROR("Failed to append name - %s", name
);
108 /* we're at the root of ref_tree */
110 retpath
= malloc(len
);
116 retlen
= strlcat(retpath
, name
, len
);
118 ERROR("Failed to append name - %s", name
);
127 int btrfs_list_get_path_rootid(int fd
, u64
*treeid
)
130 struct btrfs_ioctl_ino_lookup_args args
;
132 memset(&args
, 0, sizeof(args
));
133 args
.objectid
= BTRFS_FIRST_FREE_OBJECTID
;
135 ret
= ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
);
137 SYSWARN("Can't perform the search");
141 *treeid
= args
.treeid
;
145 bool is_btrfs_fs(const char *path
)
148 struct btrfs_ioctl_space_args sargs
;
150 /* Make sure this is a btrfs filesystem. */
151 fd
= open(path
, O_RDONLY
);
155 sargs
.space_slots
= 0;
156 sargs
.total_spaces
= 0;
157 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, &sargs
);
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
171 int is_btrfs_subvol(const char *path
)
177 ret
= stat(path
, &st
);
181 if (st
.st_ino
!= BTRFS_FIRST_FREE_OBJECTID
|| !S_ISDIR(st
.st_mode
))
184 ret
= statfs(path
, &stfs
);
188 return stfs
.f_type
== BTRFS_SUPER_MAGIC
;
191 bool btrfs_detect(const char *path
)
196 if (!strncmp(path
, "btrfs:", 6))
199 if (!is_btrfs_fs(path
))
202 /* make sure it's a subvolume */
203 ret
= stat(path
, &st
);
207 if (st
.st_ino
== 256 && S_ISDIR(st
.st_mode
))
213 int btrfs_mount(struct lxc_storage
*bdev
)
215 unsigned long mntflags
;
220 if (strcmp(bdev
->type
, "btrfs"))
223 if (!bdev
->src
|| !bdev
->dest
)
226 if (parse_mntopts(bdev
->mntopts
, &mntflags
, &mntdata
) < 0) {
231 src
= lxc_storage_get_path(bdev
->src
, "btrfs");
233 ret
= mount(src
, bdev
->dest
, "bind", MS_BIND
| MS_REC
| mntflags
, mntdata
);
238 int btrfs_umount(struct lxc_storage
*bdev
)
240 if (strcmp(bdev
->type
, "btrfs"))
243 if (!bdev
->src
|| !bdev
->dest
)
246 return umount(bdev
->dest
);
249 static int btrfs_subvolume_create(const char *path
)
251 int ret
, saved_errno
;
253 struct btrfs_ioctl_vol_args args
;
257 newfull
= strdup(path
);
263 p
= strrchr(newfull
, '/');
271 fd
= open(newfull
, O_RDONLY
);
277 memset(&args
, 0, sizeof(args
));
278 retlen
= strlcpy(args
.name
, p
+ 1, BTRFS_SUBVOL_NAME_MAX
);
279 if (retlen
>= BTRFS_SUBVOL_NAME_MAX
) {
285 ret
= ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
);
294 int btrfs_same_fs(const char *orig
, const char *new)
296 int fd_orig
= -1, fd_new
= -1, ret
= -1;
297 struct btrfs_ioctl_fs_info_args orig_args
, new_args
;
299 fd_orig
= open(orig
, O_RDONLY
);
301 SYSERROR("Failed to open original rootfs %s", orig
);
305 ret
= ioctl(fd_orig
, BTRFS_IOC_FS_INFO
, &orig_args
);
307 SYSERROR("BTRFS_IOC_FS_INFO %s", orig
);
311 fd_new
= open(new, O_RDONLY
);
313 SYSERROR("Failed to open new container dir %s", new);
318 ret
= ioctl(fd_new
, BTRFS_IOC_FS_INFO
, &new_args
);
320 SYSERROR("BTRFS_IOC_FS_INFO %s", new);
324 if (strncmp(orig_args
.fsid
, new_args
.fsid
, BTRFS_FSID_SIZE
) != 0) {
341 int btrfs_snapshot(const char *orig
, const char *new)
344 struct btrfs_ioctl_vol_args_v2 args
;
345 char *newdir
, *newname
;
346 char *newfull
= NULL
;
347 int saved_errno
= -1;
348 int fd
= -1, fddst
= -1, ret
= -1;
350 newfull
= strdup(new);
354 ret
= rmdir(newfull
);
355 if (ret
< 0 && errno
!= ENOENT
)
358 newname
= basename(newfull
);
359 fd
= open(orig
, O_RDONLY
);
363 newdir
= dirname(newfull
);
364 fddst
= open(newdir
, O_RDONLY
);
368 memset(&args
, 0, sizeof(args
));
370 retlen
= strlcpy(args
.name
, newname
, BTRFS_SUBVOL_NAME_MAX
);
371 if (retlen
>= BTRFS_SUBVOL_NAME_MAX
)
374 ret
= ioctl(fddst
, BTRFS_IOC_SNAP_CREATE_V2
, &args
);
386 if (saved_errno
>= 0)
392 int btrfs_snapshot_wrapper(void *data
)
395 struct rsync_data_char
*arg
= data
;
398 ERROR("Failed to setgid to 0");
402 if (setgroups(0, NULL
) < 0)
403 WARN("Failed to clear groups");
406 ERROR("Failed to setuid to 0");
410 src
= lxc_storage_get_path(arg
->src
, "btrfs");
411 return btrfs_snapshot(src
, arg
->dest
);
414 int btrfs_clonepaths(struct lxc_storage
*orig
, struct lxc_storage
*new,
415 const char *oldname
, const char *cname
,
416 const char *oldpath
, const char *lxcpath
, int snap
,
417 uint64_t newsize
, struct lxc_conf
*conf
)
421 if (!orig
->dest
|| !orig
->src
)
424 if (strcmp(orig
->type
, "btrfs") && snap
) {
425 ERROR("btrfs snapshot from %s backing store is not supported",
430 new->src
= lxc_string_join(
432 (const char *[]){"btrfs:", *lxcpath
!= '/' ? lxcpath
: ++lxcpath
,
433 cname
, "rootfs", NULL
},
436 ERROR("Failed to create new rootfs path");
439 TRACE("Constructed new rootfs path \"%s\"", new->src
);
441 src
= lxc_storage_get_path(new->src
, "btrfs");
442 new->dest
= strdup(src
);
444 ERROR("Failed to duplicate string \"%s\"", src
);
449 new->mntopts
= strdup(orig
->mntopts
);
451 ERROR("Failed to duplicate string \"%s\"",
460 bool btrfs_create_clone(struct lxc_conf
*conf
, struct lxc_storage
*orig
,
461 struct lxc_storage
*new, uint64_t newsize
)
464 struct rsync_data data
= {0, 0};
465 char cmd_output
[PATH_MAX
] = {0};
467 ret
= rmdir(new->dest
);
468 if (ret
< 0 && errno
!= ENOENT
)
471 ret
= btrfs_subvolume_create(new->dest
);
473 SYSERROR("Failed to create btrfs subvolume \"%s\"", new->dest
);
477 /* rsync the contents from source to target */
481 if (am_guest_unpriv()) {
482 ret
= userns_exec_full(conf
, lxc_storage_rsync_exec_wrapper
,
483 &data
, "lxc_storage_rsync_exec_wrapper");
485 ERROR("Failed to rsync from \"%s\" into \"%s\"",
486 orig
->dest
, new->dest
);
493 ret
= run_command(cmd_output
, sizeof(cmd_output
),
494 lxc_storage_rsync_exec_wrapper
, (void *)&data
);
496 ERROR("Failed to rsync from \"%s\" into \"%s\": %s", orig
->dest
,
497 new->dest
, cmd_output
);
504 bool btrfs_create_snapshot(struct lxc_conf
*conf
, struct lxc_storage
*orig
,
505 struct lxc_storage
*new, uint64_t newsize
)
509 ret
= rmdir(new->dest
);
510 if (ret
< 0 && errno
!= ENOENT
)
513 if (am_guest_unpriv()) {
514 struct rsync_data_char args
;
516 args
.src
= orig
->src
;
517 args
.dest
= new->dest
;
519 ret
= userns_exec_1(conf
, btrfs_snapshot_wrapper
, &args
,
520 "btrfs_snapshot_wrapper");
522 ERROR("Failed to run \"btrfs_snapshot_wrapper\"");
526 TRACE("Created btrfs snapshot \"%s\" from \"%s\"", new->dest
,
531 ret
= btrfs_snapshot(orig
->src
, new->dest
);
533 SYSERROR("Failed to create btrfs snapshot \"%s\" from \"%s\"",
534 new->dest
, orig
->dest
);
538 TRACE("Created btrfs snapshot \"%s\" from \"%s\"", new->dest
, orig
->dest
);
542 static int btrfs_do_destroy_subvol(const char *path
)
546 struct btrfs_ioctl_vol_args args
;
547 char *p
, *newfull
= strdup(path
);
550 ERROR("Out of memory");
554 p
= strrchr(newfull
, '/');
556 ERROR("Invalid path: %s", path
);
562 fd
= open(newfull
, O_RDONLY
);
564 SYSERROR("Failed to open %s", newfull
);
569 memset(&args
, 0, sizeof(args
));
570 retlen
= strlcpy(args
.name
, p
+1, BTRFS_SUBVOL_NAME_MAX
);
571 if (retlen
>= BTRFS_SUBVOL_NAME_MAX
) {
577 ret
= ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &args
);
578 INFO("IOCTL for destroying snapshot returned %d for %s", ret
, path
);
579 if (ret
< 0 && errno
== EPERM
)
580 ERROR("Is the rootfs mounted with -o user_subvol_rm_allowed?");
587 static int get_btrfs_tree_idx(struct my_btrfs_tree
*tree
, u64 id
)
594 for (i
= 0; i
< tree
->num
; i
++)
595 if (tree
->nodes
[i
].objid
== id
)
601 static struct my_btrfs_tree
*create_my_btrfs_tree(u64 id
, const char *path
,
604 struct my_btrfs_tree
*tree
;
606 tree
= malloc(sizeof(struct my_btrfs_tree
));
610 tree
->nodes
= malloc(sizeof(struct mytree_node
));
617 tree
->nodes
[0].dirname
= NULL
;
618 tree
->nodes
[0].name
= strdup(path
);
619 if (!tree
->nodes
[0].name
) {
625 tree
->nodes
[0].parentid
= 0;
626 tree
->nodes
[0].objid
= id
;
630 static bool update_tree_node(struct mytree_node
*n
, u64 id
, u64 parent
,
631 char *name
, u16 name_len
, char *dirname
)
637 n
->parentid
= parent
;
640 n
->name
= malloc(name_len
+ 1);
644 (void)strlcpy(n
->name
, name
, name_len
+ 1);
650 len
= strlen(dirname
);
651 n
->dirname
= malloc(len
+ 1);
657 (void)strlcpy(n
->dirname
, dirname
, len
+ 1);
663 static bool add_btrfs_tree_node(struct my_btrfs_tree
*tree
, u64 id
, u64 parent
,
664 char *name
, u16 name_len
, char *dirname
)
666 struct mytree_node
*tmp
;
668 int i
= get_btrfs_tree_idx(tree
, id
);
670 return update_tree_node(&tree
->nodes
[i
], id
, parent
, name
,
673 tmp
= realloc(tree
->nodes
, (tree
->num
+1) * sizeof(struct mytree_node
));
678 memset(&tree
->nodes
[tree
->num
], 0, sizeof(struct mytree_node
));
680 if (!update_tree_node(&tree
->nodes
[tree
->num
], id
, parent
, name
,
688 static void free_btrfs_tree(struct my_btrfs_tree
*tree
)
695 for (i
= 0; i
< tree
->num
; i
++) {
696 free(tree
->nodes
[i
].name
);
697 free(tree
->nodes
[i
].dirname
);
705 * Given a @tree of subvolumes under @path, ask btrfs to remove each
708 static bool do_remove_btrfs_children(struct my_btrfs_tree
*tree
, u64 root_id
,
715 for (i
= 0; i
< tree
->num
; i
++) {
716 if (tree
->nodes
[i
].parentid
== root_id
) {
717 if (!tree
->nodes
[i
].dirname
) {
718 WARN("Odd condition: child objid with no name under %s", path
);
722 len
= strlen(path
) + strlen(tree
->nodes
[i
].dirname
) + 2;
723 newpath
= malloc(len
);
725 ERROR("Out of memory");
729 ret
= snprintf(newpath
, len
, "%s/%s", path
, tree
->nodes
[i
].dirname
);
730 if (ret
< 0 || ret
>= len
) {
735 if (!do_remove_btrfs_children(tree
, tree
->nodes
[i
].objid
, newpath
)) {
736 ERROR("Failed to prune %s", tree
->nodes
[i
].name
);
741 if (btrfs_do_destroy_subvol(newpath
) != 0) {
742 ERROR("Failed to remove %s", newpath
);
754 static int btrfs_recursive_destroy(const char *path
)
758 struct btrfs_ioctl_search_args args
;
759 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
760 struct btrfs_ioctl_search_header sh
;
761 struct btrfs_root_ref
*ref
;
762 struct my_btrfs_tree
*tree
;
764 unsigned long off
= 0;
770 fd
= open(path
, O_RDONLY
);
772 ERROR("Failed to open %s", path
);
776 if (btrfs_list_get_path_rootid(fd
, &root_id
)) {
779 if (e
== EPERM
|| e
== EACCES
) {
780 WARN("Will simply try removing");
787 tree
= create_my_btrfs_tree(root_id
, path
, strlen(path
));
789 ERROR("Out of memory");
794 /* Walk all subvols looking for any under this id */
795 memset(&args
, 0, sizeof(args
));
797 /* search in the tree of tree roots */
799 sk
->max_type
= BTRFS_ROOT_REF_KEY
;
800 sk
->min_type
= BTRFS_ROOT_ITEM_KEY
;
801 sk
->min_objectid
= 0;
802 sk
->max_objectid
= (u64
)-1;
803 sk
->max_offset
= (u64
)-1;
805 sk
->max_transid
= (u64
)-1;
809 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
813 free_btrfs_tree(tree
);
814 if (e
== EPERM
|| e
== EACCES
) {
815 WARN("Can't perform the search under %s. "
816 "Will simply try removing", path
);
820 ERROR("Can't perform the search under %s", path
);
824 if (sk
->nr_items
== 0)
828 for (i
= 0; i
< sk
->nr_items
; i
++) {
829 memcpy(&sh
, args
.buf
+ off
, sizeof(sh
));
833 * A backref key with the name and dirid of the parent
834 * comes followed by the root ref key which has the
835 * name of the child subvol in question.
837 if (sh
.objectid
!= root_id
&& sh
.type
== BTRFS_ROOT_BACKREF_KEY
) {
838 ref
= (struct btrfs_root_ref
*)(args
.buf
+ off
);
839 name_len
= btrfs_stack_root_ref_name_len(ref
);
840 name
= (char *)(ref
+ 1);
841 dir_id
= btrfs_stack_root_ref_dirid(ref
);
842 tmppath
= get_btrfs_subvol_path(fd
, sh
.offset
,
843 dir_id
, name
, name_len
);
845 if (!add_btrfs_tree_node(tree
, sh
.objectid
,
847 name_len
, tmppath
)) {
848 ERROR("Out of memory");
849 free_btrfs_tree(tree
);
861 * record the mins in sk so we can make sure the
862 * next search doesn't repeat this root
864 sk
->min_objectid
= sh
.objectid
;
865 sk
->min_type
= sh
.type
;
866 sk
->min_offset
= sh
.offset
;
877 if (sk
->min_type
> BTRFS_ROOT_BACKREF_KEY
) {
878 sk
->min_type
= BTRFS_ROOT_ITEM_KEY
;
884 if (sk
->min_objectid
>= sk
->max_objectid
)
890 /* now actually remove them */
891 if (!do_remove_btrfs_children(tree
, root_id
, path
)) {
892 free_btrfs_tree(tree
);
893 ERROR("Failed to prune");
897 free_btrfs_tree(tree
);
899 /* All child subvols have been removed, now remove this one */
901 return btrfs_do_destroy_subvol(path
);
904 bool btrfs_try_remove_subvol(const char *path
)
906 if (!btrfs_detect(path
))
909 return btrfs_recursive_destroy(path
) == 0;
912 int btrfs_destroy(struct lxc_storage
*orig
)
916 src
= lxc_storage_get_path(orig
->src
, "btrfs");
918 return btrfs_recursive_destroy(src
);
921 int btrfs_create(struct lxc_storage
*bdev
, const char *dest
, const char *n
,
922 struct bdev_specs
*specs
)
928 len
= strlen(dest
) + 1;
929 /* strlen("btrfs:") */
932 bdev
->src
= malloc(len
);
934 ERROR("Failed to allocate memory");
938 ret
= snprintf(bdev
->src
, len
, "btrfs:%s", dest
);
939 if (ret
< 0 || (size_t)ret
>= len
) {
940 ERROR("Failed to create string");
944 bdev
->dest
= strdup(dest
);
946 ERROR("Failed to duplicate string \"%s\"", dest
);
950 ret
= btrfs_subvolume_create(bdev
->dest
);
952 SYSERROR("Failed to create btrfs subvolume \"%s\"", bdev
->dest
);