diff options
author | peadar <peadar@FreeBSD.org> | 2005-10-09 21:11:05 +0000 |
---|---|---|
committer | peadar <peadar@FreeBSD.org> | 2005-10-09 21:11:05 +0000 |
commit | 60fb64c30e9b2c543b4e89c17d7ee8d4570e9dcc (patch) | |
tree | 48f1adfdb334dd861d074d9c38e23b6c53d6c5c0 /sys/dev/ata/atapi-cd.c | |
parent | 6210e62129dd5f6332e7445b51c62f600aeb5c74 (diff) | |
download | FreeBSD-src-60fb64c30e9b2c543b4e89c17d7ee8d4570e9dcc.zip FreeBSD-src-60fb64c30e9b2c543b4e89c17d7ee8d4570e9dcc.tar.gz |
When breaking up a large request into smaller ones for the strategy
routine, create all the child bio objects before starting the
requests, rather than starting them as created. This closes a race
whereby some number of child operations could complete before the
rest were ever created, and prematurely freeing the parent bio.
This fixes the panics installing in VMWare and qemu
Diffstat (limited to 'sys/dev/ata/atapi-cd.c')
-rw-r--r-- | sys/dev/ata/atapi-cd.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index 16a188a..f737fe3 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -760,7 +760,7 @@ acd_geom_start(struct bio *bp) } else { u_int pos, size = cdp->iomax - cdp->iomax % bp->bio_to->sectorsize; - struct bio *bp2; + struct bio *bp2, *first, **next = &first; for (pos = 0; pos < bp->bio_length; pos += size) { if (!(bp2 = g_clone_bio(bp))) { @@ -773,6 +773,12 @@ acd_geom_start(struct bio *bp) bp2->bio_data += pos; bp2->bio_length = MIN(size, bp->bio_length - pos); bp2->bio_pblkno = bp2->bio_offset / bp2->bio_to->sectorsize; + *next = bp2; + next = (struct bio **)&bp2->bio_driver1; + } + *next = NULL; + while ((bp2 = first) != NULL) { + first = (struct bio *)bp2->bio_driver1; acd_strategy(bp2); } } |