From fdbabea57a1fce77febfb2ac6bcbfed83e0427f8 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 20 Jan 2010 20:01:59 +0100 Subject: [PATCH] libblkid: rewrite blkid_probe_get_buffer() 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 --- shlibs/blkid/src/blkidP.h | 21 ++-- shlibs/blkid/src/probe.c | 187 +++++++++------------------- shlibs/blkid/src/superblocks/vfat.c | 6 +- 3 files changed, 68 insertions(+), 146 deletions(-) diff --git a/shlibs/blkid/src/blkidP.h b/shlibs/blkid/src/blkidP.h index fb40505b..975878c4 100644 --- a/shlibs/blkid/src/blkidP.h +++ b/shlibs/blkid/src/blkidP.h @@ -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); diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c index 1bd98b55..91366851 100644 --- a/shlibs/blkid/src/probe.c +++ b/shlibs/blkid/src/probe.c @@ -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 -S 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); } /* diff --git a/shlibs/blkid/src/superblocks/vfat.c b/shlibs/blkid/src/superblocks/vfat.c index 29066c34..71c0fbcb 100644 --- a/shlibs/blkid/src/superblocks/vfat.c +++ b/shlibs/blkid/src/superblocks/vfat.c @@ -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) -- 2.39.5