diff options
author | Andrey V. Elsukov <ae@FreeBSD.org> | 2015-05-19 09:28:52 +0000 |
---|---|---|
committer | Andrey V. Elsukov <ae@FreeBSD.org> | 2015-05-19 09:28:52 +0000 |
commit | 153c57b5b43f3f26f11821bb69c64e42fb6e0668 (patch) | |
tree | 1489c0851718a09eb93278bb072d1efb87cdd4de /sys/geom | |
parent | 68691fe0ce927e489f568e60df44e4a3a4ab21b1 (diff) | |
download | src-153c57b5b43f3f26f11821bb69c64e42fb6e0668.tar.gz src-153c57b5b43f3f26f11821bb69c64e42fb6e0668.zip |
Read GEOM_UNCOMPRESS metadata using several requests that fit into
MAXPHYS. For large compressed images the metadata size can be bigger
than MAXPHYS and this triggers KASSERT in g_read_data().
Also use g_free() to free memory allocated by g_read_data().
PR: 199476
MFC after: 2 weeks
Notes
Notes:
svn path=/head/; revision=283104
Diffstat (limited to 'sys/geom')
-rw-r--r-- | sys/geom/uncompress/g_uncompress.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/sys/geom/uncompress/g_uncompress.c b/sys/geom/uncompress/g_uncompress.c index 8c2d5cb6c929..62a677de25a7 100644 --- a/sys/geom/uncompress/g_uncompress.c +++ b/sys/geom/uncompress/g_uncompress.c @@ -464,7 +464,8 @@ g_uncompress_taste(struct g_class *mp, struct g_provider *pp, int flags) struct g_provider *pp2; struct g_consumer *cp; struct g_geom *gp; - uint32_t i, total_offsets, type; + uint64_t *offsets; + uint32_t i, r, total, total_offsets, type; uint8_t *buf; int error; @@ -499,8 +500,8 @@ g_uncompress_taste(struct g_class *mp, struct g_provider *pp, int flags) */ DPRINTF(("%s: media sectorsize %u, mediasize %jd\n", gp->name, pp->sectorsize, (intmax_t)pp->mediasize)); - i = roundup(sizeof(struct cloop_header), pp->sectorsize); - buf = g_read_data(cp, 0, i, NULL); + total = roundup(sizeof(struct cloop_header), pp->sectorsize); + buf = g_read_data(cp, 0, total, NULL); if (buf == NULL) goto err; header = (struct cloop_header *) buf; @@ -557,20 +558,29 @@ g_uncompress_taste(struct g_class *mp, struct g_provider *pp, int flags) gp->name, sc->nblocks); goto err; } - free(buf, M_GEOM); + g_free(buf); - i = roundup((sizeof(struct cloop_header) + - total_offsets * sizeof(uint64_t)), pp->sectorsize); - buf = g_read_data(cp, 0, i, NULL); - if (buf == NULL) - goto err; sc->offsets = malloc(total_offsets * sizeof(uint64_t), - M_GEOM_UNCOMPRESS, M_WAITOK); - for (i = 0; i <= total_offsets; i++) { - sc->offsets[i] = be64toh(((uint64_t *) - (buf+sizeof(struct cloop_header)))[i]); + M_GEOM_UNCOMPRESS, M_WAITOK | M_ZERO); + total = roundup((sizeof(struct cloop_header) + + total_offsets * sizeof(uint64_t)), pp->sectorsize); +#define RSZ ((total - r) > MAXPHYS ? MAXPHYS: (total - r)) + for (r = 0, i = 0; r < total; r += MAXPHYS) { + buf = g_read_data(cp, r, RSZ, &error); + if (buf == NULL) { + free(sc->offsets, M_GEOM_UNCOMPRESS); + goto err; + } + offsets = (uint64_t *)buf; + if (r == 0) + offsets += + sizeof(struct cloop_header) / sizeof(uint64_t); + for (; i < total_offsets && offsets < (uint64_t *)(buf + RSZ); + i++, offsets++) + sc->offsets[i] = be64toh(*offsets); + g_free(buf); } - free(buf, M_GEOM); +#undef RSZ buf = NULL; DPRINTF(("%s: done reading offsets\n", gp->name)); mtx_init(&sc->last_mtx, "geom_uncompress cache", NULL, MTX_DEF); @@ -619,7 +629,7 @@ err: g_topology_lock(); g_access(cp, -1, 0, 0); if (buf != NULL) - free(buf, M_GEOM); + g_free(buf); if (gp->softc != NULL) { g_uncompress_softc_free(gp->softc, NULL); gp->softc = NULL; |