LVM snapshots create a problem to the btrfs devices management. BTRFS assumes that each device haw an unique 'device UUID'. A LVM snapshot breaks this assumption.
This patch skips LVM snapshots during the device scan phase. If you need to consider a LVM snapshot you have to set the environmental variable BTRFS_SKIP_LVM_SNAPSHOT to "no". To check if a device is a LVM snapshot, it is checked the 'udev' device property 'DM_UDEV_LOW_PRIORITY_FLAG' . If it is set to 1, the device has to be skipped. As conseguence, btrfs now depends by libudev. Programmatically you can control this behavior with the functions: - btrfs_scan_set_skip_lvm_snapshot(int new_value) - int btrfs_scan_get_skip_lvm_snapshot( ) Signed-off-by: Goffredo Baroncelli <kreij...@inwind.it> --- Makefile | 4 +-- utils.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ utils.h | 9 +++++- 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 4cae30c..9464361 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ TESTS = fsck-tests.sh convert-tests.sh INSTALL = install prefix ?= /usr/local bindir = $(prefix)/bin -lib_LIBS = -luuid -lblkid -lm -lz -llzo2 -L. +lib_LIBS = -luuid -lblkid -lm -lz -ludev -llzo2 -L. libdir ?= $(prefix)/lib incdir = $(prefix)/include/btrfs LIBS = $(lib_LIBS) $(libs_static) @@ -99,7 +99,7 @@ lib_links = libbtrfs.so.0 libbtrfs.so headers = $(libbtrfs_headers) # make C=1 to enable sparse -check_defs := .cc-defines.h +check_defs := .cc-defines.h ifdef C # # We're trying to use sparse against glibc headers which go wild diff --git a/utils.c b/utils.c index 2a92416..9887f8b 100644 --- a/utils.c +++ b/utils.c @@ -29,6 +29,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <uuid/uuid.h> +#include <libudev.h> #include <fcntl.h> #include <unistd.h> #include <mntent.h> @@ -52,6 +53,13 @@ #define BLKDISCARD _IO(0x12,119) #endif +/* + * This variable controls if the lvm snapshot have to be skipped or not. + * Access this variable only via the btrfs_scan_[sg]et_skip_lvm_snapshot() + * functions + */ +static int __scan_device_skip_lvm_snapshot = -1; + static int btrfs_scan_done = 0; static char argv0_buf[ARGV0_BUF_SIZE] = "btrfs"; @@ -1593,6 +1601,9 @@ int btrfs_scan_block_devices(int run_ioctl) char fullpath[110]; int scans = 0; int special; + int skip_snapshot; + + skip_snapshot = btrfs_scan_get_skip_lvm_snapshot(); scan_again: proc_partitions = fopen("/proc/partitions","r"); @@ -1642,6 +1653,9 @@ scan_again: continue; } + if (skip_snapshot && is_low_priority_device(fullpath)) + continue; + fd = open(fullpath, O_RDONLY); if (fd < 0) { if (errno != ENOMEDIUM) @@ -2182,6 +2196,30 @@ int test_dev_for_mkfs(char *file, int force_overwrite, char *estr) return 0; } +int btrfs_scan_get_skip_lvm_snapshot( ) +{ + const char *value; + + if (__scan_device_skip_lvm_snapshot != -1 ) + return __scan_device_skip_lvm_snapshot; + + value = getenv(BTRFS_SKIP_LVM_SNAPSHOT_ENV_NAME); + if (value && !strcasecmp(value, "NO")) + __scan_device_skip_lvm_snapshot = 0; + else if (value && !strcasecmp(value, "YES")) + __scan_device_skip_lvm_snapshot = 1; + else + __scan_device_skip_lvm_snapshot = + BTRFS_SKIP_LVM_SNAPSHOT_DEFAULT; + + return __scan_device_skip_lvm_snapshot; +} + +void btrfs_scan_set_skip_lvm_snapshot(int new_value) +{ + __scan_device_skip_lvm_snapshot = !!new_value; +} + int btrfs_scan_lblkid() { int fd = -1; @@ -2192,6 +2230,9 @@ int btrfs_scan_lblkid() blkid_dev dev = NULL; blkid_cache cache = NULL; char path[PATH_MAX]; + int skip_snapshot; + + skip_snapshot = btrfs_scan_get_skip_lvm_snapshot(); if (btrfs_scan_done) return 0; @@ -2210,6 +2251,9 @@ int btrfs_scan_lblkid() /* if we are here its definitely a btrfs disk*/ strncpy(path, blkid_dev_devname(dev), PATH_MAX); + if (skip_snapshot && is_low_priority_device(path)) + continue; + fd = open(path, O_RDONLY); if (fd < 0) { printf("ERROR: could not open %s\n", path); @@ -2450,3 +2494,66 @@ int find_next_key(struct btrfs_path *path, struct btrfs_key *key) } return 1; } + +/* + * This function return 1 if the device (path) is consdered "LOW_PRIORITY" by + * LVM2 library. These device are typically the nsapshot. + * This function return < 0 in case of error; 0 otherwise. + */ +int is_low_priority_device(const char *path) +{ + + struct udev *udev=NULL; + struct udev_device *dev; + struct udev_enumerate *enumerate=NULL; + struct udev_list_entry *devices; + struct udev_list_entry *node, *list; + int ret=-1; + const char *value, *syspath; + char *rpath=NULL; + + rpath = realpath(path, NULL); + if (!rpath) { + fprintf(stderr, "ERROR: not enough memory\n"); + ret=-2; + goto exit; + } + + /* Create the udev object */ + udev = udev_new(); + if (!udev) { + fprintf(stderr, "ERROR: Can't create udev\n"); + ret=-1; + goto exit; + } + + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "block"); + udev_enumerate_add_match_property(enumerate, "DEVNAME", rpath); + udev_enumerate_scan_devices(enumerate); + + devices = udev_enumerate_get_list_entry(enumerate); + syspath = udev_list_entry_get_name(devices); + + dev = udev_device_new_from_syspath(udev, syspath); + + list = udev_device_get_properties_list_entry (dev); + + ret = 0; + node = udev_list_entry_get_by_name(list, "DM_UDEV_LOW_PRIORITY_FLAG"); + if (node) { + value = udev_list_entry_get_value(node); + if (value && !strcmp(value, "1")) + ret = 1; + } + +exit: + free(rpath); + + /* Free the enumerator object */ + udev_enumerate_unref(enumerate); + + udev_unref(udev); + + return ret; +} diff --git a/utils.h b/utils.h index 289e86b..9855f09 100644 --- a/utils.h +++ b/utils.h @@ -128,7 +128,7 @@ int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, int verify); int ask_user(char *question); int lookup_ino_rootid(int fd, u64 *rootid); -int btrfs_scan_lblkid(void); +int btrfs_scan_lblkid(); int get_btrfs_mount(const char *dev, char *mp, size_t mp_size); int find_mount_root(const char *path, char **mount_root); int get_device_info(int fd, u64 devid, @@ -161,4 +161,11 @@ static inline u64 btrfs_min_dev_size(u32 leafsize) int find_next_key(struct btrfs_path *path, struct btrfs_key *key); +#define BTRFS_SKIP_LVM_SNAPSHOT_DEFAULT 1 +#define BTRFS_SKIP_LVM_SNAPSHOT_ENV_NAME "BTRFS_SKIP_LVM_SNAPSHOT" + +int is_low_priority_device(const char *path); +void btrfs_scan_set_skip_lvm_snapshot(int new_value); +int btrfs_scan_get_skip_lvm_snapshot( ); + #endif -- 2.1.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html