]> err.no Git - util-linux/commitdiff
libblkid: rewrite blkid_probe_get_buffer()
authorKarel Zak <kzak@redhat.com>
Wed, 20 Jan 2010 19:01:59 +0000 (20:01 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 16 Feb 2010 08:58:56 +0000 (09:58 +0100)
The library does not use any buffer with fixed size any more. The new
version calls read() for necessary data only.

Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/blkid/src/blkidP.h
shlibs/blkid/src/probe.c
shlibs/blkid/src/superblocks/vfat.c

index fb40505beaaa39693165e931ebfbc7dc0f7b3ff4..975878c4ba43eaa9214c4cf4403ee9a29041cb62 100644 (file)
@@ -133,8 +133,6 @@ struct blkid_prval
        struct blkid_chain      *chain;         /* owner */
 };
 
-#define BLKID_SB_BUFSIZ                0x11000
-
 /*
  * Filesystem / Raid magic strings
  */
@@ -172,6 +170,13 @@ struct blkid_idinfo
  */
 #define BLKID_IDINFO_TOLERANT  (1 << 1)
 
+struct blkid_bufinfo {
+       unsigned char           *data;
+       blkid_loff_t            off;
+       blkid_loff_t            len;
+       struct list_head        bufs;   /* list of buffers */
+};
+
 /*
  * Low-level probing control struct
  */
@@ -187,13 +192,7 @@ struct blkid_struct_probe
 
        int                     flags;          /* private libray flags */
 
-       unsigned char           *sbbuf;         /* superblok buffer */
-       size_t                  sbbuf_len;      /* size of data in superblock buffer */
-
-       unsigned char           *buf;           /* seek buffer */
-       blkid_loff_t            buf_off;        /* offset of seek buffer */
-       size_t                  buf_len;        /* size of data in seek buffer */
-       size_t                  buf_max;        /* allocated size of seek buffer */
+       struct list_head        buffers;        /* list of buffers */
 
        struct blkid_chain      chains[BLKID_NCHAINS];  /* array of chains */
        struct blkid_chain      *cur_chain;             /* current chain */
@@ -360,12 +359,8 @@ extern void blkid_free_dev(blkid_dev dev);
 
 /* probe.c */
 extern int blkid_probe_is_tiny(blkid_probe pr);
-extern int blkid_probe_has_buffer(blkid_probe pr,
-                                blkid_loff_t off, blkid_loff_t len);
 extern unsigned char *blkid_probe_get_buffer(blkid_probe pr,
                                 blkid_loff_t off, blkid_loff_t len);
-extern unsigned char *blkid_probe_get_extra_buffer(blkid_probe pr,
-                                blkid_loff_t off, blkid_loff_t len);
 
 extern unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector);
 
index 1bd98b55da722c5240ab0867cc6165e21e8aa500..91366851e34ee7ed6936565787742a695cbc4ce7 100644 (file)
@@ -115,6 +115,7 @@ static const struct blkid_chaindrv *chains_drvs[] = {
 };
 
 static void blkid_probe_reset_vals(blkid_probe pr);
+static void blkid_probe_reset_buffer(blkid_probe pr);
 
 /**
  * blkid_new_probe:
@@ -137,6 +138,7 @@ blkid_probe blkid_new_probe(void)
                pr->chains[i].flags = chains_drvs[i]->dflt_flags;
                pr->chains[i].enabled = chains_drvs[i]->dflt_enabled;
        }
+       INIT_LIST_HEAD(&pr->buffers);
        return pr;
 }
 
@@ -202,26 +204,13 @@ void blkid_free_probe(blkid_probe pr)
                        ch->driver->free_data(pr, ch->data);
                free(ch->fltr);
        }
-       free(pr->buf);
-       free(pr->sbbuf);
 
        if ((pr->flags & BLKID_PRIVATE_FD) && pr->fd >= 0)
                close(pr->fd);
+       blkid_probe_reset_buffer(pr);
        free(pr);
 }
 
-static void blkid_probe_reset_buffer(blkid_probe pr)
-{
-       DBG(DEBUG_LOWPROBE, printf("reseting blkid probe buffer\n"));
-       if (pr->buf)
-               memset(pr->buf, 0, pr->buf_max);
-       pr->buf_off = 0;
-       pr->buf_len = 0;
-       if (pr->sbbuf)
-               memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ);
-       pr->sbbuf_len = 0;
-}
-
 
 /*
  * Removes chain values from probing result.
@@ -470,141 +459,79 @@ int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[
        return 0;
 }
 
-int blkid_probe_has_buffer(blkid_probe pr,
+unsigned char *blkid_probe_get_buffer(blkid_probe pr,
                                blkid_loff_t off, blkid_loff_t len)
 {
-       return pr && (off + len <= pr->sbbuf_len ||
-                    (pr->buf_off < off && off + len < pr->buf_len));
-}
+       struct list_head *p;
+       struct blkid_bufinfo *bf = NULL;
+
+       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));
+                       bf = x;
+                       break;
+               }
+       }
+       if (!bf) {
+               ssize_t ret;
 
-/*
- * Returns buffer from the begin (69kB) of the device.
- */
-static unsigned char *blkid_probe_get_sb_buffer(blkid_probe pr,
-                               blkid_loff_t off, blkid_loff_t len)
-{
-       if (off + len > BLKID_SB_BUFSIZ)
-               return NULL;
-       if (!pr->sbbuf) {
-               pr->sbbuf = malloc(BLKID_SB_BUFSIZ);
-               if (!pr->sbbuf)
+               if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
                        return NULL;
-       }
-       if (off + len > pr->sbbuf_len) {
-               /*
-                * The sbbuf is not completely in memory.
-                *
-                */
-               ssize_t ret_read;
-               blkid_loff_t want, have = pr->sbbuf_len;
-
-               if (blkid_probe_is_tiny(pr))
-                       /* We don't read whole BLKID_SB_BUFSIZ by one read(),
-                        * it's too aggresive to small devices (floppies). We
-                        * read necessary data to complete the current request
-                        * (off + len) only.
-                        */
-                       want = off + len - have;
-               else
-                       /* large disk -- read all SB */
-                       want = BLKID_SB_BUFSIZ - have;
+
+               /* allocate info and space for data by why call */
+               bf = calloc(1, sizeof(struct blkid_bufinfo) + len);
+               if (!bf)
+                       return NULL;
+
+               bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo);
+               bf->len = len;
+               bf->off = off;
+               INIT_LIST_HEAD(&bf->bufs);
 
                DBG(DEBUG_LOWPROBE,
-                       printf("\tsb-buffer read() off=%jd len=%jd\n", have, want));
+                       printf("\tbuffer read: off=%jd len=%jd\n", off, len));
 
-               if (lseek(pr->fd, pr->off + have, SEEK_SET) < 0)
+               ret = read(pr->fd, bf->data, len);
+               if (ret != (ssize_t) len) {
+                       free(bf);
                        return NULL;
-
-               ret_read = read(pr->fd, pr->sbbuf + have, want);
-               if (ret_read < 0)
-                       ret_read = 0;
-               pr->sbbuf_len = have + ret_read;
+               }
+               list_add_tail(&bf->bufs, &pr->buffers);
        }
-       if (off + len > pr->sbbuf_len)
-               return NULL;
-       return pr->sbbuf + off;
+
+       return off ? bf->data + (off - bf->off) : bf->data;
 }
 
-/*
- * Returns pointer to the buffer on arbitrary offset on the device
- */
-unsigned char *blkid_probe_get_extra_buffer(blkid_probe pr,
-                               blkid_loff_t off, blkid_loff_t len)
+
+static void blkid_probe_reset_buffer(blkid_probe pr)
 {
-       unsigned char *newbuf = NULL;
-
-       if (off + len <= BLKID_SB_BUFSIZ &&
-           (!blkid_probe_is_tiny(pr) || blkid_probe_has_buffer(pr, off, len)))
-               /*
-                * Don't use extra buffer for superblock data if
-                *      - data are already in SB buffer
-                *      - or the device is large and we needn't extra
-                *        optimalization for tiny devices
-                */
-               return blkid_probe_get_sb_buffer(pr, off, len);
+       ssize_t read_ct = 0, len_ct = 0;
 
-       if (len > pr->buf_max) {
-               newbuf = realloc(pr->buf, len);
-               if (!newbuf)
-                       return NULL;
-               pr->buf = newbuf;
-               pr->buf_max = len;
-               pr->buf_off = 0;
-               pr->buf_len = 0;
-       }
-       if (newbuf || off < pr->buf_off ||
-           off + len > pr->buf_off + pr->buf_len) {
-               ssize_t ret_read;
+       if (!pr || list_empty(&pr->buffers))
+               return;
 
-               if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
-                       return NULL;
+       DBG(DEBUG_LOWPROBE, printf("reseting probing buffers\n"));
 
-               DBG(DEBUG_LOWPROBE,
-                       printf("\textra-buffer read: off=%jd len=%jd\n", off, len));
+       while (!list_empty(&pr->buffers)) {
+               struct blkid_bufinfo *bf = list_entry(pr->buffers.next,
+                                               struct blkid_bufinfo, bufs);
 
-               ret_read = read(pr->fd, pr->buf, len);
-               if (ret_read != (ssize_t) len)
-                       return NULL;
-               pr->buf_off = off;
-               pr->buf_len = len;
+               read_ct++;
+               len_ct += bf->len;
+               list_del(&bf->bufs);
+               free(bf);
        }
-       return off ? pr->buf + (off - pr->buf_off) : pr->buf;
-}
 
+       DBG(DEBUG_LOWPROBE,
+               printf("buffers summary: %jd bytes by %jd read() call(s)\n",
+                       len_ct, read_ct));
 
-/*
- * @off: offset within probing area
- * @len: size of requested buffer
- *
- * The probing area is between pr->off and pr->size. The @off = 0 is pr->off, the
- * max @len is pr->size.
- *
- * Note that we have two offsets:
- *
- *     1/ general device offset (pr->off), that's useful for example when we
- *        probe a partition from whole disk image:
- *                    blkid -O <partition_position> -S <size> disk.img
- *
- *     2/ buffer offset (the @off argument), that useful for offsets in
- *        superbloks, ...
- *
- * That means never use lseek(fd, 0, SEEK_SET), the zero position is always
- * pr->off, so lseek(fd, pr->off, SEEK_SET).
- *
- */
-unsigned char *blkid_probe_get_buffer(blkid_probe pr,
-                               blkid_loff_t off, blkid_loff_t len)
-{
-       if (off < 0 || len < 0) {
-               DBG(DEBUG_LOWPROBE,
-                       printf("unexpected offset or length of buffer requested\n"));
-               return NULL;
-       }
-       if (off + len > pr->size)
-               return NULL;
-       if (off + len <= BLKID_SB_BUFSIZ)
-               return blkid_probe_get_sb_buffer(pr, off, len);
-       return blkid_probe_get_extra_buffer(pr, off, len);
+       INIT_LIST_HEAD(&pr->buffers);
 }
 
 /*
index 29066c34c0d5a3b2080dd8713cb6ec96edff1cf1..71c0fbcbd3500d5800f7652ffe8b18113b7261d9 100644 (file)
@@ -142,7 +142,7 @@ static unsigned char *search_fat_label(blkid_probe pr,
                 */
                if (!dir)
                        ent = (struct vfat_dir_entry *)
-                               blkid_probe_get_extra_buffer(pr,
+                               blkid_probe_get_buffer(pr,
                                        offset + (i * sizeof(struct vfat_dir_entry)),
                                        sizeof(struct vfat_dir_entry));
                else
@@ -330,7 +330,7 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag)
                        /* get FAT entry */
                        fat_entry_off = (reserved * sector_size) +
                                (next * sizeof(uint32_t));
-                       buf = blkid_probe_get_extra_buffer(pr, fat_entry_off, buf_size);
+                       buf = blkid_probe_get_buffer(pr, fat_entry_off, buf_size);
                        if (buf == NULL)
                                break;
 
@@ -351,7 +351,7 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag)
                if (fsinfo_sect) {
                        struct fat32_fsinfo *fsinfo;
 
-                       buf = blkid_probe_get_extra_buffer(pr,
+                       buf = blkid_probe_get_buffer(pr,
                                        fsinfo_sect * sector_size,
                                        sizeof(struct fat32_fsinfo));
                        if (buf == NULL)