From: Karel Zak Date: Thu, 24 Feb 2011 13:03:44 +0000 (+0100) Subject: libblkid: try to detect if PT is newer than LVM X-Git-Tag: v2.19.1-rc1~58 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9c2b44e668a2475752ccae1d0255ac92d3c85002;p=thirdparty%2Futil-linux.git libblkid: try to detect if PT is newer than LVM LVM (pvcreate) wipes the begin of the device. If there is a PT in the wiped area then LVM signature is obsolete. # pvcreate /dev/sdb # fdisk /dev/sdb old version: # blkid -p -o udev /dev/sdb ID_FS_TYPE=LVM2_member new version: # blkid -p -o udev /dev/sdb ID_PART_TABLE_TYPE=dos Reported-by: Matej Cepl Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=679799 Signed-off-by: Karel Zak --- diff --git a/shlibs/blkid/src/blkidP.h b/shlibs/blkid/src/blkidP.h index 5bf9ccaf36..94709a5349 100644 --- a/shlibs/blkid/src/blkidP.h +++ b/shlibs/blkid/src/blkidP.h @@ -198,6 +198,10 @@ struct blkid_struct_probe int flags; /* private libray flags */ int prob_flags; /* always zeroized by blkid_do_*() */ + blkid_loff_t wipe_off; /* begin of the wiped area */ + blkid_loff_t wipe_size; /* size of the wiped area */ + struct blkid_chain *wipe_chain; /* superblock, partition, ... */ + struct list_head buffers; /* list of buffers */ struct blkid_chain chains[BLKID_NCHAINS]; /* array of chains */ @@ -428,6 +432,12 @@ extern int blkid_probe_sprintf_value(blkid_probe pr, const char *name, extern void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len); extern size_t blkid_rtrim_whitespace(unsigned char *str); +extern void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, + blkid_loff_t size); +extern int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn, + blkid_loff_t off, blkid_loff_t size); +extern void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size); + /* filter bitmap macros */ #define blkid_bmp_wordsize (8 * sizeof(unsigned long)) #define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize)) diff --git a/shlibs/blkid/src/partitions/dos.c b/shlibs/blkid/src/partitions/dos.c index c961ef7a90..72ac7788c4 100644 --- a/shlibs/blkid/src/partitions/dos.c +++ b/shlibs/blkid/src/partitions/dos.c @@ -177,6 +177,9 @@ static int probe_dos_pt(blkid_probe pr, const struct blkid_idmag *mag) } } + blkid_probe_use_wiper(pr, BLKID_MSDOS_PT_OFFSET, + 512 - BLKID_MSDOS_PT_OFFSET); + /* * Well, all checks pass, it's MS-DOS partiton table */ diff --git a/shlibs/blkid/src/partitions/gpt.c b/shlibs/blkid/src/partitions/gpt.c index 12100e0f85..8259c2fddd 100644 --- a/shlibs/blkid/src/partitions/gpt.c +++ b/shlibs/blkid/src/partitions/gpt.c @@ -303,6 +303,8 @@ static int probe_gpt_pt(blkid_probe pr, const struct blkid_idmag *mag) if (!h) goto nothing; + blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8); + if (blkid_partitions_need_typeonly(pr)) /* caller does not ask for details about partitions */ return 0; diff --git a/shlibs/blkid/src/partitions/partitions.c b/shlibs/blkid/src/partitions/partitions.c index fb2e015fc9..4fa826b5c3 100644 --- a/shlibs/blkid/src/partitions/partitions.c +++ b/shlibs/blkid/src/partitions/partitions.c @@ -556,7 +556,7 @@ static int partitions_probe(blkid_probe pr, struct blkid_chain *chn) if (chn->binary) partitions_init_data(pr, chn); - if (pr->prob_flags & BLKID_PARTS_IGNORE_PT) + if (!pr->wipe_size && (pr->prob_flags & BLKID_PARTS_IGNORE_PT)) goto details_only; DBG(DEBUG_LOWPROBE, diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c index 677b32fabc..3429277436 100644 --- a/shlibs/blkid/src/probe.c +++ b/shlibs/blkid/src/probe.c @@ -752,6 +752,7 @@ static inline void blkid_probe_start(blkid_probe pr) if (pr) { pr->cur_chain = NULL; pr->prob_flags = 0; + blkid_probe_set_wiper(pr, 0, 0); } } @@ -760,6 +761,7 @@ static inline void blkid_probe_end(blkid_probe pr) if (pr) { pr->cur_chain = NULL; pr->prob_flags = 0; + blkid_probe_set_wiper(pr, 0, 0); } } @@ -1338,3 +1340,79 @@ size_t blkid_rtrim_whitespace(unsigned char *str) return i; } +/* + * Some mkfs-like utils wipe some parts (usually begin) of the device. + * For example LVM (pvcreate) or mkswap(8). This information could be used + * for later resolution to conflicts between superblocks. + * + * For example we found valid LVM superblock, LVM wipes 8KiB at the begin of + * the device. If we found another signature (for example MBR) this wiped area + * then the signature has been added later and LVM superblock should be ignore. + * + * Note that this heuristic is not 100% reliable, for example "pvcreate --zero + * n" allows to keep the begin of the device unmodified. It's probably better + * to use this heuristic for conflicts between superblocks and partition tables + * than for conflicts between filesystem superblocks -- existence of unwanted + * partition table is very unusual, because PT is pretty visible (parsed and + * interpreted by kernel). + */ +void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) +{ + struct blkid_chain *chn; + + if (!pr) + return; + + if (!size) { + DBG(DEBUG_LOWPROBE, printf("zeroize wiper\n")); + pr->wipe_size = pr->wipe_off = 0; + pr->wipe_chain = NULL; + return; + } + + chn = pr->cur_chain; + + if (!chn || !chn->driver || + chn->idx < 0 || chn->idx >= chn->driver->nidinfos) + return; + + pr->wipe_size = size; + pr->wipe_off = off; + pr->wipe_chain = chn; + + DBG(DEBUG_LOWPROBE, + printf("wiper set to %s::%s off=%jd size=%jd\n", + chn->driver->name, + chn->driver->idinfos[chn->idx]->name, + pr->wipe_off, pr->wipe_size)); + return; +} + +/* + * Returns 1 if the <@off,@size> area was wiped + */ +int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn, + blkid_loff_t off, blkid_loff_t size) +{ + if (!pr || !size) + return 0; + + if (pr->wipe_off <= off && off + size <= pr->wipe_off + pr->wipe_size) { + if (chn) + *chn = pr->wipe_chain; + return 1; + } + return 0; +} + +void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) +{ + struct blkid_chain *chn = NULL; + + if (blkid_probe_is_wiped(pr, &chn, off, size) && chn) { + DBG(DEBUG_LOWPROBE, printf("wiped area detected -- ignore previous results\n")); + blkid_probe_set_wiper(pr, 0, 0); + blkid_probe_chain_reset_vals(pr, chn); + } +} + diff --git a/shlibs/blkid/src/superblocks/lvm.c b/shlibs/blkid/src/superblocks/lvm.c index facf703e9c..3a9807c8db 100644 --- a/shlibs/blkid/src/superblocks/lvm.c +++ b/shlibs/blkid/src/superblocks/lvm.c @@ -112,6 +112,12 @@ static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag) /* the mag->magic is the same string as label->type, * but zero terminated */ blkid_probe_set_version(pr, mag->magic); + + /* LVM (pvcreate) wipes begin of the device -- let's remember this + * to resolve conflicts bettween LVM and partition tables, ... + */ + blkid_probe_set_wiper(pr, 0, 8 * 1024); + return 0; }