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); | ... | ... |