Commit 221f715d90ec5fec569a19119887445c037bca86

Authored by aliguori
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
block-raw-posix.c
@@ -1209,6 +1209,26 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) @@ -1209,6 +1209,26 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
1209 1209
1210 return ioctl(s->fd, req, buf); 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 #elif defined(__FreeBSD__) 1232 #elif defined(__FreeBSD__)
1213 1233
1214 static int fd_open(BlockDriverState *bs) 1234 static int fd_open(BlockDriverState *bs)
@@ -1349,33 +1369,14 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) @@ -1349,33 +1369,14 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
1349 { 1369 {
1350 return -ENOTSUP; 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 BlockDriver bdrv_host_device = { 1381 BlockDriver bdrv_host_device = {
1381 .format_name = "host_device", 1382 .format_name = "host_device",
@@ -1402,8 +1403,5 @@ BlockDriver bdrv_host_device = { @@ -1402,8 +1403,5 @@ BlockDriver bdrv_host_device = {
1402 .bdrv_set_locked = raw_set_locked, 1403 .bdrv_set_locked = raw_set_locked,
1403 /* generic scsi device */ 1404 /* generic scsi device */
1404 .bdrv_ioctl = raw_ioctl, 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 };
@@ -1633,24 +1633,13 @@ int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) @@ -1633,24 +1633,13 @@ int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
1633 return -ENOTSUP; 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 }
@@ -102,12 +102,10 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, @@ -102,12 +102,10 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
102 void bdrv_aio_cancel(BlockDriverAIOCB *acb); 102 void bdrv_aio_cancel(BlockDriverAIOCB *acb);
103 103
104 /* sg packet commands */ 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 /* Ensure contents are flushed to disk. */ 110 /* Ensure contents are flushed to disk. */
113 void bdrv_flush(BlockDriverState *bs); 111 void bdrv_flush(BlockDriverState *bs);
@@ -169,7 +167,6 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); @@ -169,7 +167,6 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
169 int bdrv_snapshot_list(BlockDriverState *bs, 167 int bdrv_snapshot_list(BlockDriverState *bs,
170 QEMUSnapshotInfo **psn_info); 168 QEMUSnapshotInfo **psn_info);
171 char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); 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 char *get_human_readable_size(char *buf, int buf_size, int64_t size); 171 char *get_human_readable_size(char *buf, int buf_size, int64_t size);
175 int path_is_absolute(const char *path); 172 int path_is_absolute(const char *path);
block_int.h
@@ -86,16 +86,9 @@ struct BlockDriver { @@ -86,16 +86,9 @@ struct BlockDriver {
86 86
87 /* to control generic scsi devices */ 87 /* to control generic scsi devices */
88 int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf); 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 AIOPool aio_pool; 93 AIOPool aio_pool;
101 struct BlockDriver *next; 94 struct BlockDriver *next;
hw/scsi-generic.c
@@ -201,8 +201,6 @@ static int execute_command(BlockDriverState *bdrv, @@ -201,8 +201,6 @@ static int execute_command(BlockDriverState *bdrv,
201 SCSIRequest *r, int direction, 201 SCSIRequest *r, int direction,
202 BlockDriverCompletionFunc *complete) 202 BlockDriverCompletionFunc *complete)
203 { 203 {
204 - int ret;  
205 -  
206 r->io_header.interface_id = 'S'; 204 r->io_header.interface_id = 'S';
207 r->io_header.dxfer_direction = direction; 205 r->io_header.dxfer_direction = direction;
208 r->io_header.dxferp = r->buf; 206 r->io_header.dxferp = r->buf;
@@ -215,27 +213,7 @@ static int execute_command(BlockDriverState *bdrv, @@ -215,27 +213,7 @@ static int execute_command(BlockDriverState *bdrv,
215 r->io_header.usr_ptr = r; 213 r->io_header.usr_ptr = r;
216 r->io_header.flags |= SG_FLAG_DIRECT_IO; 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 if (r->aiocb == NULL) { 217 if (r->aiocb == NULL) {
240 BADF("execute_command: read failed !\n"); 218 BADF("execute_command: read failed !\n");
241 return -1; 219 return -1;
@@ -637,14 +615,7 @@ static int get_blocksize(BlockDriverState *bdrv) @@ -637,14 +615,7 @@ static int get_blocksize(BlockDriverState *bdrv)
637 io_header.sbp = sensebuf; 615 io_header.sbp = sensebuf;
638 io_header.timeout = 6000; /* XXX */ 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 if (ret < 0) 619 if (ret < 0)
649 return -1; 620 return -1;
650 621
@@ -675,14 +646,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv) @@ -675,14 +646,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
675 io_header.sbp = sensebuf; 646 io_header.sbp = sensebuf;
676 io_header.timeout = 6000; /* XXX */ 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 if (ret < 0) 650 if (ret < 0)
687 return -1; 651 return -1;
688 652
posix-aio-compat.c
@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
11 * 11 *
12 */ 12 */
13 13
  14 +#include <sys/ioctl.h>
14 #include <pthread.h> 15 #include <pthread.h>
15 #include <unistd.h> 16 #include <unistd.h>
16 #include <errno.h> 17 #include <errno.h>
@@ -75,6 +76,47 @@ static void thread_create(pthread_t *thread, pthread_attr_t *attr, @@ -75,6 +76,47 @@ static void thread_create(pthread_t *thread, pthread_attr_t *attr,
75 if (ret) die2(ret, "pthread_create"); 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 static void *aio_thread(void *unused) 120 static void *aio_thread(void *unused)
79 { 121 {
80 pid_t pid; 122 pid_t pid;
@@ -88,8 +130,7 @@ static void *aio_thread(void *unused) @@ -88,8 +130,7 @@ static void *aio_thread(void *unused)
88 130
89 while (1) { 131 while (1) {
90 struct qemu_paiocb *aiocb; 132 struct qemu_paiocb *aiocb;
91 - size_t offset;  
92 - int ret = 0; 133 + size_t ret = 0;
93 qemu_timeval tv; 134 qemu_timeval tv;
94 struct timespec ts; 135 struct timespec ts;
95 136
@@ -109,40 +150,26 @@ static void *aio_thread(void *unused) @@ -109,40 +150,26 @@ static void *aio_thread(void *unused)
109 150
110 aiocb = TAILQ_FIRST(&request_list); 151 aiocb = TAILQ_FIRST(&request_list);
111 TAILQ_REMOVE(&request_list, aiocb, node); 152 TAILQ_REMOVE(&request_list, aiocb, node);
112 -  
113 - offset = 0;  
114 aiocb->active = 1; 153 aiocb->active = 1;
115 -  
116 idle_threads--; 154 idle_threads--;
117 mutex_unlock(&lock); 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 mutex_lock(&lock); 171 mutex_lock(&lock);
145 - aiocb->ret = offset; 172 + aiocb->ret = ret;
146 idle_threads++; 173 idle_threads++;
147 mutex_unlock(&lock); 174 mutex_unlock(&lock);
148 175
@@ -178,9 +205,9 @@ int qemu_paio_init(struct qemu_paioinit *aioinit) @@ -178,9 +205,9 @@ int qemu_paio_init(struct qemu_paioinit *aioinit)
178 return 0; 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 aiocb->ret = -EINPROGRESS; 211 aiocb->ret = -EINPROGRESS;
185 aiocb->active = 0; 212 aiocb->active = 0;
186 mutex_lock(&lock); 213 mutex_lock(&lock);
@@ -195,12 +222,17 @@ static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write) @@ -195,12 +222,17 @@ static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write)
195 222
196 int qemu_paio_read(struct qemu_paiocb *aiocb) 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 int qemu_paio_write(struct qemu_paiocb *aiocb) 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 ssize_t qemu_paio_return(struct qemu_paiocb *aiocb) 238 ssize_t qemu_paio_return(struct qemu_paiocb *aiocb)
posix-aio-compat.h
@@ -29,12 +29,16 @@ struct qemu_paiocb @@ -29,12 +29,16 @@ struct qemu_paiocb
29 int aio_fildes; 29 int aio_fildes;
30 void *aio_buf; 30 void *aio_buf;
31 size_t aio_nbytes; 31 size_t aio_nbytes;
  32 +#define aio_ioctl_cmd aio_nbytes /* for QEMU_PAIO_IOCTL */
32 int ev_signo; 33 int ev_signo;
33 off_t aio_offset; 34 off_t aio_offset;
34 35
35 /* private */ 36 /* private */
36 TAILQ_ENTRY(qemu_paiocb) node; 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 ssize_t ret; 42 ssize_t ret;
39 int active; 43 int active;
40 }; 44 };
@@ -49,6 +53,7 @@ struct qemu_paioinit @@ -49,6 +53,7 @@ struct qemu_paioinit
49 int qemu_paio_init(struct qemu_paioinit *aioinit); 53 int qemu_paio_init(struct qemu_paioinit *aioinit);
50 int qemu_paio_read(struct qemu_paiocb *aiocb); 54 int qemu_paio_read(struct qemu_paiocb *aiocb);
51 int qemu_paio_write(struct qemu_paiocb *aiocb); 55 int qemu_paio_write(struct qemu_paiocb *aiocb);
  56 +int qemu_paio_ioctl(struct qemu_paiocb *aiocb);
52 int qemu_paio_error(struct qemu_paiocb *aiocb); 57 int qemu_paio_error(struct qemu_paiocb *aiocb);
53 ssize_t qemu_paio_return(struct qemu_paiocb *aiocb); 58 ssize_t qemu_paio_return(struct qemu_paiocb *aiocb);
54 int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb); 59 int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb);