svn commit: r264504 - head/sys/geom/uzip

Marcel Moolenaar marcel at FreeBSD.org
Tue Apr 15 15:41:58 UTC 2014


Author: marcel
Date: Tue Apr 15 15:41:57 2014
New Revision: 264504
URL: http://svnweb.freebsd.org/changeset/base/264504

Log:
  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.
  
  Obtained from:	Juniper Networks, Inc.

Modified:
  head/sys/geom/uzip/g_uzip.c

Modified: head/sys/geom/uzip/g_uzip.c
==============================================================================
--- head/sys/geom/uzip/g_uzip.c	Tue Apr 15 15:20:37 2014	(r264503)
+++ head/sys/geom/uzip/g_uzip.c	Tue Apr 15 15:41:57 2014	(r264504)
@@ -125,7 +125,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 +153,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 %jd, upos %jd (%jd, %d, %zd)\n",
+	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)bp2->bio_offset, sc->blksz, bsize));
+	    (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 +174,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;
@@ -196,6 +204,7 @@ g_uzip_done(struct bio *bp)
 		mtx_unlock(&sc->last_mtx);
 
 		pos += len;
+		iolen -= len;
 		upos += ulen;
 		bp2->bio_completed += ulen;
 		err = inflateReset(&zs);
@@ -290,8 +299,16 @@ g_uzip_start(struct bio *bp)
 	    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;
+	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,
 	    (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length,


More information about the svn-src-head mailing list