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. Quoting r264504: When we detect the condition, we'll reduce the block count and perform a "short" read. In g_uncompress_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. Reviewed by: marcel
This commit is contained in:
parent
82c2c89084
commit
6f05733a1f
@ -169,7 +169,7 @@ g_uncompress_done(struct bio *bp)
|
||||
struct g_geom *gp;
|
||||
struct bio *bp2;
|
||||
uint32_t start_blk, i;
|
||||
off_t pos, upos;
|
||||
off_t iolen, pos, upos;
|
||||
size_t bsize;
|
||||
int err;
|
||||
|
||||
@ -210,6 +210,7 @@ g_uncompress_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;
|
||||
|
||||
@ -239,6 +240,13 @@ g_uncompress_done(struct bio *bp)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len > iolen) {
|
||||
DPRINTF(("%s: done: early termination: len (%jd) > "
|
||||
"iolen (%jd)\n",
|
||||
gp->name, (intmax_t)len, (intmax_t)iolen));
|
||||
break;
|
||||
}
|
||||
|
||||
mtx_lock(&sc->last_mtx);
|
||||
|
||||
#ifdef GEOM_UNCOMPRESS_DEBUG
|
||||
@ -292,6 +300,7 @@ g_uncompress_done(struct bio *bp)
|
||||
mtx_unlock(&sc->last_mtx);
|
||||
|
||||
pos += len;
|
||||
iolen -= len;
|
||||
upos += ulen;
|
||||
bp2->bio_completed += ulen;
|
||||
}
|
||||
@ -380,10 +389,18 @@ g_uncompress_start(struct bio *bp)
|
||||
bsize = pp2->sectorsize;
|
||||
|
||||
bp2->bio_done = g_uncompress_done;
|
||||
bp2->bio_offset = rounddown(sc->offsets[start_blk],bsize);
|
||||
bp2->bio_length = roundup(sc->offsets[end_blk],bsize) -
|
||||
bp2->bio_offset;
|
||||
bp2->bio_data = malloc(bp2->bio_length, M_GEOM_UNCOMPRESS, M_NOWAIT);
|
||||
bp2->bio_offset = rounddown(sc->offsets[start_blk], bsize);
|
||||
while (1) {
|
||||
bp2->bio_length = roundup(sc->offsets[end_blk], bsize) -
|
||||
bp2->bio_offset;
|
||||
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,
|
||||
@ -392,6 +409,7 @@ g_uncompress_start(struct bio *bp)
|
||||
(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_UNCOMPRESS, M_NOWAIT);
|
||||
if (bp2->bio_data == NULL) {
|
||||
g_destroy_bio(bp2);
|
||||
g_io_deliver(bp, ENOMEM);
|
||||
|
Loading…
Reference in New Issue
Block a user