diff --git a/qemu-dma-aio-cancellation1.patch b/qemu-dma-aio-cancellation1.patch new file mode 100644 index 0000000..a8b57cd --- /dev/null +++ b/qemu-dma-aio-cancellation1.patch @@ -0,0 +1,96 @@ +From 3b92e958482155404cfd134a9608041eed69622a Mon Sep 17 00:00:00 2001 +From: Avi Kivity +Date: Fri, 20 Mar 2009 18:26:12 +0000 +Subject: [STABLE][PATCH 1/4] Use vectored aiocb storage to store vector translation state + +Now that we have a dedicated acb pool for vector translation acbs, we can +store the vector translation state in the acbs instead of in an external +structure. + +Signed-off-by: Avi Kivity + +--- + block.c | 29 ++++++++++++++--------------- + 1 files changed, 14 insertions(+), 15 deletions(-) + +diff --git a/block.c b/block.c +index b12318f..689ea37 100644 +--- a/block.c ++++ b/block.c +@@ -1332,31 +1332,32 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) + /**************************************************************/ + /* async I/Os */ + +-typedef struct VectorTranslationState { ++typedef struct VectorTranslationAIOCB { ++ BlockDriverAIOCB common; + QEMUIOVector *iov; + uint8_t *bounce; + int is_write; + BlockDriverAIOCB *aiocb; +- BlockDriverAIOCB *this_aiocb; +-} VectorTranslationState; ++} VectorTranslationAIOCB; + +-static void bdrv_aio_cancel_vector(BlockDriverAIOCB *acb) ++static void bdrv_aio_cancel_vector(BlockDriverAIOCB *_acb) + { +- VectorTranslationState *s = acb->opaque; ++ VectorTranslationAIOCB *acb ++ = container_of(_acb, VectorTranslationAIOCB, common); + +- bdrv_aio_cancel(s->aiocb); ++ bdrv_aio_cancel(acb->aiocb); + } + + static void bdrv_aio_rw_vector_cb(void *opaque, int ret) + { +- VectorTranslationState *s = opaque; ++ VectorTranslationAIOCB *s = (VectorTranslationAIOCB *)opaque; + + if (!s->is_write) { + qemu_iovec_from_buffer(s->iov, s->bounce, s->iov->size); + } + qemu_vfree(s->bounce); +- s->this_aiocb->cb(s->this_aiocb->opaque, ret); +- qemu_aio_release(s->this_aiocb); ++ s->common.cb(s->common.opaque, ret); ++ qemu_aio_release(s); + } + + static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, +@@ -1368,11 +1369,9 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, + int is_write) + + { +- VectorTranslationState *s = qemu_mallocz(sizeof(*s)); +- BlockDriverAIOCB *aiocb = qemu_aio_get_pool(&vectored_aio_pool, bs, +- cb, opaque); ++ VectorTranslationAIOCB *s = qemu_aio_get_pool(&vectored_aio_pool, bs, ++ cb, opaque); + +- s->this_aiocb = aiocb; + s->iov = iov; + s->bounce = qemu_memalign(512, nb_sectors * 512); + s->is_write = is_write; +@@ -1384,7 +1383,7 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, + s->aiocb = bdrv_aio_read(bs, sector_num, s->bounce, nb_sectors, + bdrv_aio_rw_vector_cb, s); + } +- return aiocb; ++ return &s->common; + } + + BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, +@@ -1560,7 +1559,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, + + void bdrv_init(void) + { +- aio_pool_init(&vectored_aio_pool, sizeof(BlockDriverAIOCB), ++ aio_pool_init(&vectored_aio_pool, sizeof(VectorTranslationAIOCB), + bdrv_aio_cancel_vector); + + bdrv_register(&bdrv_raw); +-- +1.6.0.6 + diff --git a/qemu-dma-aio-cancellation2.patch b/qemu-dma-aio-cancellation2.patch new file mode 100644 index 0000000..33fbe38 --- /dev/null +++ b/qemu-dma-aio-cancellation2.patch @@ -0,0 +1,137 @@ +From b591f5930d0eaa93690c5a7acf95e4f5a3e04e06 Mon Sep 17 00:00:00 2001 +From: Avi Kivity +Date: Fri, 20 Mar 2009 18:26:16 +0000 +Subject: [STABLE][PATCH 2/4] Move block dma helpers aiocb to store dma state + +Use the dedicated dma aiocb to store intermediate state for dma block +transactions. + +Signed-off-by: Avi Kivity + +--- + dma-helpers.c | 37 ++++++++++++++++++++----------------- + 1 files changed, 20 insertions(+), 17 deletions(-) + +diff --git a/dma-helpers.c b/dma-helpers.c +index 19fa4f0..96a120c 100644 +--- a/dma-helpers.c ++++ b/dma-helpers.c +@@ -39,6 +39,7 @@ void qemu_sglist_destroy(QEMUSGList *qsg) + } + + typedef struct { ++ BlockDriverAIOCB common; + BlockDriverState *bs; + BlockDriverAIOCB *acb; + QEMUSGList *sg; +@@ -48,13 +49,13 @@ typedef struct { + target_phys_addr_t sg_cur_byte; + QEMUIOVector iov; + QEMUBH *bh; +-} DMABlockState; ++} DMAAIOCB; + + static void dma_bdrv_cb(void *opaque, int ret); + + static void reschedule_dma(void *opaque) + { +- DMABlockState *dbs = (DMABlockState *)opaque; ++ DMAAIOCB *dbs = (DMAAIOCB *)opaque; + + qemu_bh_delete(dbs->bh); + dbs->bh = NULL; +@@ -63,7 +64,7 @@ static void reschedule_dma(void *opaque) + + static void continue_after_map_failure(void *opaque) + { +- DMABlockState *dbs = (DMABlockState *)opaque; ++ DMAAIOCB *dbs = (DMAAIOCB *)opaque; + + dbs->bh = qemu_bh_new(reschedule_dma, dbs); + qemu_bh_schedule(dbs->bh); +@@ -71,11 +72,12 @@ static void continue_after_map_failure(void *opaque) + + static void dma_bdrv_cb(void *opaque, int ret) + { +- DMABlockState *dbs = (DMABlockState *)opaque; ++ DMAAIOCB *dbs = (DMAAIOCB *)opaque; + target_phys_addr_t cur_addr, cur_len; + void *mem; + int i; + ++ dbs->acb = NULL; + dbs->sector_num += dbs->iov.size / 512; + for (i = 0; i < dbs->iov.niov; ++i) { + cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base, +@@ -85,10 +87,9 @@ static void dma_bdrv_cb(void *opaque, int ret) + qemu_iovec_reset(&dbs->iov); + + if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) { +- dbs->acb->cb(dbs->acb->opaque, ret); ++ dbs->common.cb(dbs->common.opaque, ret); + qemu_iovec_destroy(&dbs->iov); +- qemu_aio_release(dbs->acb); +- qemu_free(dbs); ++ qemu_aio_release(dbs); + return; + } + +@@ -112,11 +113,11 @@ static void dma_bdrv_cb(void *opaque, int ret) + } + + if (dbs->is_write) { +- bdrv_aio_writev(dbs->bs, dbs->sector_num, &dbs->iov, +- dbs->iov.size / 512, dma_bdrv_cb, dbs); ++ dbs->acb = bdrv_aio_writev(dbs->bs, dbs->sector_num, &dbs->iov, ++ dbs->iov.size / 512, dma_bdrv_cb, dbs); + } else { +- bdrv_aio_readv(dbs->bs, dbs->sector_num, &dbs->iov, +- dbs->iov.size / 512, dma_bdrv_cb, dbs); ++ dbs->acb = bdrv_aio_readv(dbs->bs, dbs->sector_num, &dbs->iov, ++ dbs->iov.size / 512, dma_bdrv_cb, dbs); + } + } + +@@ -125,10 +126,10 @@ static BlockDriverAIOCB *dma_bdrv_io( + BlockDriverCompletionFunc *cb, void *opaque, + int is_write) + { +- DMABlockState *dbs = qemu_malloc(sizeof(*dbs)); ++ DMAAIOCB *dbs = qemu_aio_get_pool(&dma_aio_pool, bs, cb, opaque); + ++ dbs->acb = NULL; + dbs->bs = bs; +- dbs->acb = qemu_aio_get_pool(&dma_aio_pool, bs, cb, opaque); + dbs->sg = sg; + dbs->sector_num = sector_num; + dbs->sg_cur_index = 0; +@@ -137,7 +138,7 @@ static BlockDriverAIOCB *dma_bdrv_io( + dbs->bh = NULL; + qemu_iovec_init(&dbs->iov, sg->nsg); + dma_bdrv_cb(dbs, 0); +- return dbs->acb; ++ return &dbs->common; + } + + +@@ -157,12 +158,14 @@ BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs, + + static void dma_aio_cancel(BlockDriverAIOCB *acb) + { +- DMABlockState *dbs = (DMABlockState *)acb->opaque; ++ DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common); + +- bdrv_aio_cancel(dbs->acb); ++ if (dbs->acb) { ++ bdrv_aio_cancel(dbs->acb); ++ } + } + + void dma_helper_init(void) + { +- aio_pool_init(&dma_aio_pool, sizeof(BlockDriverAIOCB), dma_aio_cancel); ++ aio_pool_init(&dma_aio_pool, sizeof(DMAAIOCB), dma_aio_cancel); + } +-- +1.6.0.6 + diff --git a/qemu-dma-aio-cancellation3.patch b/qemu-dma-aio-cancellation3.patch new file mode 100644 index 0000000..1fe1fd0 --- /dev/null +++ b/qemu-dma-aio-cancellation3.patch @@ -0,0 +1,37 @@ +From 2df6efa1790a7a2894707257d2fe67b8d1cfb13a Mon Sep 17 00:00:00 2001 +From: Avi Kivity +Date: Sat, 28 Mar 2009 16:11:20 +0000 +Subject: [STABLE][PATCH 3/4] Fix vectored aio bounce handling immediate errors + +If a bounced vectored aio fails immediately (the inner aio submission +returning NULL) then the bounce handler erronously returns an aio +request which will never be completed (and which crashes when cancelled). + +Fix by detecting that the inner request has failed and propagating the +error. + +Signed-off-by: Avi Kivity + +--- + block.c | 5 +++++ + 1 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/block.c b/block.c +index 689ea37..b68a8da 100644 +--- a/block.c ++++ b/block.c +@@ -1383,6 +1383,11 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, + s->aiocb = bdrv_aio_read(bs, sector_num, s->bounce, nb_sectors, + bdrv_aio_rw_vector_cb, s); + } ++ if (!s->aiocb) { ++ qemu_vfree(s->bounce); ++ qemu_aio_release(s); ++ return NULL; ++ } + return &s->common; + } + +-- +1.6.0.6 + diff --git a/qemu-dma-aio-cancellation4.patch b/qemu-dma-aio-cancellation4.patch new file mode 100644 index 0000000..bb993eb --- /dev/null +++ b/qemu-dma-aio-cancellation4.patch @@ -0,0 +1,81 @@ +From eaa874771bb83df639e2937884240a6b05622e3f Mon Sep 17 00:00:00 2001 +From: Avi Kivity +Date: Sat, 28 Mar 2009 16:11:25 +0000 +Subject: [STABLE][PATCH 4/4] Fix DMA API when handling an immediate error from block layer + +The block layer may signal an immediate error on an asynchronous request +by returning NULL. The DMA API did not handle this correctly, returning +an AIO request which would never complete (and which would crash if +cancelled). + +Fix by detecting the failure and propagating it. + +Signed-off-by: Avi Kivity + +--- + dma-helpers.c | 27 +++++++++++++++++++++------ + 1 files changed, 21 insertions(+), 6 deletions(-) + +diff --git a/dma-helpers.c b/dma-helpers.c +index 96a120c..1469e34 100644 +--- a/dma-helpers.c ++++ b/dma-helpers.c +@@ -70,20 +70,26 @@ static void continue_after_map_failure(void *opaque) + qemu_bh_schedule(dbs->bh); + } + +-static void dma_bdrv_cb(void *opaque, int ret) ++static void dma_bdrv_unmap(DMAAIOCB *dbs) + { +- DMAAIOCB *dbs = (DMAAIOCB *)opaque; +- target_phys_addr_t cur_addr, cur_len; +- void *mem; + int i; + +- dbs->acb = NULL; +- dbs->sector_num += dbs->iov.size / 512; + for (i = 0; i < dbs->iov.niov; ++i) { + cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base, + dbs->iov.iov[i].iov_len, !dbs->is_write, + dbs->iov.iov[i].iov_len); + } ++} ++ ++void dma_bdrv_cb(void *opaque, int ret) ++{ ++ DMAAIOCB *dbs = (DMAAIOCB *)opaque; ++ target_phys_addr_t cur_addr, cur_len; ++ void *mem; ++ ++ dbs->acb = NULL; ++ dbs->sector_num += dbs->iov.size / 512; ++ dma_bdrv_unmap(dbs); + qemu_iovec_reset(&dbs->iov); + + if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) { +@@ -119,6 +125,11 @@ static void dma_bdrv_cb(void *opaque, int ret) + dbs->acb = bdrv_aio_readv(dbs->bs, dbs->sector_num, &dbs->iov, + dbs->iov.size / 512, dma_bdrv_cb, dbs); + } ++ if (!dbs->acb) { ++ dma_bdrv_unmap(dbs); ++ qemu_iovec_destroy(&dbs->iov); ++ return; ++ } + } + + static BlockDriverAIOCB *dma_bdrv_io( +@@ -138,6 +149,10 @@ static BlockDriverAIOCB *dma_bdrv_io( + dbs->bh = NULL; + qemu_iovec_init(&dbs->iov, sg->nsg); + dma_bdrv_cb(dbs, 0); ++ if (!dbs->acb) { ++ qemu_aio_release(dbs); ++ return NULL; ++ } + return &dbs->common; + } + +-- +1.6.0.6 + diff --git a/qemu.spec b/qemu.spec index c1d8b23..6ba3503 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,7 +1,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 0.10.4 -Release: 3%{?dist} +Release: 4%{?dist} # Epoch because we pushed a qemu-1.0 package Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD @@ -29,6 +29,10 @@ Patch13: qemu-roms-more-room-fix-vga-align.patch Patch14: qemu-bios-bigger-roms.patch Patch15: qemu-kvm-fix-kerneldir-includes.patch Patch16: qemu-fix-load-linux.patch +Patch17: qemu-dma-aio-cancellation1.patch +Patch18: qemu-dma-aio-cancellation2.patch +Patch19: qemu-dma-aio-cancellation3.patch +Patch20: qemu-dma-aio-cancellation4.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel @@ -225,6 +229,10 @@ such as kvmtrace and kvm_stat. %patch14 -p1 %patch15 -p1 %patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 %build # systems like rhel build system does not have a recent enough linker so @@ -467,6 +475,9 @@ fi %{_mandir}/man1/qemu-img.1* %changelog +* Thu May 14 2009 Mark McLoughlin - 2:0.10.4-4 +- Cherry pick more DMA AIO cancellation fixes from upstream (#497170) + * Wed May 13 2009 Mark McLoughlin - 2:0.10.4-3 - Fix mixup between kvm.modules and the init script (reported by Rich Jones)