summaryrefslogtreecommitdiffstats
path: root/libblkid/src/probe.c
diff options
context:
space:
mode:
authorKarel Zak2015-09-24 10:35:18 +0200
committerKarel Zak2015-09-24 11:10:09 +0200
commit2355dd6a49a684f098f2c7d048588848194f7e14 (patch)
tree87f08a903a180df684dcfb7d29414aea89dc4fec /libblkid/src/probe.c
parentlibblkid: use mmap() rather than read() (diff)
downloadkernel-qcow2-util-linux-2355dd6a49a684f098f2c7d048588848194f7e14.tar.gz
kernel-qcow2-util-linux-2355dd6a49a684f098f2c7d048588848194f7e14.tar.xz
kernel-qcow2-util-linux-2355dd6a49a684f098f2c7d048588848194f7e14.zip
libblkid: add read() based fallback for char (UBI) devs
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libblkid/src/probe.c')
-rw-r--r--libblkid/src/probe.c69
1 files changed, 60 insertions, 9 deletions
diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c
index 35a25d20f..9f8109959 100644
--- a/libblkid/src/probe.c
+++ b/libblkid/src/probe.c
@@ -588,6 +588,8 @@ int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[
#define PROBE_MMAP_ENDSIZ (1024 * 1024 * 2) /* end of the device */
#define PROBE_MMAP_MIDSIZ (1024 * 1024) /* middle of the device */
+#define probe_is_mmap_wanted(p) (!S_ISCHR((p)->mode))
+
static struct blkid_bufinfo *mmap_buffer(blkid_probe pr,
blkid_loff_t real_off,
blkid_loff_t len)
@@ -660,6 +662,50 @@ static struct blkid_bufinfo *mmap_buffer(blkid_probe pr,
return bf;
}
+static struct blkid_bufinfo *read_buffer(blkid_probe pr,
+ blkid_loff_t real_off,
+ blkid_loff_t len)
+{
+ ssize_t ret;
+ struct blkid_bufinfo *bf = NULL;
+
+ if (blkid_llseek(pr->fd, real_off, SEEK_SET) < 0) {
+ errno = 0;
+ return NULL;
+ }
+
+ /* someone trying to overflow some buffers? */
+ if (len > ULONG_MAX - sizeof(struct blkid_bufinfo)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* allocate info and space for data by one malloc call */
+ bf = calloc(1, sizeof(struct blkid_bufinfo) + len);
+ if (!bf) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo);
+ bf->len = len;
+ bf->off = real_off;
+ INIT_LIST_HEAD(&bf->bufs);
+
+ DBG(LOWPROBE, ul_debug("\tread %p: off=%jd len=%jd", bf->data, real_off, len));
+
+ ret = read(pr->fd, bf->data, len);
+ if (ret != (ssize_t) len) {
+ DBG(LOWPROBE, ul_debug("\tread failed: %m"));
+ free(bf);
+ if (ret >= 0)
+ errno = 0;
+ return NULL;
+ }
+
+ return bf;
+}
+
/*
* Note that @off is offset within probing area, the probing area is defined by
* pr->off and pr->size.
@@ -717,7 +763,10 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
/* not found; read from disk */
if (!bf) {
- bf = mmap_buffer(pr, real_off, len);
+ if (probe_is_mmap_wanted(pr))
+ bf = mmap_buffer(pr, real_off, len);
+ else
+ bf = read_buffer(pr, real_off, len);
if (!bf)
return NULL;
@@ -733,7 +782,7 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
static void blkid_probe_reset_buffer(blkid_probe pr)
{
- uint64_t mmap_ct = 0, len_ct = 0;
+ uint64_t ct = 0, len = 0;
if (!pr || list_empty(&pr->buffers))
return;
@@ -743,17 +792,19 @@ static void blkid_probe_reset_buffer(blkid_probe pr)
while (!list_empty(&pr->buffers)) {
struct blkid_bufinfo *bf = list_entry(pr->buffers.next,
struct blkid_bufinfo, bufs);
- mmap_ct++;
- len_ct += bf->len;
+ ct++;
+ len += bf->len;
list_del(&bf->bufs);
- DBG(BUFFER, ul_debug(" unmap: %p [off=%ju, len=%ju]", bf->data, bf->off, bf->len));
- munmap(bf->data, bf->len);
+ DBG(BUFFER, ul_debug(" remove buffer: %p [off=%ju, len=%ju]", bf->data, bf->off, bf->len));
+
+ if (probe_is_mmap_wanted(pr))
+ munmap(bf->data, bf->len);
free(bf);
}
- DBG(LOWPROBE, ul_debug("buffers summary: %ju bytes (%ju pages) by %ju mmap() call(s)",
- len_ct, len_ct / pr->mmap_granularity, mmap_ct));
+ DBG(LOWPROBE, ul_debug(" buffers summary: %ju bytes by %ju read/mmap() calls",
+ len, ct));
INIT_LIST_HEAD(&pr->buffers);
}
@@ -840,7 +891,7 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
goto err;
if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode) && !S_ISREG(sb.st_mode)) {
- errno = EINVAL;
+ errno = EINVAL;
goto err;
}