Author: loos
Date: Tue Apr 22 18:08:34 2014
New Revision: 264769
URL: http://svnweb.freebsd.org/changeset/base/264769

Log:
  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

Modified:
  head/sys/geom/uncompress/g_uncompress.c

Modified: head/sys/geom/uncompress/g_uncompress.c
==============================================================================
--- head/sys/geom/uncompress/g_uncompress.c     Tue Apr 22 16:13:56 2014        
(r264768)
+++ head/sys/geom/uncompress/g_uncompress.c     Tue Apr 22 18:08:34 2014        
(r264769)
@@ -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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to