]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: make whole disk probing more robust
authorKarel Zak <kzak@redhat.com>
Fri, 13 May 2011 13:07:56 +0000 (15:07 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 16 May 2011 18:22:52 +0000 (20:22 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/blkid/src/blkidP.h
shlibs/blkid/src/partitions/partitions.c
shlibs/blkid/src/probe.c

index 53e4c5954b032bbacd6da96668a13d13b6bc588b..ddd1bb8905a2e327d55f8871863526edb0b96c03 100644 (file)
@@ -209,6 +209,9 @@ struct blkid_struct_probe
 
        struct blkid_prval      vals[BLKID_NVALS];      /* results */
        int                     nvals;          /* number of assigned vals */
+
+       struct blkid_struct_probe *parent;      /* for clones */
+       struct blkid_struct_probe *disk_probe;  /* whole-disk probing */
 };
 
 /* private flags library flags */
@@ -219,6 +222,9 @@ struct blkid_struct_probe
 /* private per-probing flags */
 #define BLKID_PROBE_FL_IGNORE_PT (1 << 1)      /* ignore partition table */
 
+extern blkid_probe blkid_clone_probe(blkid_probe parent);
+extern blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr);
+
 /*
  * Evaluation methods (for blkid_eval_* API)
  */
index b89dad5bdad20c6bbfc4c946b50b2438639ca2f4..42c6c2c79f5275bf6b2e475f47e7c77bf0b455de 100644 (file)
@@ -677,30 +677,13 @@ static int blkid_partitions_probe_partition(blkid_probe pr)
        blkid_probe disk_pr = NULL;
        blkid_partlist ls;
        blkid_partition par;
-       dev_t devno, disk_devno;
-       char *disk_path = NULL;
+       dev_t devno;
 
        devno = blkid_probe_get_devno(pr);
        if (!devno)
                goto nothing;
 
-       disk_devno = blkid_probe_get_wholedisk_devno(pr);
-       if (!disk_devno)
-               goto nothing;
-
-       if (devno == disk_devno)
-               goto nothing;           /* this is not a partition */
-
-       disk_path = blkid_devno_to_devname(disk_devno);
-       if (!disk_path)
-               goto nothing;
-
-       DBG(DEBUG_LOWPROBE, printf(
-               "parts: %d:%d: starting whole-disk probing: %s\n",
-               major(devno), minor(devno), disk_path));
-
-       /* create a new prober for the disk */
-       disk_pr = blkid_new_probe_from_filename(disk_path);
+       disk_pr = blkid_probe_get_wholedisk_probe(pr);
        if (!disk_pr)
                goto nothing;
 
@@ -749,46 +732,9 @@ static int blkid_partitions_probe_partition(blkid_probe pr)
        }
        rc = 0;
 nothing:
-       blkid_free_probe(disk_pr);
-       free(disk_path);
        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.
@@ -796,6 +742,7 @@ static blkid_partlist blkid_probe_get_independent_partlist(blkid_probe pr)
 int blkid_probe_is_covered_by_pt(blkid_probe pr,
                                 blkid_loff_t offset, blkid_loff_t size)
 {
+       blkid_probe prc;
        blkid_partlist ls = NULL;
        blkid_loff_t start, end;
        int nparts, i, rc = 0;
@@ -804,7 +751,11 @@ int blkid_probe_is_covered_by_pt(blkid_probe pr,
                "=> checking if off=%jd size=%jd covered by PT\n",
                offset, size));
 
-       ls = blkid_probe_get_independent_partlist(pr);
+       prc = blkid_clone_probe(pr);
+       if (!prc)
+               goto done;
+
+       ls = blkid_probe_get_partitions(prc);
        if (!ls)
                goto done;
 
@@ -837,7 +788,7 @@ int blkid_probe_is_covered_by_pt(blkid_probe pr,
                }
        }
 done:
-       partitions_free_data(pr, (void *)ls);
+       blkid_free_probe(prc);
 
        DBG(DEBUG_LOWPROBE, printf("<= %s covered by PT\n", rc ? "IS" : "NOT"));
        return rc;
index 7cece7ef25621178eabd6ff9193fbd50d419bb63..5f75d713e2a0cbbe6d61ae59a2f5b40f3ce60782 100644 (file)
@@ -142,6 +142,8 @@ blkid_probe blkid_new_probe(void)
        if (!pr)
                return NULL;
 
+       DBG(DEBUG_LOWPROBE, printf("allocate a new probe %p\n", pr));
+
        /* initialize chains */
        for (i = 0; i < BLKID_NCHAINS; i++) {
                pr->chains[i].driver = chains_drvs[i];
@@ -152,6 +154,39 @@ blkid_probe blkid_new_probe(void)
        return pr;
 }
 
+/*
+ * Clone @parent, the new clone shares all, but except:
+ *
+ *     - probing result
+ *     - bufferes if another device (or offset) is set to the prober
+ */
+blkid_probe blkid_clone_probe(blkid_probe parent)
+{
+       blkid_probe pr;
+
+       if (!parent)
+               return NULL;
+
+       DBG(DEBUG_LOWPROBE, printf("allocate a probe clone\n"));
+
+       pr = blkid_new_probe();
+       if (!pr)
+               return NULL;
+
+       pr->fd = parent->fd;
+       pr->off = parent->off;
+       pr->size = parent->size;
+       pr->devno = parent->devno;
+       pr->disk_devno = parent->disk_devno;
+       pr->blkssz = parent->blkssz;
+       pr->flags = parent->flags;
+       pr->parent = parent;
+
+       return pr;
+}
+
+
+
 /**
  * blkid_new_probe_from_filename:
  * @filename: device or regular file
@@ -218,6 +253,9 @@ void blkid_free_probe(blkid_probe pr)
        if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0)
                close(pr->fd);
        blkid_probe_reset_buffer(pr);
+       blkid_free_probe(pr->disk_probe);
+
+       DBG(DEBUG_LOWPROBE, printf("free probe %p\n", pr));
        free(pr);
 }
 
@@ -487,14 +525,23 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
        if (pr->size <= 0)
                return NULL;
 
+       if (pr->parent &&
+           pr->parent->devno == pr->devno &&
+           pr->parent->off == pr->off)
+               /*
+                * This is a cloned prober and points to the same area as
+                * parent. Let's use parent's bufferes.
+                */
+               return blkid_probe_get_buffer(pr->parent, off, len);
+
        list_for_each(p, &pr->buffers) {
                struct blkid_bufinfo *x =
                                list_entry(p, struct blkid_bufinfo, bufs);
 
                if (x->off <= off && off + len <= x->off + x->len) {
                        DBG(DEBUG_LOWPROBE,
-                               printf("\treuse buffer: off=%jd len=%jd\n",
-                                                       x->off, x->len));
+                               printf("\treuse buffer: off=%jd len=%jd pr=%p\n",
+                                                       x->off, x->len, pr));
                        bf = x;
                        break;
                }
@@ -516,7 +563,8 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
                INIT_LIST_HEAD(&bf->bufs);
 
                DBG(DEBUG_LOWPROBE,
-                       printf("\tbuffer read: off=%jd len=%jd\n", off, len));
+                       printf("\tbuffer read: off=%jd len=%jd pr=%p\n",
+                               off, len, pr));
 
                ret = read(pr->fd, bf->data, len);
                if (ret != (ssize_t) len) {
@@ -537,12 +585,11 @@ static void blkid_probe_reset_buffer(blkid_probe pr)
        if (!pr || list_empty(&pr->buffers))
                return;
 
-       DBG(DEBUG_LOWPROBE, printf("reseting probing buffers\n"));
+       DBG(DEBUG_LOWPROBE, printf("reseting probing buffers pr=%p\n", pr));
 
        while (!list_empty(&pr->buffers)) {
                struct blkid_bufinfo *bf = list_entry(pr->buffers.next,
                                                struct blkid_bufinfo, bufs);
-
                read_ct++;
                len_ct += bf->len;
                list_del(&bf->bufs);
@@ -1123,6 +1170,42 @@ int blkid_probe_is_wholedisk(blkid_probe pr)
        return devno == disk_devno;
 }
 
+blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr)
+{
+       dev_t disk;
+
+       if (blkid_probe_is_wholedisk(pr))
+               return NULL;                    /* this is not partition */
+
+       if (pr->parent)
+               /* this is cloned blkid_probe, use parent's stuff */
+               return blkid_probe_get_wholedisk_probe(pr->parent);
+
+       disk = blkid_probe_get_wholedisk_devno(pr);
+
+       if (pr->disk_probe && pr->disk_probe->devno != disk) {
+               /* we have disk prober, but for another disk... close it */
+               blkid_free_probe(pr->disk_probe);
+               pr->disk_probe = NULL;
+       }
+
+       if (!pr->disk_probe) {
+               /* Open a new disk prober */
+               char *disk_path = blkid_devno_to_devname(disk);
+
+               if (!disk_path)
+                       return NULL;
+
+               DBG(DEBUG_LOWPROBE, printf("allocate a wholedisk probe\n"));
+
+               pr->disk_probe = blkid_new_probe_from_filename(disk_path);
+               if (!pr->disk_probe)
+                       return NULL;    /* ENOMEM? */
+       }
+
+       return pr->disk_probe;
+}
+
 /**
  * blkid_probe_get_size:
  * @pr: probe