]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
bdev: be smarter about btrfs subvolume detection 1125/head
authorChristian Brauner <cbrauner@suse.de>
Fri, 12 Aug 2016 19:07:34 +0000 (21:07 +0200)
committerChristian Brauner <cbrauner@suse.de>
Fri, 12 Aug 2016 22:40:17 +0000 (00:40 +0200)
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 <cbrauner@suse.de>
src/lxc/bdev/lxcbtrfs.c
src/lxc/bdev/lxcbtrfs.h
src/lxc/lxccontainer.c

index 5ee6dd3401db8eb1b31fd1d28f55c4c9e4c6ad50..7879d718b62535a36be106dabf05feb9c3c917bb 100644 (file)
@@ -33,6 +33,7 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/vfs.h>
 
 #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;
index 3b2742fa8ee615f83e468ae45963643f55abe48a..ebd8421e18e555e38cf99eb7381092b3d6aa6c2f 100644 (file)
 #include <stdint.h>
 #include <byteswap.h>
 
+#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);
index ae0286fdd99546b25ea357a4257959d6dc7d4e7f..57219776b5c8f6da23e871e0d83c502376d8df44 100644 (file)
@@ -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;
 }