Commit 014c8714 by Christian Brauner Committed by Stéphane Graber

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: 's avatarChristian Brauner <cbrauner@suse.de>
parent 9b9e2d5e
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/vfs.h>
#include "bdev.h" #include "bdev.h"
#include "log.h" #include "log.h"
...@@ -142,6 +143,32 @@ bool is_btrfs_fs(const char *path) ...@@ -142,6 +143,32 @@ bool is_btrfs_fs(const char *path)
return true; 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) int btrfs_detect(const char *path)
{ {
struct stat st; struct stat st;
......
...@@ -30,6 +30,10 @@ ...@@ -30,6 +30,10 @@
#include <stdint.h> #include <stdint.h>
#include <byteswap.h> #include <byteswap.h>
#ifndef BTRFS_SUPER_MAGIC
# define BTRFS_SUPER_MAGIC 0x9123683E
#endif
typedef uint8_t u8; typedef uint8_t u8;
typedef uint16_t u16; typedef uint16_t u16;
typedef uint32_t u32; typedef uint32_t u32;
...@@ -404,6 +408,7 @@ char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid, char *name, ...@@ -404,6 +408,7 @@ char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid, char *name,
int name_len); int name_len);
int btrfs_list_get_path_rootid(int fd, u64 *treeid); int btrfs_list_get_path_rootid(int fd, u64 *treeid);
bool is_btrfs_fs(const char *path); bool is_btrfs_fs(const char *path);
int is_btrfs_subvol(const char *path);
bool btrfs_try_remove_subvol(const char *path); bool btrfs_try_remove_subvol(const char *path);
int btrfs_same_fs(const char *orig, const char *new); int btrfs_same_fs(const char *orig, const char *new);
int btrfs_snapshot(const char *orig, const char *new); int btrfs_snapshot(const char *orig, const char *new);
......
...@@ -2826,6 +2826,7 @@ bool should_default_to_snapshot(struct lxc_container *c0, ...@@ -2826,6 +2826,7 @@ bool should_default_to_snapshot(struct lxc_container *c0,
size_t l1 = strlen(c1->config_path) + strlen(c1->name) + 2; size_t l1 = strlen(c1->config_path) + strlen(c1->name) + 2;
char *p0 = alloca(l0 + 1); char *p0 = alloca(l0 + 1);
char *p1 = alloca(l1 + 1); char *p1 = alloca(l1 + 1);
char *rootfs = c0->lxc_conf->rootfs.path;
snprintf(p0, l0, "%s/%s", c0->config_path, c0->name); snprintf(p0, l0, "%s/%s", c0->config_path, c0->name);
snprintf(p1, l1, "%s/%s", c1->config_path, c1->name); snprintf(p1, l1, "%s/%s", c1->config_path, c1->name);
...@@ -2833,6 +2834,9 @@ bool should_default_to_snapshot(struct lxc_container *c0, ...@@ -2833,6 +2834,9 @@ bool should_default_to_snapshot(struct lxc_container *c0,
if (!is_btrfs_fs(p0) || !is_btrfs_fs(p1)) if (!is_btrfs_fs(p0) || !is_btrfs_fs(p1))
return false; return false;
if (is_btrfs_subvol(rootfs) <= 0)
return false;
return btrfs_same_fs(p0, p1) == 0; return btrfs_same_fs(p0, p1) == 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment