From d37a26b680f6c7ca9ec0bb1ce0cca189d19b525f Mon Sep 17 00:00:00 2001 From: Zdenek Kabelac Date: Wed, 1 Jun 2016 16:39:47 +0200 Subject: [PATCH] devices: handle partscan loop devices Treat loop device created with 'losetup -P' as regular partitioned device - so if it has partition table, prevent its usage in commands like 'pvcreate'. Before 'pvcreate /dev/loop0' could have erased and formated as PV, after this patch, device is filtered out and cannot be used. --- WHATS_NEW | 1 + lib/device/dev-type.c | 43 +++++++++++++++++++++++++++++++++++++++++++ lib/device/dev-type.h | 1 + 3 files changed, 45 insertions(+) diff --git a/WHATS_NEW b/WHATS_NEW index 1bad12ae9..74b5bdb56 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.155 - ================================ + Automatically filter out partitioned loop devices with partscan (losetup -P). Fix lvm devtypes internal error if -S used with field name from pvs/vgs/lvs. When reporting Data%,Snap%,Meta%,Cpy%Sync use single ioctl per LV. Add lvseg_percent_with_info_and_seg_status() for percent retrieval. diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c index f9f14188f..0246c09bf 100644 --- a/lib/device/dev-type.c +++ b/lib/device/dev-type.c @@ -125,6 +125,9 @@ struct dev_types *create_dev_types(const char *proc_dir, if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8))) dt->emcpower_major = line_maj; + if (!strncmp("loop", line + i, 4) && isspace(*(line + i + 4))) + dt->loop_major = line_maj; + if (!strncmp("power2", line + i, 6) && isspace(*(line + i + 6))) dt->power2_major = line_maj; @@ -246,6 +249,9 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev) if (MAJOR(dev->dev) == dt->blkext_major) return "BLKEXT"; + if (MAJOR(dev->dev) == dt->loop_major) + return "LOOP"; + return ""; } @@ -265,6 +271,38 @@ int major_is_scsi_device(struct dev_types *dt, int major) return (dt->dev_type_array[major].flags & PARTITION_SCSI_DEVICE) ? 1 : 0; } + +static int _loop_is_with_partscan(struct device *dev) +{ + FILE *fp; + int partscan = 0; + char path[PATH_MAX]; + char buffer[64]; + + if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/loop/partscan", + dm_sysfs_dir(), + (int) MAJOR(dev->dev), + (int) MINOR(dev->dev)) < 0) { + log_warn("Sysfs path for partscan is too long."); + return 0; + } + + if (!(fp = fopen(path, "r"))) + return 0; /* not there -> no partscan */ + + if (!fgets(buffer, sizeof(buffer), fp)) { + log_warn("Failed to read %s.", path); + } else if (sscanf(buffer, "%d", &partscan) != 1) { + log_warn("Failed to parse %s '%s'.", path, buffer); + partscan = 0; + } + + if (fclose(fp)) + log_sys_debug("fclose", path); + + return partscan; +} + /* See linux/genhd.h and fs/partitions/msdos */ #define PART_MAGIC 0xAA55 #define PART_MAGIC_OFFSET UINT64_C(0x1FE) @@ -294,6 +332,11 @@ static int _is_partitionable(struct dev_types *dt, struct device *dev) if (MAJOR(dev->dev) == dt->md_major) return 1; + /* All loop devices are partitionable via blkext (as of 3.2) */ + if ((MAJOR(dev->dev) == dt->loop_major) && + _loop_is_with_partscan(dev)) + return 1; + if ((parts <= 1) || (MINOR(dev->dev) % parts)) return 0; diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h index 6438b4462..267b79f6c 100644 --- a/lib/device/dev-type.h +++ b/lib/device/dev-type.h @@ -43,6 +43,7 @@ struct dev_types { int emcpower_major; int power2_major; int dasd_major; + int loop_major; struct dev_type_def dev_type_array[NUMBER_OF_MAJORS]; };