diff options
author | loos <loos@FreeBSD.org> | 2014-05-16 14:28:55 +0000 |
---|---|---|
committer | loos <loos@FreeBSD.org> | 2014-05-16 14:28:55 +0000 |
commit | 058ac53f3fed1564d8cecfb570d0fbfa2cab8802 (patch) | |
tree | b14a08bae03e2fc4c713332584ca699f4e25b653 /sys/geom/uzip/g_uzip.c | |
parent | c5659dcd16ed886ea681d541edb63efd092e73ff (diff) | |
download | FreeBSD-src-058ac53f3fed1564d8cecfb570d0fbfa2cab8802.zip FreeBSD-src-058ac53f3fed1564d8cecfb570d0fbfa2cab8802.tar.gz |
MFC r260522, r260523, r261439, r261440, r261586, r264504, r264769, r265193,
r265194, r265197
r260522:
Add the manual page for geom_uncompress(4).
r260523:
Build the geom_uncompress(4) module by default.
Fix geom_uncompress(4) module loading. Don't link zlib.c (which is a module
itself) directly.
r261439:
Remove some unnecessary code. The offsets read from the first block are
overwritten a few lines bellow.
r261440:
Fix a logic error. Because of this inflateReset() wasn't being called and
the output buffer wasn't being cleared between the inflate() calls,
producing zeroed output after the first inflate() call.
This fixes the read of mkuzip(8) images with geom_uncompress(4).
r261586:
Fix the build with DEBUG enabled. Where possible, fix style(9) issues.
r264504:
Make sure not to do I/O for more than MAXPHYS bytes. Doing so can cause
problems in our providers, such as a KASSERT in md(4). We can initiate
I/O for more than MAXPHYS bytes if we've been given a BIO for MAXPHYS
bytes, the blocks from which we're reading couldn't be compressed and
we had compression in preceeding blocks resulting in misalignment of
the blocks we're trying to read relative to the sector. We're forced to
round up the I/O length to make it an multiple of the sector size.
When we detect the condition, we'll reduce the block count and perform
a "short" read. In g_uzip_done() we need to consider the original I/O
length and stop early if we're about to deflate a block that we didn't
read. By using bio_completed in the cloned BIO and not bio_length to
check for this, we automatically and gracefully handle short reads that
our providers may be doing on top of the short reads we may initiate
ourselves.
r264769:
Keep geom_uncompress(4) in line with geom_uzip(4), bring in the r264504 fix.
Make sure not to start I/O bigger than MAXPHYS bytes.
r265193:
Some style and whitespace fixes. Reduce the difference between geom_uzip(4)
and geom_uncompress(4). Now, they produce an almost clean diff(1) output.
Remove a duplicated variable from g_uncompress.c and an unnecessary header
from g_uzip.c.
r265194:
Actually the FEATURE() macro is defined on sys/sysctl.h.
r265197:
Fix a leak in g_uzip_taste(). After retrieve all the block offsets from
the uzip image, free the last data read.
Diffstat (limited to 'sys/geom/uzip/g_uzip.c')
-rw-r--r-- | sys/geom/uzip/g_uzip.c | 125 |
1 files changed, 75 insertions, 50 deletions
diff --git a/sys/geom/uzip/g_uzip.c b/sys/geom/uzip/g_uzip.c index 917789f..1dacfa0 100644 --- a/sys/geom/uzip/g_uzip.c +++ b/sys/geom/uzip/g_uzip.c @@ -35,8 +35,8 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/mutex.h> #include <sys/malloc.h> -#include <sys/systm.h> #include <sys/sysctl.h> +#include <sys/systm.h> #include <geom/geom.h> #include <net/zlib.h> @@ -45,19 +45,19 @@ FEATURE(geom_uzip, "GEOM uzip read-only compressed disks support"); #undef GEOM_UZIP_DEBUG #ifdef GEOM_UZIP_DEBUG -#define DPRINTF(a) printf a +#define DPRINTF(a) printf a #else -#define DPRINTF(a) +#define DPRINTF(a) #endif static MALLOC_DEFINE(M_GEOM_UZIP, "geom_uzip", "GEOM UZIP data structures"); -#define UZIP_CLASS_NAME "UZIP" +#define UZIP_CLASS_NAME "UZIP" /* * Maximum allowed valid block size (to prevent foot-shooting) */ -#define MAX_BLKSZ (MAXPHYS - MAXPHYS / 1000 - 12) +#define MAX_BLKSZ (MAXPHYS - MAXPHYS / 1000 - 12) /* * Integer values (block size, number of blocks, offsets) @@ -65,7 +65,7 @@ static MALLOC_DEFINE(M_GEOM_UZIP, "geom_uzip", "GEOM UZIP data structures"); * and in native order in struct g_uzip_softc */ -#define CLOOP_MAGIC_LEN 128 +#define CLOOP_MAGIC_LEN 128 static char CLOOP_MAGIC_START[] = "#!/bin/sh\n"; struct cloop_header { @@ -89,12 +89,15 @@ struct g_uzip_softc { static void g_uzip_softc_free(struct g_uzip_softc *sc, struct g_geom *gp) { + if (gp != NULL) { printf("%s: %d requests, %d cached\n", gp->name, sc->req_total, sc->req_cached); } - if (sc->offsets != NULL) + if (sc->offsets != NULL) { free(sc->offsets, M_GEOM_UZIP); + sc->offsets = NULL; + } mtx_destroy(&sc->last_mtx); free(sc->last_buf, M_GEOM_UZIP); free(sc, M_GEOM_UZIP); @@ -106,12 +109,14 @@ z_alloc(void *nil, u_int type, u_int size) void *ptr; ptr = malloc(type * size, M_GEOM_UZIP, M_NOWAIT); - return ptr; + + return (ptr); } static void z_free(void *nil, void *ptr) { + free(ptr, M_GEOM_UZIP); } @@ -125,7 +130,7 @@ g_uzip_done(struct bio *bp) struct g_consumer *cp; struct g_geom *gp; struct g_uzip_softc *sc; - off_t pos, upos; + off_t iolen, pos, upos; uint32_t start_blk, i; size_t bsize; @@ -153,11 +158,13 @@ g_uzip_done(struct bio *bp) } start_blk = bp2->bio_offset / sc->blksz; bsize = pp2->sectorsize; + iolen = bp->bio_completed; pos = sc->offsets[start_blk] % bsize; upos = 0; - DPRINTF(("%s: done: start_blk %d, pos %lld, upos %lld (%lld, %d, %d)\n", - gp->name, start_blk, pos, upos, - bp2->bio_offset, sc->blksz, bsize)); + DPRINTF(("%s: done: start_blk %d, pos %jd, upos %jd, iolen %jd " + "(%jd, %d, %zd)\n", + gp->name, start_blk, (intmax_t)pos, (intmax_t)upos, + (intmax_t)iolen, (intmax_t)bp2->bio_offset, sc->blksz, bsize)); for (i = start_blk; upos < bp2->bio_length; i++) { off_t len, ulen, uoff; @@ -172,6 +179,12 @@ g_uzip_done(struct bio *bp) bp2->bio_completed += ulen; continue; } + if (len > iolen) { + DPRINTF(("%s: done: early termination: len (%jd) > " + "iolen (%jd)\n", + gp->name, (intmax_t)len, (intmax_t)iolen)); + break; + } zs.next_in = bp->bio_data + pos; zs.avail_in = len; zs.next_out = sc->last_buf; @@ -181,21 +194,22 @@ g_uzip_done(struct bio *bp) if (err != Z_STREAM_END) { sc->last_blk = -1; mtx_unlock(&sc->last_mtx); - DPRINTF(("%s: done: inflate failed (%lld + %lld -> %lld + %lld + %lld)\n", - gp->name, pos, len, uoff, upos, ulen)); + DPRINTF(("%s: done: inflate failed (%jd + %jd -> %jd + %jd + %jd)\n", + gp->name, (intmax_t)pos, (intmax_t)len, + (intmax_t)uoff, (intmax_t)upos, (intmax_t)ulen)); inflateEnd(&zs); bp2->bio_error = EIO; goto done; } sc->last_blk = i; - DPRINTF(("%s: done: inflated %lld + %lld -> %lld + %lld + %lld\n", - gp->name, - pos, len, - uoff, upos, ulen)); + DPRINTF(("%s: done: inflated %jd + %jd -> %jd + %jd + %jd\n", + gp->name, (intmax_t)pos, (intmax_t)len, (intmax_t)uoff, + (intmax_t)upos, (intmax_t)ulen)); memcpy(bp2->bio_data + upos, sc->last_buf + uoff, ulen); mtx_unlock(&sc->last_mtx); pos += len; + iolen -= len; upos += ulen; bp2->bio_completed += ulen; err = inflateReset(&zs); @@ -215,8 +229,9 @@ done: /* * Finish processing the request. */ - DPRINTF(("%s: done: (%d, %lld, %ld)\n", - gp->name, bp2->bio_error, bp2->bio_completed, bp2->bio_resid)); + DPRINTF(("%s: done: (%d, %jd, %ld)\n", + gp->name, bp2->bio_error, (intmax_t)bp2->bio_completed, + bp2->bio_resid)); free(bp->bio_data, M_GEOM_UZIP); g_destroy_bio(bp); g_io_deliver(bp2, bp2->bio_error); @@ -248,10 +263,8 @@ g_uzip_start(struct bio *bp) start_blk = bp->bio_offset / sc->blksz; end_blk = (bp->bio_offset + bp->bio_length + sc->blksz - 1) / sc->blksz; - KASSERT(start_blk < sc->nblocks, - ("start_blk out of range")); - KASSERT(end_blk <= sc->nblocks, - ("end_blk out of range")); + KASSERT(start_blk < sc->nblocks, ("start_blk out of range")); + KASSERT(end_blk <= sc->nblocks, ("end_blk out of range")); sc->req_total++; if (start_blk + 1 == end_blk) { @@ -267,8 +280,9 @@ g_uzip_start(struct bio *bp) sc->req_cached++; mtx_unlock(&sc->last_mtx); - DPRINTF(("%s: start: cached 0 + %lld, %lld + 0 + %lld\n", - gp->name, bp->bio_length, uoff, bp->bio_length)); + DPRINTF(("%s: start: cached 0 + %jd, %jd + 0 + %jd\n", + gp->name, (intmax_t)bp->bio_length, (intmax_t)uoff, + (intmax_t)bp->bio_length)); bp->bio_completed = bp->bio_length; g_io_deliver(bp, 0); return; @@ -282,19 +296,28 @@ g_uzip_start(struct bio *bp) return; } bp2->bio_done = g_uzip_done; - DPRINTF(("%s: start (%d..%d), %s: %d + %lld, %s: %d + %lld\n", + DPRINTF(("%s: start (%d..%d), %s: %d + %jd, %s: %d + %jd\n", gp->name, start_blk, end_blk, - pp->name, pp->sectorsize, pp->mediasize, - pp2->name, pp2->sectorsize, pp2->mediasize)); + pp->name, pp->sectorsize, (intmax_t)pp->mediasize, + pp2->name, pp2->sectorsize, (intmax_t)pp2->mediasize)); bsize = pp2->sectorsize; bp2->bio_offset = sc->offsets[start_blk] - sc->offsets[start_blk] % bsize; - bp2->bio_length = sc->offsets[end_blk] - bp2->bio_offset; - bp2->bio_length = (bp2->bio_length + bsize - 1) / bsize * bsize; - DPRINTF(("%s: start %lld + %lld -> %lld + %lld -> %lld + %lld\n", + while (1) { + bp2->bio_length = sc->offsets[end_blk] - bp2->bio_offset; + bp2->bio_length = (bp2->bio_length + bsize - 1) / bsize * bsize; + if (bp2->bio_length < MAXPHYS) + break; + + end_blk--; + DPRINTF(("%s: bio_length (%jd) > MAXPHYS: lowering end_blk " + "to %u\n", gp->name, (intmax_t)bp2->bio_length, end_blk)); + } + DPRINTF(("%s: start %jd + %jd -> %ju + %ju -> %jd + %jd\n", gp->name, - bp->bio_offset, bp->bio_length, - sc->offsets[start_blk], sc->offsets[end_blk] - sc->offsets[start_blk], - bp2->bio_offset, bp2->bio_length)); + (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length, + (uintmax_t)sc->offsets[start_blk], + (uintmax_t)sc->offsets[end_blk] - sc->offsets[start_blk], + (intmax_t)bp2->bio_offset, (intmax_t)bp2->bio_length)); bp2->bio_data = malloc(bp2->bio_length, M_GEOM_UZIP, M_NOWAIT); if (bp2->bio_data == NULL) { g_destroy_bio(bp2); @@ -311,7 +334,7 @@ g_uzip_orphan(struct g_consumer *cp) { struct g_geom *gp; - g_trace(G_T_TOPOLOGY, "g_uzip_orphan(%p/%s)", cp, cp->provider->name); + g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, cp->provider->name); g_topology_assert(); gp = cp->geom; @@ -331,7 +354,7 @@ g_uzip_access(struct g_provider *pp, int dr, int dw, int de) KASSERT (cp != NULL, ("g_uzip_access but no consumer")); if (cp->acw + dw > 0) - return EROFS; + return (EROFS); return (g_access(cp, dr, dw, de)); } @@ -342,7 +365,7 @@ g_uzip_spoiled(struct g_consumer *cp) struct g_geom *gp; gp = cp->geom; - g_trace(G_T_TOPOLOGY, "g_uzip_spoiled(%p/%s)", cp, gp->name); + g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, gp->name); g_topology_assert(); g_uzip_softc_free(gp->softc, gp); @@ -362,7 +385,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) struct g_provider *pp2; struct g_uzip_softc *sc; - g_trace(G_T_TOPOLOGY, "g_uzip_taste(%s,%s)", mp->name, pp->name); + g_trace(G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name); g_topology_assert(); /* Skip providers that are already open for writing. */ @@ -391,14 +414,14 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) * Read cloop header, look for CLOOP magic, perform * other validity checks. */ - DPRINTF(("%s: media sectorsize %u, mediasize %lld\n", - gp->name, pp->sectorsize, pp->mediasize)); + DPRINTF(("%s: media sectorsize %u, mediasize %jd\n", + gp->name, pp->sectorsize, (intmax_t)pp->mediasize)); buf = g_read_data(cp, 0, pp->sectorsize, NULL); if (buf == NULL) goto err; header = (struct cloop_header *) buf; if (strncmp(header->magic, CLOOP_MAGIC_START, - sizeof(CLOOP_MAGIC_START) - 1) != 0) { + sizeof(CLOOP_MAGIC_START) - 1) != 0) { DPRINTF(("%s: no CLOOP magic\n", gp->name)); goto err; } @@ -427,7 +450,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) if (sizeof(struct cloop_header) + total_offsets * sizeof(uint64_t) > pp->mediasize) { printf("%s: media too small for %u blocks\n", - gp->name, sc->nblocks); + gp->name, sc->nblocks); goto err; } sc->offsets = malloc( @@ -456,6 +479,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) } offsets_read += nread; } + free(buf, M_GEOM); DPRINTF(("%s: done reading offsets\n", gp->name)); mtx_init(&sc->last_mtx, "geom_uzip cache", NULL, MTX_DEF); sc->last_blk = -1; @@ -467,17 +491,16 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) pp2 = g_new_providerf(gp, "%s", gp->name); pp2->sectorsize = 512; pp2->mediasize = (off_t)sc->nblocks * sc->blksz; - pp2->stripesize = pp->stripesize; - pp2->stripeoffset = pp->stripeoffset; + pp2->stripesize = pp->stripesize; + pp2->stripeoffset = pp->stripeoffset; g_error_provider(pp2, 0); g_access(cp, -1, 0, 0); - DPRINTF(("%s: taste ok (%d, %lld), (%d, %d), %x\n", + DPRINTF(("%s: taste ok (%d, %jd), (%d, %d), %x\n", gp->name, - pp2->sectorsize, pp2->mediasize, + pp2->sectorsize, (intmax_t)pp2->mediasize, pp2->stripeoffset, pp2->stripesize, pp2->flags)); - printf("%s: %u x %u blocks\n", - gp->name, sc->nblocks, sc->blksz); + printf("%s: %u x %u blocks\n", gp->name, sc->nblocks, sc->blksz); return (gp); err: @@ -492,6 +515,7 @@ err: g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); + return (NULL); } @@ -500,7 +524,7 @@ g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) { struct g_provider *pp; - g_trace(G_T_TOPOLOGY, "g_uzip_destroy_geom(%s, %s)", mp->name, gp->name); + g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, gp->name); g_topology_assert(); if (gp->softc == NULL) { @@ -517,6 +541,7 @@ g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) g_uzip_softc_free(gp->softc, gp); gp->softc = NULL; g_wither_geom(gp, ENXIO); + return (0); } |