Commit 221f715d90ec5fec569a19119887445c037bca86
1 parent
64a7fde8
new scsi-generic abstraction, use SG_IO (Christoph Hellwig)
Okay, I started looking into how to handle scsi-generic I/O in the new world order. I think the best is to use the SG_IO ioctl instead of the read/write interface as that allows us to support scsi passthrough on disk/cdrom devices, too. See Hannes patch on the kvm list from August for an example. Now that we always do ioctls we don't need another abstraction than bdrv_ioctl for the synchronous requests for now, and for asynchronous requests I've added a aio_ioctl abstraction keeping it simple. Long-term we might want to move the ops to a higher-level abstraction and let the low-level code fill out the request header, but I'm lazy enough to leave that to the people trying to support scsi-passthrough on a non-Linux OS. Tested lightly by issuing various sg_ commands from sg3-utils in a guest to a host CDROM device. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6895 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
7 changed files
with
115 additions
and
137 deletions
block-raw-posix.c
| ... | ... | @@ -1209,6 +1209,26 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) |
| 1209 | 1209 | |
| 1210 | 1210 | return ioctl(s->fd, req, buf); |
| 1211 | 1211 | } |
| 1212 | + | |
| 1213 | +static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, | |
| 1214 | + unsigned long int req, void *buf, | |
| 1215 | + BlockDriverCompletionFunc *cb, void *opaque) | |
| 1216 | +{ | |
| 1217 | + RawAIOCB *acb; | |
| 1218 | + | |
| 1219 | + acb = raw_aio_setup(bs, 0, buf, 0, cb, opaque); | |
| 1220 | + if (!acb) | |
| 1221 | + return NULL; | |
| 1222 | + | |
| 1223 | + acb->aiocb.aio_ioctl_cmd = req; | |
| 1224 | + if (qemu_paio_ioctl(&acb->aiocb) < 0) { | |
| 1225 | + raw_aio_remove(acb); | |
| 1226 | + return NULL; | |
| 1227 | + } | |
| 1228 | + | |
| 1229 | + return &acb->common; | |
| 1230 | +} | |
| 1231 | + | |
| 1212 | 1232 | #elif defined(__FreeBSD__) |
| 1213 | 1233 | |
| 1214 | 1234 | static int fd_open(BlockDriverState *bs) |
| ... | ... | @@ -1349,33 +1369,14 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) |
| 1349 | 1369 | { |
| 1350 | 1370 | return -ENOTSUP; |
| 1351 | 1371 | } |
| 1352 | -#endif /* !linux && !FreeBSD */ | |
| 1353 | - | |
| 1354 | -static int raw_sg_send_command(BlockDriverState *bs, void *buf, int count) | |
| 1355 | -{ | |
| 1356 | - return raw_pwrite(bs, -1, buf, count); | |
| 1357 | -} | |
| 1358 | - | |
| 1359 | -static int raw_sg_recv_response(BlockDriverState *bs, void *buf, int count) | |
| 1360 | -{ | |
| 1361 | - return raw_pread(bs, -1, buf, count); | |
| 1362 | -} | |
| 1363 | - | |
| 1364 | -static BlockDriverAIOCB *raw_sg_aio_read(BlockDriverState *bs, | |
| 1365 | - void *buf, int count, | |
| 1366 | - BlockDriverCompletionFunc *cb, | |
| 1367 | - void *opaque) | |
| 1368 | -{ | |
| 1369 | - return raw_aio_read(bs, 0, buf, -(int64_t)count, cb, opaque); | |
| 1370 | -} | |
| 1371 | 1372 | |
| 1372 | -static BlockDriverAIOCB *raw_sg_aio_write(BlockDriverState *bs, | |
| 1373 | - void *buf, int count, | |
| 1374 | - BlockDriverCompletionFunc *cb, | |
| 1375 | - void *opaque) | |
| 1373 | +static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, | |
| 1374 | + unsigned long int req, void *buf, | |
| 1375 | + BlockDriverCompletionFunc *cb, void *opaque) | |
| 1376 | 1376 | { |
| 1377 | - return raw_aio_write(bs, 0, buf, -(int64_t)count, cb, opaque); | |
| 1377 | + return -ENOTSUP; | |
| 1378 | 1378 | } |
| 1379 | +#endif /* !linux && !FreeBSD */ | |
| 1379 | 1380 | |
| 1380 | 1381 | BlockDriver bdrv_host_device = { |
| 1381 | 1382 | .format_name = "host_device", |
| ... | ... | @@ -1402,8 +1403,5 @@ BlockDriver bdrv_host_device = { |
| 1402 | 1403 | .bdrv_set_locked = raw_set_locked, |
| 1403 | 1404 | /* generic scsi device */ |
| 1404 | 1405 | .bdrv_ioctl = raw_ioctl, |
| 1405 | - .bdrv_sg_send_command = raw_sg_send_command, | |
| 1406 | - .bdrv_sg_recv_response = raw_sg_recv_response, | |
| 1407 | - .bdrv_sg_aio_read = raw_sg_aio_read, | |
| 1408 | - .bdrv_sg_aio_write = raw_sg_aio_write, | |
| 1406 | + .bdrv_aio_ioctl = raw_aio_ioctl, | |
| 1409 | 1407 | }; | ... | ... |
block.c
| ... | ... | @@ -1633,24 +1633,13 @@ int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) |
| 1633 | 1633 | return -ENOTSUP; |
| 1634 | 1634 | } |
| 1635 | 1635 | |
| 1636 | -int bdrv_sg_send_command(BlockDriverState *bs, void *buf, int count) | |
| 1637 | -{ | |
| 1638 | - return bs->drv->bdrv_sg_send_command(bs, buf, count); | |
| 1639 | -} | |
| 1640 | - | |
| 1641 | -int bdrv_sg_recv_response(BlockDriverState *bs, void *buf, int count) | |
| 1642 | -{ | |
| 1643 | - return bs->drv->bdrv_sg_recv_response(bs, buf, count); | |
| 1644 | -} | |
| 1645 | - | |
| 1646 | -BlockDriverAIOCB *bdrv_sg_aio_read(BlockDriverState *bs, void *buf, int count, | |
| 1647 | - BlockDriverCompletionFunc *cb, void *opaque) | |
| 1636 | +BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, | |
| 1637 | + unsigned long int req, void *buf, | |
| 1638 | + BlockDriverCompletionFunc *cb, void *opaque) | |
| 1648 | 1639 | { |
| 1649 | - return bs->drv->bdrv_sg_aio_read(bs, buf, count, cb, opaque); | |
| 1650 | -} | |
| 1640 | + BlockDriver *drv = bs->drv; | |
| 1651 | 1641 | |
| 1652 | -BlockDriverAIOCB *bdrv_sg_aio_write(BlockDriverState *bs, void *buf, int count, | |
| 1653 | - BlockDriverCompletionFunc *cb, void *opaque) | |
| 1654 | -{ | |
| 1655 | - return bs->drv->bdrv_sg_aio_write(bs, buf, count, cb, opaque); | |
| 1642 | + if (drv && drv->bdrv_aio_ioctl) | |
| 1643 | + return drv->bdrv_aio_ioctl(bs, req, buf, cb, opaque); | |
| 1644 | + return NULL; | |
| 1656 | 1645 | } | ... | ... |
block.h
| ... | ... | @@ -102,12 +102,10 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, |
| 102 | 102 | void bdrv_aio_cancel(BlockDriverAIOCB *acb); |
| 103 | 103 | |
| 104 | 104 | /* sg packet commands */ |
| 105 | -int bdrv_sg_send_command(BlockDriverState *bs, void *buf, int count); | |
| 106 | -int bdrv_sg_recv_response(BlockDriverState *bs, void *buf, int count); | |
| 107 | -BlockDriverAIOCB *bdrv_sg_aio_read(BlockDriverState *bs, void *buf, int count, | |
| 108 | - BlockDriverCompletionFunc *cb, void *opaque); | |
| 109 | -BlockDriverAIOCB *bdrv_sg_aio_write(BlockDriverState *bs, void *buf, int count, | |
| 110 | - BlockDriverCompletionFunc *cb, void *opaque); | |
| 105 | +int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf); | |
| 106 | +BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, | |
| 107 | + unsigned long int req, void *buf, | |
| 108 | + BlockDriverCompletionFunc *cb, void *opaque); | |
| 111 | 109 | |
| 112 | 110 | /* Ensure contents are flushed to disk. */ |
| 113 | 111 | void bdrv_flush(BlockDriverState *bs); |
| ... | ... | @@ -169,7 +167,6 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); |
| 169 | 167 | int bdrv_snapshot_list(BlockDriverState *bs, |
| 170 | 168 | QEMUSnapshotInfo **psn_info); |
| 171 | 169 | char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); |
| 172 | -int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf); | |
| 173 | 170 | |
| 174 | 171 | char *get_human_readable_size(char *buf, int buf_size, int64_t size); |
| 175 | 172 | int path_is_absolute(const char *path); | ... | ... |
block_int.h
| ... | ... | @@ -86,16 +86,9 @@ struct BlockDriver { |
| 86 | 86 | |
| 87 | 87 | /* to control generic scsi devices */ |
| 88 | 88 | int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf); |
| 89 | - int (*bdrv_sg_send_command)(BlockDriverState *bs, void *buf, int count); | |
| 90 | - int (*bdrv_sg_recv_response)(BlockDriverState *bs, void *buf, int count); | |
| 91 | - BlockDriverAIOCB *(*bdrv_sg_aio_read)(BlockDriverState *bs, | |
| 92 | - void *buf, int count, | |
| 93 | - BlockDriverCompletionFunc *cb, | |
| 94 | - void *opaque); | |
| 95 | - BlockDriverAIOCB *(*bdrv_sg_aio_write)(BlockDriverState *bs, | |
| 96 | - void *buf, int count, | |
| 97 | - BlockDriverCompletionFunc *cb, | |
| 98 | - void *opaque); | |
| 89 | + BlockDriverAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, | |
| 90 | + unsigned long int req, void *buf, | |
| 91 | + BlockDriverCompletionFunc *cb, void *opaque); | |
| 99 | 92 | |
| 100 | 93 | AIOPool aio_pool; |
| 101 | 94 | struct BlockDriver *next; | ... | ... |
hw/scsi-generic.c
| ... | ... | @@ -201,8 +201,6 @@ static int execute_command(BlockDriverState *bdrv, |
| 201 | 201 | SCSIRequest *r, int direction, |
| 202 | 202 | BlockDriverCompletionFunc *complete) |
| 203 | 203 | { |
| 204 | - int ret; | |
| 205 | - | |
| 206 | 204 | r->io_header.interface_id = 'S'; |
| 207 | 205 | r->io_header.dxfer_direction = direction; |
| 208 | 206 | r->io_header.dxferp = r->buf; |
| ... | ... | @@ -215,27 +213,7 @@ static int execute_command(BlockDriverState *bdrv, |
| 215 | 213 | r->io_header.usr_ptr = r; |
| 216 | 214 | r->io_header.flags |= SG_FLAG_DIRECT_IO; |
| 217 | 215 | |
| 218 | - ret = bdrv_sg_send_command(bdrv, &r->io_header, sizeof(r->io_header)); | |
| 219 | - if (ret < 0) { | |
| 220 | - BADF("execute_command: write failed ! (%d)\n", errno); | |
| 221 | - return -1; | |
| 222 | - } | |
| 223 | - if (complete == NULL) { | |
| 224 | - int ret; | |
| 225 | - r->aiocb = NULL; | |
| 226 | - while ((ret = bdrv_sg_recv_response(bdrv, &r->io_header, | |
| 227 | - sizeof(r->io_header))) < 0 && | |
| 228 | - ret == -EINTR) | |
| 229 | - ; | |
| 230 | - if (ret < 0) { | |
| 231 | - BADF("execute_command: read failed !\n"); | |
| 232 | - return -1; | |
| 233 | - } | |
| 234 | - return 0; | |
| 235 | - } | |
| 236 | - | |
| 237 | - r->aiocb = bdrv_sg_aio_read(bdrv, (uint8_t*)&r->io_header, | |
| 238 | - sizeof(r->io_header), complete, r); | |
| 216 | + r->aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r); | |
| 239 | 217 | if (r->aiocb == NULL) { |
| 240 | 218 | BADF("execute_command: read failed !\n"); |
| 241 | 219 | return -1; |
| ... | ... | @@ -637,14 +615,7 @@ static int get_blocksize(BlockDriverState *bdrv) |
| 637 | 615 | io_header.sbp = sensebuf; |
| 638 | 616 | io_header.timeout = 6000; /* XXX */ |
| 639 | 617 | |
| 640 | - ret = bdrv_sg_send_command(bdrv, &io_header, sizeof(io_header)); | |
| 641 | - if (ret < 0) | |
| 642 | - return -1; | |
| 643 | - | |
| 644 | - while ((ret = bdrv_sg_recv_response(bdrv, &io_header, sizeof(io_header))) < 0 && | |
| 645 | - ret == -EINTR) | |
| 646 | - ; | |
| 647 | - | |
| 618 | + ret = bdrv_ioctl(bdrv, SG_IO, &io_header); | |
| 648 | 619 | if (ret < 0) |
| 649 | 620 | return -1; |
| 650 | 621 | |
| ... | ... | @@ -675,14 +646,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv) |
| 675 | 646 | io_header.sbp = sensebuf; |
| 676 | 647 | io_header.timeout = 6000; /* XXX */ |
| 677 | 648 | |
| 678 | - ret = bdrv_sg_send_command(bdrv, &io_header, sizeof(io_header)); | |
| 679 | - if (ret < 0) | |
| 680 | - return -1; | |
| 681 | - | |
| 682 | - while ((ret = bdrv_sg_recv_response(bdrv, &io_header, sizeof(io_header))) < 0 && | |
| 683 | - ret == -EINTR) | |
| 684 | - ; | |
| 685 | - | |
| 649 | + ret = bdrv_ioctl(bdrv, SG_IO, &io_header); | |
| 686 | 650 | if (ret < 0) |
| 687 | 651 | return -1; |
| 688 | 652 | ... | ... |
posix-aio-compat.c
| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | * |
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | +#include <sys/ioctl.h> | |
| 14 | 15 | #include <pthread.h> |
| 15 | 16 | #include <unistd.h> |
| 16 | 17 | #include <errno.h> |
| ... | ... | @@ -75,6 +76,47 @@ static void thread_create(pthread_t *thread, pthread_attr_t *attr, |
| 75 | 76 | if (ret) die2(ret, "pthread_create"); |
| 76 | 77 | } |
| 77 | 78 | |
| 79 | +static size_t handle_aiocb_readwrite(struct qemu_paiocb *aiocb) | |
| 80 | +{ | |
| 81 | + size_t offset = 0; | |
| 82 | + ssize_t len; | |
| 83 | + | |
| 84 | + while (offset < aiocb->aio_nbytes) { | |
| 85 | + if (aiocb->aio_type == QEMU_PAIO_WRITE) | |
| 86 | + len = pwrite(aiocb->aio_fildes, | |
| 87 | + (const char *)aiocb->aio_buf + offset, | |
| 88 | + aiocb->aio_nbytes - offset, | |
| 89 | + aiocb->aio_offset + offset); | |
| 90 | + else | |
| 91 | + len = pread(aiocb->aio_fildes, | |
| 92 | + (char *)aiocb->aio_buf + offset, | |
| 93 | + aiocb->aio_nbytes - offset, | |
| 94 | + aiocb->aio_offset + offset); | |
| 95 | + | |
| 96 | + if (len == -1 && errno == EINTR) | |
| 97 | + continue; | |
| 98 | + else if (len == -1) { | |
| 99 | + offset = -errno; | |
| 100 | + break; | |
| 101 | + } else if (len == 0) | |
| 102 | + break; | |
| 103 | + | |
| 104 | + offset += len; | |
| 105 | + } | |
| 106 | + | |
| 107 | + return offset; | |
| 108 | +} | |
| 109 | + | |
| 110 | +static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb) | |
| 111 | +{ | |
| 112 | + int ret; | |
| 113 | + | |
| 114 | + ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_buf); | |
| 115 | + if (ret == -1) | |
| 116 | + return -errno; | |
| 117 | + return ret; | |
| 118 | +} | |
| 119 | + | |
| 78 | 120 | static void *aio_thread(void *unused) |
| 79 | 121 | { |
| 80 | 122 | pid_t pid; |
| ... | ... | @@ -88,8 +130,7 @@ static void *aio_thread(void *unused) |
| 88 | 130 | |
| 89 | 131 | while (1) { |
| 90 | 132 | struct qemu_paiocb *aiocb; |
| 91 | - size_t offset; | |
| 92 | - int ret = 0; | |
| 133 | + size_t ret = 0; | |
| 93 | 134 | qemu_timeval tv; |
| 94 | 135 | struct timespec ts; |
| 95 | 136 | |
| ... | ... | @@ -109,40 +150,26 @@ static void *aio_thread(void *unused) |
| 109 | 150 | |
| 110 | 151 | aiocb = TAILQ_FIRST(&request_list); |
| 111 | 152 | TAILQ_REMOVE(&request_list, aiocb, node); |
| 112 | - | |
| 113 | - offset = 0; | |
| 114 | 153 | aiocb->active = 1; |
| 115 | - | |
| 116 | 154 | idle_threads--; |
| 117 | 155 | mutex_unlock(&lock); |
| 118 | 156 | |
| 119 | - while (offset < aiocb->aio_nbytes) { | |
| 120 | - ssize_t len; | |
| 121 | - | |
| 122 | - if (aiocb->is_write) | |
| 123 | - len = pwrite(aiocb->aio_fildes, | |
| 124 | - (const char *)aiocb->aio_buf + offset, | |
| 125 | - aiocb->aio_nbytes - offset, | |
| 126 | - aiocb->aio_offset + offset); | |
| 127 | - else | |
| 128 | - len = pread(aiocb->aio_fildes, | |
| 129 | - (char *)aiocb->aio_buf + offset, | |
| 130 | - aiocb->aio_nbytes - offset, | |
| 131 | - aiocb->aio_offset + offset); | |
| 132 | - | |
| 133 | - if (len == -1 && errno == EINTR) | |
| 134 | - continue; | |
| 135 | - else if (len == -1) { | |
| 136 | - offset = -errno; | |
| 137 | - break; | |
| 138 | - } else if (len == 0) | |
| 139 | - break; | |
| 140 | - | |
| 141 | - offset += len; | |
| 142 | - } | |
| 157 | + switch (aiocb->aio_type) { | |
| 158 | + case QEMU_PAIO_READ: | |
| 159 | + case QEMU_PAIO_WRITE: | |
| 160 | + ret = handle_aiocb_readwrite(aiocb); | |
| 161 | + break; | |
| 162 | + case QEMU_PAIO_IOCTL: | |
| 163 | + ret = handle_aiocb_ioctl(aiocb); | |
| 164 | + break; | |
| 165 | + default: | |
| 166 | + fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); | |
| 167 | + ret = -EINVAL; | |
| 168 | + break; | |
| 169 | + } | |
| 143 | 170 | |
| 144 | 171 | mutex_lock(&lock); |
| 145 | - aiocb->ret = offset; | |
| 172 | + aiocb->ret = ret; | |
| 146 | 173 | idle_threads++; |
| 147 | 174 | mutex_unlock(&lock); |
| 148 | 175 | |
| ... | ... | @@ -178,9 +205,9 @@ int qemu_paio_init(struct qemu_paioinit *aioinit) |
| 178 | 205 | return 0; |
| 179 | 206 | } |
| 180 | 207 | |
| 181 | -static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write) | |
| 208 | +static int qemu_paio_submit(struct qemu_paiocb *aiocb, int type) | |
| 182 | 209 | { |
| 183 | - aiocb->is_write = is_write; | |
| 210 | + aiocb->aio_type = type; | |
| 184 | 211 | aiocb->ret = -EINPROGRESS; |
| 185 | 212 | aiocb->active = 0; |
| 186 | 213 | mutex_lock(&lock); |
| ... | ... | @@ -195,12 +222,17 @@ static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write) |
| 195 | 222 | |
| 196 | 223 | int qemu_paio_read(struct qemu_paiocb *aiocb) |
| 197 | 224 | { |
| 198 | - return qemu_paio_submit(aiocb, 0); | |
| 225 | + return qemu_paio_submit(aiocb, QEMU_PAIO_READ); | |
| 199 | 226 | } |
| 200 | 227 | |
| 201 | 228 | int qemu_paio_write(struct qemu_paiocb *aiocb) |
| 202 | 229 | { |
| 203 | - return qemu_paio_submit(aiocb, 1); | |
| 230 | + return qemu_paio_submit(aiocb, QEMU_PAIO_WRITE); | |
| 231 | +} | |
| 232 | + | |
| 233 | +int qemu_paio_ioctl(struct qemu_paiocb *aiocb) | |
| 234 | +{ | |
| 235 | + return qemu_paio_submit(aiocb, QEMU_PAIO_IOCTL); | |
| 204 | 236 | } |
| 205 | 237 | |
| 206 | 238 | ssize_t qemu_paio_return(struct qemu_paiocb *aiocb) | ... | ... |
posix-aio-compat.h
| ... | ... | @@ -29,12 +29,16 @@ struct qemu_paiocb |
| 29 | 29 | int aio_fildes; |
| 30 | 30 | void *aio_buf; |
| 31 | 31 | size_t aio_nbytes; |
| 32 | +#define aio_ioctl_cmd aio_nbytes /* for QEMU_PAIO_IOCTL */ | |
| 32 | 33 | int ev_signo; |
| 33 | 34 | off_t aio_offset; |
| 34 | 35 | |
| 35 | 36 | /* private */ |
| 36 | 37 | TAILQ_ENTRY(qemu_paiocb) node; |
| 37 | - int is_write; | |
| 38 | + int aio_type; | |
| 39 | +#define QEMU_PAIO_READ 0x01 | |
| 40 | +#define QEMU_PAIO_WRITE 0x02 | |
| 41 | +#define QEMU_PAIO_IOCTL 0x03 | |
| 38 | 42 | ssize_t ret; |
| 39 | 43 | int active; |
| 40 | 44 | }; |
| ... | ... | @@ -49,6 +53,7 @@ struct qemu_paioinit |
| 49 | 53 | int qemu_paio_init(struct qemu_paioinit *aioinit); |
| 50 | 54 | int qemu_paio_read(struct qemu_paiocb *aiocb); |
| 51 | 55 | int qemu_paio_write(struct qemu_paiocb *aiocb); |
| 56 | +int qemu_paio_ioctl(struct qemu_paiocb *aiocb); | |
| 52 | 57 | int qemu_paio_error(struct qemu_paiocb *aiocb); |
| 53 | 58 | ssize_t qemu_paio_return(struct qemu_paiocb *aiocb); |
| 54 | 59 | int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb); | ... | ... |