From 6e0fa6a0c65eda9c6586baebbfdfc82cc7c7ebe6 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 12 Aug 2016 21:07:34 +0200 Subject: [PATCH] bdev: be smarter about btrfs subvolume detection When a container c is on a btrfs filesystem but is directory backed, copying the container will default to snapshot. This is because of should_default_to_snapshot() returning true in this case because c is on a btrfs filesystem. We should make sure that should_default_to_snapshot() only returns true, when c itself is a btrfs subvolume. Signed-off-by: Christian Brauner --- src/lxc/bdev/lxcbtrfs.c | 27 +++++++++++++++++++++++++++ src/lxc/bdev/lxcbtrfs.h | 5 +++++ src/lxc/lxccontainer.c | 4 ++++ 3 files changed, 36 insertions(+) diff --git a/src/lxc/bdev/lxcbtrfs.c b/src/lxc/bdev/lxcbtrfs.c index 5ee6dd340..7879d718b 100644 --- a/src/lxc/bdev/lxcbtrfs.c +++ b/src/lxc/bdev/lxcbtrfs.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "bdev.h" #include "log.h" @@ -142,6 +143,32 @@ bool is_btrfs_fs(const char *path) return true; } +/* + * Taken from btrfs toolsuite. Test if path is a subvolume. + * return 0; path exists but it is not a subvolume + * return 1; path exists and it is a subvolume + * return < 0; error + */ +int is_btrfs_subvol(const char *path) +{ + struct stat st; + struct statfs stfs; + int ret; + + ret = stat(path, &st); + if (ret < 0) + return -errno; + + if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode)) + return 0; + + ret = statfs(path, &stfs); + if (ret < 0) + return -errno; + + return stfs.f_type == BTRFS_SUPER_MAGIC; +} + int btrfs_detect(const char *path) { struct stat st; diff --git a/src/lxc/bdev/lxcbtrfs.h b/src/lxc/bdev/lxcbtrfs.h index 3b2742fa8..ebd8421e1 100644 --- a/src/lxc/bdev/lxcbtrfs.h +++ b/src/lxc/bdev/lxcbtrfs.h @@ -30,6 +30,10 @@ #include #include +#ifndef BTRFS_SUPER_MAGIC +# define BTRFS_SUPER_MAGIC 0x9123683E +#endif + typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; @@ -404,6 +408,7 @@ char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid, char *name, int name_len); int btrfs_list_get_path_rootid(int fd, u64 *treeid); bool is_btrfs_fs(const char *path); +int is_btrfs_subvol(const char *path); bool btrfs_try_remove_subvol(const char *path); int btrfs_same_fs(const char *orig, const char *new); int btrfs_snapshot(const char *orig, const char *new); diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index ae0286fdd..57219776b 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -2826,6 +2826,7 @@ bool should_default_to_snapshot(struct lxc_container *c0, size_t l1 = strlen(c1->config_path) + strlen(c1->name) + 2; char *p0 = alloca(l0 + 1); char *p1 = alloca(l1 + 1); + char *rootfs = c0->lxc_conf->rootfs.path; snprintf(p0, l0, "%s/%s", c0->config_path, c0->name); snprintf(p1, l1, "%s/%s", c1->config_path, c1->name); @@ -2833,6 +2834,9 @@ bool should_default_to_snapshot(struct lxc_container *c0, if (!is_btrfs_fs(p0) || !is_btrfs_fs(p1)) return false; + if (is_btrfs_subvol(rootfs) <= 0) + return false; + return btrfs_same_fs(p0, p1) == 0; } -- 2.47.2