qcow2: Avoid direct AIO callback
bdrv_aio_* must not call the callback before returning to its caller. In qcow2, 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:
parent
7bf4162a80
commit
42496d6240
@ -378,6 +378,7 @@ typedef struct QCowAIOCB {
|
|||||||
uint64_t bytes_done;
|
uint64_t bytes_done;
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
uint8_t *cluster_data;
|
uint8_t *cluster_data;
|
||||||
|
bool is_write;
|
||||||
BlockDriverAIOCB *hd_aiocb;
|
BlockDriverAIOCB *hd_aiocb;
|
||||||
QEMUIOVector hd_qiov;
|
QEMUIOVector hd_qiov;
|
||||||
QEMUBH *bh;
|
QEMUBH *bh;
|
||||||
@ -399,12 +400,19 @@ static AIOPool qcow2_aio_pool = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void qcow2_aio_read_cb(void *opaque, int ret);
|
static void qcow2_aio_read_cb(void *opaque, int ret);
|
||||||
static void qcow2_aio_read_bh(void *opaque)
|
static void qcow2_aio_write_cb(void *opaque, int ret);
|
||||||
|
|
||||||
|
static void qcow2_aio_rw_bh(void *opaque)
|
||||||
{
|
{
|
||||||
QCowAIOCB *acb = opaque;
|
QCowAIOCB *acb = opaque;
|
||||||
qemu_bh_delete(acb->bh);
|
qemu_bh_delete(acb->bh);
|
||||||
acb->bh = NULL;
|
acb->bh = NULL;
|
||||||
qcow2_aio_read_cb(opaque, 0);
|
|
||||||
|
if (acb->is_write) {
|
||||||
|
qcow2_aio_write_cb(opaque, 0);
|
||||||
|
} else {
|
||||||
|
qcow2_aio_read_cb(opaque, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
|
static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
|
||||||
@ -493,14 +501,14 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
|
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Note: in this case, no need to wait */
|
/* Note: in this case, no need to wait */
|
||||||
qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
|
qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
|
||||||
ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
|
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -515,7 +523,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
|
|||||||
s->cluster_cache + index_in_cluster * 512,
|
s->cluster_cache + index_in_cluster * 512,
|
||||||
512 * acb->cur_nr_sectors);
|
512 * acb->cur_nr_sectors);
|
||||||
|
|
||||||
ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
|
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
@ -572,6 +580,7 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
|
|||||||
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;
|
||||||
|
|
||||||
qemu_iovec_init(&acb->hd_qiov, qiov->niov);
|
qemu_iovec_init(&acb->hd_qiov, qiov->niov);
|
||||||
|
|
||||||
@ -591,17 +600,22 @@ static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs,
|
|||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
QCowAIOCB *acb;
|
QCowAIOCB *acb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
|
acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
|
||||||
if (!acb)
|
if (!acb)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
qcow2_aio_read_cb(acb, 0);
|
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
|
||||||
|
if (ret < 0) {
|
||||||
|
qemu_iovec_destroy(&acb->hd_qiov);
|
||||||
|
qemu_aio_release(acb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qcow2_aio_write_cb(void *opaque, int ret);
|
|
||||||
|
|
||||||
static void run_dependent_requests(QCowL2Meta *m)
|
static void run_dependent_requests(QCowL2Meta *m)
|
||||||
{
|
{
|
||||||
QCowAIOCB *req;
|
QCowAIOCB *req;
|
||||||
@ -724,6 +738,7 @@ static BlockDriverAIOCB *qcow2_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 */
|
||||||
|
|
||||||
@ -731,7 +746,13 @@ static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
|
|||||||
if (!acb)
|
if (!acb)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
qcow2_aio_write_cb(acb, 0);
|
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
|
||||||
|
if (ret < 0) {
|
||||||
|
qemu_iovec_destroy(&acb->hd_qiov);
|
||||||
|
qemu_aio_release(acb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user