Fix aggregating geoms for BIO_SPEEDUP.

If the bio was split into several bios going down, completion computes
bio_completed of the original bio as sum of the bio_completes of the
splits.  For BIO_SETUP, bio_length means something different than the
length. it is the requested speedup amount, and is duplicated into the
splits, which is in fact reasonable, since we cannot know how the
previous activity was distributed among subordinate geoms.  Obviously,
the sum of n bio_length is greater than bio_length for n > 1, which
triggers assert that bio_length >= bio_completed for e.g. geom_stripe
and geom_raid3.

Fix this by reassigning bio_completed from bio_length for completed
BIO_SPEEDED, I do not think it really mattters what we return in
bio_completed.

Reported and tested by:	pho
Reviewed by:	imp
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D23380
This commit is contained in:
Konstantin Belousov 2020-01-27 13:15:16 +00:00
parent d2c32def56
commit fd99699d7e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=357172
2 changed files with 6 additions and 1 deletions

View file

@ -1134,8 +1134,11 @@ g_std_done(struct bio *bp)
bp2->bio_completed += bp->bio_completed;
g_destroy_bio(bp);
bp2->bio_inbed++;
if (bp2->bio_children == bp2->bio_inbed)
if (bp2->bio_children == bp2->bio_inbed) {
if (bp2->bio_cmd == BIO_SPEEDUP)
bp2->bio_completed = bp2->bio_length;
g_io_deliver(bp2, bp2->bio_error);
}
}
/* XXX: maybe this is only g_slice_spoiled */

View file

@ -298,6 +298,8 @@ g_stripe_done(struct bio *bp)
mtx_unlock(&sc->sc_lock);
if (pbp->bio_driver1 != NULL)
uma_zfree(g_stripe_zone, pbp->bio_driver1);
if (bp->bio_cmd == BIO_SPEEDUP)
pbp->bio_completed = pbp->bio_length;
g_io_deliver(pbp, pbp->bio_error);
} else
mtx_unlock(&sc->sc_lock);