Revision c20fd872 hw/virtio-blk.c
b/hw/virtio-blk.c | ||
---|---|---|
223 | 223 |
} |
224 | 224 |
#endif /* __linux__ */ |
225 | 225 |
|
226 |
static void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq, |
|
227 |
int num_writes) |
|
226 |
typedef struct MultiReqBuffer { |
|
227 |
BlockRequest blkreq[32]; |
|
228 |
unsigned int num_writes; |
|
229 |
} MultiReqBuffer; |
|
230 |
|
|
231 |
static void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb) |
|
228 | 232 |
{ |
229 | 233 |
int i, ret; |
230 |
ret = bdrv_aio_multiwrite(bs, blkreq, num_writes); |
|
231 | 234 |
|
235 |
if (!mrb->num_writes) { |
|
236 |
return; |
|
237 |
} |
|
238 |
|
|
239 |
ret = bdrv_aio_multiwrite(bs, mrb->blkreq, mrb->num_writes); |
|
232 | 240 |
if (ret != 0) { |
233 |
for (i = 0; i < num_writes; i++) { |
|
234 |
if (blkreq[i].error) { |
|
235 |
virtio_blk_rw_complete(blkreq[i].opaque, -EIO); |
|
241 |
for (i = 0; i < mrb->num_writes; i++) {
|
|
242 |
if (mrb->blkreq[i].error) {
|
|
243 |
virtio_blk_rw_complete(mrb->blkreq[i].opaque, -EIO);
|
|
236 | 244 |
} |
237 | 245 |
} |
238 | 246 |
} |
247 |
|
|
248 |
mrb->num_writes = 0; |
|
239 | 249 |
} |
240 | 250 |
|
241 |
static void virtio_blk_handle_flush(BlockRequest *blkreq, int *num_writes, |
|
242 |
VirtIOBlockReq *req) |
|
251 |
static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb) |
|
243 | 252 |
{ |
244 | 253 |
BlockDriverAIOCB *acb; |
245 | 254 |
|
246 | 255 |
/* |
247 | 256 |
* Make sure all outstanding writes are posted to the backing device. |
248 | 257 |
*/ |
249 |
if (*num_writes > 0) { |
|
250 |
do_multiwrite(req->dev->bs, blkreq, *num_writes); |
|
251 |
} |
|
252 |
*num_writes = 0; |
|
258 |
virtio_submit_multiwrite(req->dev->bs, mrb); |
|
253 | 259 |
|
254 | 260 |
acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req); |
255 | 261 |
if (!acb) { |
... | ... | |
257 | 263 |
} |
258 | 264 |
} |
259 | 265 |
|
260 |
static void virtio_blk_handle_write(BlockRequest *blkreq, int *num_writes, |
|
261 |
VirtIOBlockReq *req) |
|
266 |
static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb) |
|
262 | 267 |
{ |
268 |
BlockRequest *blkreq; |
|
269 |
|
|
263 | 270 |
if (req->out->sector & req->dev->sector_mask) { |
264 | 271 |
virtio_blk_rw_complete(req, -EIO); |
265 | 272 |
return; |
266 | 273 |
} |
267 | 274 |
|
268 |
if (*num_writes == 32) { |
|
269 |
do_multiwrite(req->dev->bs, blkreq, *num_writes); |
|
270 |
*num_writes = 0; |
|
275 |
if (mrb->num_writes == 32) { |
|
276 |
virtio_submit_multiwrite(req->dev->bs, mrb); |
|
271 | 277 |
} |
272 | 278 |
|
273 |
blkreq[*num_writes].sector = req->out->sector; |
|
274 |
blkreq[*num_writes].nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE; |
|
275 |
blkreq[*num_writes].qiov = &req->qiov; |
|
276 |
blkreq[*num_writes].cb = virtio_blk_rw_complete; |
|
277 |
blkreq[*num_writes].opaque = req; |
|
278 |
blkreq[*num_writes].error = 0; |
|
279 |
blkreq = &mrb->blkreq[mrb->num_writes]; |
|
280 |
blkreq->sector = req->out->sector; |
|
281 |
blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE; |
|
282 |
blkreq->qiov = &req->qiov; |
|
283 |
blkreq->cb = virtio_blk_rw_complete; |
|
284 |
blkreq->opaque = req; |
|
285 |
blkreq->error = 0; |
|
279 | 286 |
|
280 |
(*num_writes)++;
|
|
287 |
mrb->num_writes++;
|
|
281 | 288 |
} |
282 | 289 |
|
283 | 290 |
static void virtio_blk_handle_read(VirtIOBlockReq *req) |
... | ... | |
297 | 304 |
} |
298 | 305 |
} |
299 | 306 |
|
300 |
typedef struct MultiReqBuffer { |
|
301 |
BlockRequest blkreq[32]; |
|
302 |
int num_writes; |
|
303 |
} MultiReqBuffer; |
|
304 |
|
|
305 | 307 |
static void virtio_blk_handle_request(VirtIOBlockReq *req, |
306 | 308 |
MultiReqBuffer *mrb) |
307 | 309 |
{ |
... | ... | |
320 | 322 |
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base; |
321 | 323 |
|
322 | 324 |
if (req->out->type & VIRTIO_BLK_T_FLUSH) { |
323 |
virtio_blk_handle_flush(mrb->blkreq, &mrb->num_writes, req);
|
|
325 |
virtio_blk_handle_flush(req, mrb);
|
|
324 | 326 |
} else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) { |
325 | 327 |
virtio_blk_handle_scsi(req); |
326 | 328 |
} else if (req->out->type & VIRTIO_BLK_T_OUT) { |
327 | 329 |
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1], |
328 | 330 |
req->elem.out_num - 1); |
329 |
virtio_blk_handle_write(mrb->blkreq, &mrb->num_writes, req);
|
|
331 |
virtio_blk_handle_write(req, mrb);
|
|
330 | 332 |
} else { |
331 | 333 |
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0], |
332 | 334 |
req->elem.in_num - 1); |
... | ... | |
346 | 348 |
virtio_blk_handle_request(req, &mrb); |
347 | 349 |
} |
348 | 350 |
|
349 |
if (mrb.num_writes > 0) { |
|
350 |
do_multiwrite(s->bs, mrb.blkreq, mrb.num_writes); |
|
351 |
} |
|
351 |
virtio_submit_multiwrite(s->bs, &mrb); |
|
352 | 352 |
|
353 | 353 |
/* |
354 | 354 |
* FIXME: Want to check for completions before returning to guest mode, |
... | ... | |
375 | 375 |
req = req->next; |
376 | 376 |
} |
377 | 377 |
|
378 |
if (mrb.num_writes > 0) { |
|
379 |
do_multiwrite(s->bs, mrb.blkreq, mrb.num_writes); |
|
380 |
} |
|
378 |
virtio_submit_multiwrite(s->bs, &mrb); |
|
381 | 379 |
} |
382 | 380 |
|
383 | 381 |
static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason) |
Also available in: Unified diff