qcow: Avoid direct AIO callback

bdrv_aio_* must not call the callback before returning to its caller. In qcow,
this could happen in some error cases. This starts the real requests processing
in a BH to avoid this situation.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Kevin Wolf 2011-06-07 15:20:44 +02:00
parent 42496d6240
commit b11a24dee6
1 changed files with 56 additions and 2 deletions

View File

@ -496,6 +496,8 @@ typedef struct QCowAIOCB {
uint64_t cluster_offset; uint64_t cluster_offset;
uint8_t *cluster_data; uint8_t *cluster_data;
struct iovec hd_iov; struct iovec hd_iov;
bool is_write;
QEMUBH *bh;
QEMUIOVector hd_qiov; QEMUIOVector hd_qiov;
BlockDriverAIOCB *hd_aiocb; BlockDriverAIOCB *hd_aiocb;
} QCowAIOCB; } QCowAIOCB;
@ -525,6 +527,8 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
acb->hd_aiocb = NULL; acb->hd_aiocb = NULL;
acb->sector_num = sector_num; acb->sector_num = sector_num;
acb->qiov = qiov; acb->qiov = qiov;
acb->is_write = is_write;
if (qiov->niov > 1) { if (qiov->niov > 1) {
acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size); acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
if (is_write) if (is_write)
@ -538,6 +542,38 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
return acb; return acb;
} }
static void qcow_aio_read_cb(void *opaque, int ret);
static void qcow_aio_write_cb(void *opaque, int ret);
static void qcow_aio_rw_bh(void *opaque)
{
QCowAIOCB *acb = opaque;
qemu_bh_delete(acb->bh);
acb->bh = NULL;
if (acb->is_write) {
qcow_aio_write_cb(opaque, 0);
} else {
qcow_aio_read_cb(opaque, 0);
}
}
static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
{
if (acb->bh) {
return -EIO;
}
acb->bh = qemu_bh_new(cb, acb);
if (!acb->bh) {
return -EIO;
}
qemu_bh_schedule(acb->bh);
return 0;
}
static void qcow_aio_read_cb(void *opaque, int ret) static void qcow_aio_read_cb(void *opaque, int ret)
{ {
QCowAIOCB *acb = opaque; QCowAIOCB *acb = opaque;
@ -640,12 +676,21 @@ static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque) BlockDriverCompletionFunc *cb, void *opaque)
{ {
QCowAIOCB *acb; QCowAIOCB *acb;
int ret;
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0); acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb) if (!acb)
return NULL; return NULL;
qcow_aio_read_cb(acb, 0); ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
if (ret < 0) {
if (acb->qiov->niov > 1) {
qemu_vfree(acb->orig_buf);
}
qemu_aio_release(acb);
return NULL;
}
return &acb->common; return &acb->common;
} }
@ -725,6 +770,7 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb; QCowAIOCB *acb;
int ret;
s->cluster_cache_offset = -1; /* disable compressed cache */ s->cluster_cache_offset = -1; /* disable compressed cache */
@ -733,7 +779,15 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
return NULL; return NULL;
qcow_aio_write_cb(acb, 0); ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
if (ret < 0) {
if (acb->qiov->niov > 1) {
qemu_vfree(acb->orig_buf);
}
qemu_aio_release(acb);
return NULL;
}
return &acb->common; return &acb->common;
} }