]> err.no Git - util-linux/commitdiff
libblkid: fix collision between RAID and PT probing
authorKarel Zak <kzak@redhat.com>
Thu, 22 Apr 2010 19:30:04 +0000 (21:30 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 22 Apr 2010 19:30:04 +0000 (21:30 +0200)
The RAID signature is usually at end of the block device. We have to
differentiate between:

- RAID signature at the end of disk, and
- RAID signature at the end of the last partition

The position of the signature is same in both cases... It means we have
to the parse partition table and check if the area where is RAID signature
is covered by any partition. If yes, then the RAID signature belongs to the
partition and has to be ignored during whole-disk probing.

The second problem are RAID1 underlaying disks (=raid members).  The
RAID device could be partitioned, in such a case the partition table
is visible from underlaying devices. These partition tables has to be
ignored. The libblkid ignores partition tables on raid members now.

Note that all these changes are implemented for blkid_do_safeprobe()
only. The others functions allow to access all detected superblocks or
partition tables.

Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=543749
Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/blkid/src/blkidP.h
shlibs/blkid/src/partitions/partitions.c
shlibs/blkid/src/probe.c
shlibs/blkid/src/superblocks/superblocks.c

index c37f73062f573d91d9927897f4aa2455415f274a..41eba9102da99346e586250ee36cc436cde67321 100644 (file)
@@ -196,6 +196,7 @@ struct blkid_struct_probe
        mode_t                  mode;           /* struct stat.sb_mode */
 
        int                     flags;          /* private libray flags */
+       int                     prob_flags;     /* always zeroized by blkid_do_*() */
 
        struct list_head        buffers;        /* list of buffers */
 
@@ -206,10 +207,12 @@ struct blkid_struct_probe
        int                     nvals;          /* number of assigned vals */
 };
 
-/* flags */
+/* private flags */
 #define BLKID_PRIVATE_FD       (1 << 1)        /* see blkid_new_probe_from_filename() */
 #define BLKID_TINY_DEV         (1 << 2)        /* <= 1.47MiB (floppy or so) */
 #define BLKID_CDROM_DEV                (1 << 3)        /* is a CD/DVD drive */
+/* private probing flags */
+#define BLKID_PARTS_IGNORE_PT  (1 << 1)        /* ignore partition table */
 
 /*
  * Evaluation methods (for blkid_eval_* API)
@@ -390,6 +393,9 @@ extern int blkid_probe_set_dimension(blkid_probe pr,
 
 extern blkid_partlist blkid_probe_get_partlist(blkid_probe pr);
 
+extern int blkid_probe_is_covered_by_pt(blkid_probe pr,
+                                       blkid_loff_t offset, blkid_loff_t size);
+
 extern void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn);
 extern int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn,
                                        struct blkid_prval *vals, int nvals);
index 293ee86aa12771de85906d9246ca2b297d510831..9d8f3db7ab98d0de34338ea236fbdd97cb2045d3 100644 (file)
@@ -582,6 +582,9 @@ 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)
+               goto details_only;
+
        DBG(DEBUG_LOWPROBE,
                printf("--> starting probing loop [PARTS idx=%d]\n",
                chn->idx));
@@ -620,6 +623,7 @@ static int partitions_probe(blkid_probe pr, struct blkid_chain *chn)
                        chn->idx));
        }
 
+details_only:
        /*
         * Gather PART_ENTRY_* values if the current device is a partition.
         */
@@ -764,6 +768,82 @@ nothing:
        return rc;
 }
 
+/*
+ * This function is compatible with blkid_probe_get_partitions(), but the
+ * result is not stored in @pr and all probing is independent on the
+ * status of @pr. It's possible to call this function from arbitrary
+ * place without a care about @pr.
+ */
+static blkid_partlist blkid_probe_get_independent_partlist(blkid_probe pr)
+{
+
+       blkid_partlist ls = NULL, org_ls = NULL;
+       struct blkid_chain *chn = &pr->chains[BLKID_CHAIN_PARTS];
+       struct blkid_prval vals[BLKID_NVALS_PARTS];
+       int nvals = BLKID_NVALS_PARTS;
+       int idx;
+
+       /* save old results */
+       nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals);
+       idx = chn->idx;
+       if (chn->data) {
+               org_ls = chn->data;
+               chn->data = NULL;
+       }
+
+       ls = blkid_probe_get_partitions(pr);
+
+       /* restore original results */
+       chn->data = org_ls;
+       chn->idx = idx;
+
+       blkid_probe_chain_reset_vals(pr, chn);
+       blkid_probe_append_vals(pr, vals, nvals);
+
+       return ls;
+}
+
+/*
+ * Returns 1 if the device is whole-disk and the area specified by @offset and
+ * @size is covered by any partition.
+ */
+int blkid_probe_is_covered_by_pt(blkid_probe pr,
+                                blkid_loff_t offset, blkid_loff_t size)
+{
+       blkid_partlist ls = NULL;
+       blkid_loff_t start, end;
+       int nparts, i, rc = 0;
+
+       DBG(DEBUG_LOWPROBE, printf(
+               "=> checking if off=%jd size=%jd covered by PT\n",
+               offset, size));
+
+       ls = blkid_probe_get_independent_partlist(pr);
+       if (!ls)
+               goto done;
+
+       nparts = blkid_partlist_numof_partitions(ls);
+       if (!nparts)
+               goto done;
+
+       end = (offset + size) >> 9;
+       start = offset >> 9;
+
+       for (i = 0; i < nparts; i++) {
+               blkid_partition par = &ls->parts[i];
+
+               if (start >= par->start && end <= par->start + par->size) {
+                       rc = 1;
+                       break;
+               }
+       }
+done:
+       partitions_free_data(pr, (void *)ls);
+
+       DBG(DEBUG_LOWPROBE, printf("<= %s covered by PT\n", rc ? "IS" : "NOT"));
+       return rc;
+}
+
 /**
  * blkid_known_pttype:
  * @pttype: partiton name
index 56e66a311f70b1fbeb3c1678cb5a12bccddbb7df..9021a7e8441766196d6d097437b6dfcd9414498c 100644 (file)
@@ -290,21 +290,33 @@ struct blkid_chain *blkid_probe_get_chain(blkid_probe pr)
 
 void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn)
 {
-       int rc;
+       int rc, org_prob_flags;
+       struct blkid_chain *org_chn;
 
        if (!pr || !chn)
                return NULL;
 
+       /* save the current setting -- the binary API has to be completely
+        * independent on the current probing status
+        */
+       org_chn = pr->cur_chain;
+       org_prob_flags = pr->prob_flags;
+
        pr->cur_chain = chn;
+       pr->prob_flags = 0;
        chn->binary = TRUE;
        blkid_probe_chain_reset_position(chn);
 
        rc = chn->driver->probe(pr, chn);
 
        chn->binary = FALSE;
-       pr->cur_chain = NULL;
        blkid_probe_chain_reset_position(chn);
 
+       /* restore the original setting
+        */
+       pr->cur_chain = org_chn;
+       pr->prob_flags = org_prob_flags;
+
        if (rc != 0)
                return NULL;
 
@@ -679,6 +691,22 @@ int blkid_probe_set_dimension(blkid_probe pr,
        return 0;
 }
 
+static inline void blkid_probe_start(blkid_probe pr)
+{
+       if (pr) {
+               pr->cur_chain = NULL;
+               pr->prob_flags = 0;
+       }
+}
+
+static inline void blkid_probe_end(blkid_probe pr)
+{
+       if (pr) {
+               pr->cur_chain = NULL;
+               pr->prob_flags = 0;
+       }
+}
+
 /**
  * blkid_do_probe:
  * @pr: prober
@@ -730,9 +758,10 @@ int blkid_do_probe(blkid_probe pr)
        do {
                struct blkid_chain *chn = pr->cur_chain;
 
-               if (!chn)
+               if (!chn) {
+                       blkid_probe_start(pr);
                        chn = pr->cur_chain = &pr->chains[0];
-
+               }
                /* we go to the next chain only when the previous probing
                 * result was nothing (rc == 1) and when the current chain is
                 * disabled or we are at end of the current chain (chain->idx +
@@ -747,8 +776,10 @@ int blkid_do_probe(blkid_probe pr)
 
                        if (idx < BLKID_NCHAINS)
                                chn = pr->cur_chain = &pr->chains[idx];
-                       else
+                       else {
+                               blkid_probe_end(pr);
                                return 1;       /* all chains already probed */
+                       }
                }
 
                chn->binary = FALSE;            /* for sure... */
@@ -780,7 +811,9 @@ int blkid_do_probe(blkid_probe pr)
  *
  * Note about suberblocks chain -- the function does not check for filesystems
  * when a RAID signature is detected.  The function also does not check for
- * collision between RAIDs. The first detected RAID is returned.
+ * collision between RAIDs. The first detected RAID is returned. The function
+ * checks for collision between partition table and RAID signature -- it's
+ * recommended to enable partitions chain together with superblocks chain.
  *
  * Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is
  * detected and -1 on case of error.
@@ -792,6 +825,8 @@ int blkid_do_safeprobe(blkid_probe pr)
        if (!pr)
                return -1;
 
+       blkid_probe_start(pr);
+
        for (i = 0; i < BLKID_NCHAINS; i++) {
                struct blkid_chain *chn;
 
@@ -819,7 +854,7 @@ int blkid_do_safeprobe(blkid_probe pr)
        }
 
 done:
-       pr->cur_chain = NULL;
+       blkid_probe_end(pr);
        if (rc < 0)
                return rc;
        return count ? 0 : 1;
@@ -844,6 +879,8 @@ int blkid_do_fullprobe(blkid_probe pr)
        if (!pr)
                return -1;
 
+       blkid_probe_start(pr);
+
        for (i = 0; i < BLKID_NCHAINS; i++) {
                int rc;
                struct blkid_chain *chn;
@@ -872,7 +909,7 @@ int blkid_do_fullprobe(blkid_probe pr)
        }
 
 done:
-       pr->cur_chain = NULL;
+       blkid_probe_end(pr);
        if (rc < 0)
                return rc;
        return count ? 0 : 1;
index 6ed0de6e6838b3f3b3e807722453569a9f5fc2a7..b46e59633b7098932c95ad994df2f3b02f192ee9 100644 (file)
@@ -478,14 +478,17 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
        int idx = -1;
        int count = 0;
        int intol = 0;
-       int rc;
+       int rc, bin_org = chn->binary;
+
+       chn->binary = TRUE;
 
        while ((rc = superblocks_probe(pr, chn)) == 0) {
 
-               if (blkid_probe_is_tiny(pr) && !count)
+               if (blkid_probe_is_tiny(pr) && !count) {
                        /* floppy or so -- returns the first result. */
+                       chn->binary = bin_org;
                        return 0;
-
+               }
                if (!count) {
                        /* save the first result */
                        nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals);
@@ -500,6 +503,9 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
                if (!(idinfos[chn->idx]->flags & BLKID_IDINFO_TOLERANT))
                        intol++;
        }
+
+       chn->binary = bin_org;
+
        if (rc < 0)
                return rc;              /* error */
        if (count > 1 && intol) {
@@ -519,6 +525,30 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
                superblocks_copy_data(chn->data, sb);
        chn->idx = idx;
 
+       /*
+        * Check for collisions between RAID and partition table
+        */
+       if (sb && sb->usage == BLKID_USAGE_RAID &&
+           sb->magic_off > pr->size / 2 &&
+           (S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) &&
+           blkid_probe_is_covered_by_pt(pr, sb->magic_off, 0x200)) {
+               /*
+                * Ignore the result if the detected RAID superblock is
+                * within some existing partition (for example RAID on
+                * the last partition).
+                */
+               blkid_probe_chain_reset_vals(pr, chn);
+               return 1;
+       }
+
+       /*
+        * The RAID device could be partitioned. The problem are RAID1 devices
+        * where the partition table is visible from underlaying devices. We
+        * have to ignore such partition tables.
+        */
+       if (sb && sb->usage == BLKID_USAGE_RAID)
+               pr->prob_flags |= BLKID_PARTS_IGNORE_PT;
+
        return 0;
 }