]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: try to detect if PT is newer than LVM
authorKarel Zak <kzak@redhat.com>
Thu, 24 Feb 2011 13:03:44 +0000 (14:03 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 18 Apr 2011 12:37:50 +0000 (14:37 +0200)
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 <mcepl@redhat.com>
Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=679799
Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/blkid/src/blkidP.h
shlibs/blkid/src/partitions/dos.c
shlibs/blkid/src/partitions/gpt.c
shlibs/blkid/src/partitions/partitions.c
shlibs/blkid/src/probe.c
shlibs/blkid/src/superblocks/lvm.c

index 5bf9ccaf36cad6737fc84b6d429d6426d6ed7aa3..94709a5349194498051ad24ded8a849575f285e1 100644 (file)
@@ -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))
index c961ef7a90be54541b282af8ed5564253be1b4d5..72ac7788c419cfc045ef8ab977ed0827b6a67987 100644 (file)
@@ -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
         */
index 12100e0f8589c216258146a068dcc08718b733bc..8259c2fddd2763dc461ac6884f731a1024e7a84c 100644 (file)
@@ -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;
index fb2e015fc96aec7bb84d2fd4bd170dc180743f3d..4fa826b5c3b9d5876dff81d1d7138f2802af784d 100644 (file)
@@ -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,
index 677b32fabc00514890303a52f45e4a0f153dc69c..3429277436c753493e8bcb9f0552d9540609eee7 100644 (file)
@@ -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);
+       }
+}
+
index facf703e9c7f95dbe781b78baeee71bdf22c4d1a..3a9807c8db540236040d5329f91bc3a8bcd9b444 100644 (file)
@@ -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;
 }