Commit 3b69e4b9ad3483bafcc3adc948703dc78e84ed33
1 parent
44e3ee8a
Vectored block device API (Avi Kivity)
Most devices that are capable of DMA are also capable of scatter-gather. With the memory mapping API, this means that the device code needs to be able to access discontiguous host memory regions. For block devices, this translates to vectored I/O. This patch implements an aynchronous vectored interface for the qemu block devices. At the moment all I/O is bounced and submitted through the non-vectored API; in the future we will convert block devices to natively support vectored I/O wherever possible. Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6397 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
76 additions
and
0 deletions
block.c
@@ -1246,6 +1246,69 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) | @@ -1246,6 +1246,69 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) | ||
1246 | /**************************************************************/ | 1246 | /**************************************************************/ |
1247 | /* async I/Os */ | 1247 | /* async I/Os */ |
1248 | 1248 | ||
1249 | +typedef struct VectorTranslationState { | ||
1250 | + QEMUIOVector *iov; | ||
1251 | + uint8_t *bounce; | ||
1252 | + int is_write; | ||
1253 | + BlockDriverAIOCB *aiocb; | ||
1254 | + BlockDriverAIOCB *this_aiocb; | ||
1255 | +} VectorTranslationState; | ||
1256 | + | ||
1257 | +static void bdrv_aio_rw_vector_cb(void *opaque, int ret) | ||
1258 | +{ | ||
1259 | + VectorTranslationState *s = opaque; | ||
1260 | + | ||
1261 | + if (!s->is_write) { | ||
1262 | + qemu_iovec_from_buffer(s->iov, s->bounce); | ||
1263 | + } | ||
1264 | + qemu_free(s->bounce); | ||
1265 | + s->this_aiocb->cb(s->this_aiocb->opaque, ret); | ||
1266 | + qemu_aio_release(s->this_aiocb); | ||
1267 | +} | ||
1268 | + | ||
1269 | +static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, | ||
1270 | + int64_t sector_num, | ||
1271 | + QEMUIOVector *iov, | ||
1272 | + int nb_sectors, | ||
1273 | + BlockDriverCompletionFunc *cb, | ||
1274 | + void *opaque, | ||
1275 | + int is_write) | ||
1276 | + | ||
1277 | +{ | ||
1278 | + VectorTranslationState *s = qemu_mallocz(sizeof(*s)); | ||
1279 | + BlockDriverAIOCB *aiocb = qemu_aio_get(bs, cb, opaque); | ||
1280 | + | ||
1281 | + s->this_aiocb = aiocb; | ||
1282 | + s->iov = iov; | ||
1283 | + s->bounce = qemu_memalign(512, nb_sectors * 512); | ||
1284 | + s->is_write = is_write; | ||
1285 | + if (is_write) { | ||
1286 | + qemu_iovec_to_buffer(s->iov, s->bounce); | ||
1287 | + s->aiocb = bdrv_aio_write(bs, sector_num, s->bounce, nb_sectors, | ||
1288 | + bdrv_aio_rw_vector_cb, s); | ||
1289 | + } else { | ||
1290 | + s->aiocb = bdrv_aio_read(bs, sector_num, s->bounce, nb_sectors, | ||
1291 | + bdrv_aio_rw_vector_cb, s); | ||
1292 | + } | ||
1293 | + return aiocb; | ||
1294 | +} | ||
1295 | + | ||
1296 | +BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, | ||
1297 | + QEMUIOVector *iov, int nb_sectors, | ||
1298 | + BlockDriverCompletionFunc *cb, void *opaque) | ||
1299 | +{ | ||
1300 | + return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors, | ||
1301 | + cb, opaque, 0); | ||
1302 | +} | ||
1303 | + | ||
1304 | +BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, | ||
1305 | + QEMUIOVector *iov, int nb_sectors, | ||
1306 | + BlockDriverCompletionFunc *cb, void *opaque) | ||
1307 | +{ | ||
1308 | + return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors, | ||
1309 | + cb, opaque, 1); | ||
1310 | +} | ||
1311 | + | ||
1249 | BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, | 1312 | BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, |
1250 | uint8_t *buf, int nb_sectors, | 1313 | uint8_t *buf, int nb_sectors, |
1251 | BlockDriverCompletionFunc *cb, void *opaque) | 1314 | BlockDriverCompletionFunc *cb, void *opaque) |
@@ -1294,6 +1357,11 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb) | @@ -1294,6 +1357,11 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb) | ||
1294 | { | 1357 | { |
1295 | BlockDriver *drv = acb->bs->drv; | 1358 | BlockDriver *drv = acb->bs->drv; |
1296 | 1359 | ||
1360 | + if (acb->cb == bdrv_aio_rw_vector_cb) { | ||
1361 | + VectorTranslationState *s = acb->opaque; | ||
1362 | + acb = s->aiocb; | ||
1363 | + } | ||
1364 | + | ||
1297 | drv->bdrv_aio_cancel(acb); | 1365 | drv->bdrv_aio_cancel(acb); |
1298 | } | 1366 | } |
1299 | 1367 |
block.h
@@ -2,6 +2,7 @@ | @@ -2,6 +2,7 @@ | ||
2 | #define BLOCK_H | 2 | #define BLOCK_H |
3 | 3 | ||
4 | #include "qemu-aio.h" | 4 | #include "qemu-aio.h" |
5 | +#include "qemu-common.h" | ||
5 | 6 | ||
6 | /* block.c */ | 7 | /* block.c */ |
7 | typedef struct BlockDriver BlockDriver; | 8 | typedef struct BlockDriver BlockDriver; |
@@ -85,6 +86,13 @@ int bdrv_commit(BlockDriverState *bs); | @@ -85,6 +86,13 @@ int bdrv_commit(BlockDriverState *bs); | ||
85 | typedef struct BlockDriverAIOCB BlockDriverAIOCB; | 86 | typedef struct BlockDriverAIOCB BlockDriverAIOCB; |
86 | typedef void BlockDriverCompletionFunc(void *opaque, int ret); | 87 | typedef void BlockDriverCompletionFunc(void *opaque, int ret); |
87 | 88 | ||
89 | +BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, | ||
90 | + QEMUIOVector *iov, int nb_sectors, | ||
91 | + BlockDriverCompletionFunc *cb, void *opaque); | ||
92 | +BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, | ||
93 | + QEMUIOVector *iov, int nb_sectors, | ||
94 | + BlockDriverCompletionFunc *cb, void *opaque); | ||
95 | + | ||
88 | BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, | 96 | BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, |
89 | uint8_t *buf, int nb_sectors, | 97 | uint8_t *buf, int nb_sectors, |
90 | BlockDriverCompletionFunc *cb, void *opaque); | 98 | BlockDriverCompletionFunc *cb, void *opaque); |