diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-01-15 16:52:56 -0600 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-01-15 16:52:56 -0600 |
commit | b9f84ac0fa81315bf4efa8db64f0705273b7499a (patch) | |
tree | 23e52b0dceb04a1dbd53432b5276005ed221f87a /hw | |
parent | c94bf1c107df6623e54d48b90fb439a1281a36de (diff) | |
parent | 7191bf311ea9722cdcc3b2229788eff69d896bd0 (diff) |
Merge remote-tracking branch 'stefanha/block' into staging
* stefanha/block:
block: Fix how mirror_run() frees its buffer
win32-aio: Fix how win32_aio_process_completion() frees buffer
scsi-disk: qemu_vfree(NULL) is fine, simplify
w32: Make qemu_vfree() accept NULL like the POSIX implementation
sheepdog: clean up sd_aio_setup()
sheepdog: multiplex the rw FD to flush cache
block: clear dirty bitmap when discarding
ide: issue discard asynchronously but serialize the pieces
ide: fix TRIM with empty range entry
block: make discard asynchronous
raw: support discard on block devices
raw-posix: remember whether discard failed
raw-posix: support discard on more filesystems
block: fix initialization in bdrv_io_limits_enable()
qcow2: Fix segfault on zero-length write
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/ide/core.c | 79 | ||||
-rw-r--r-- | hw/scsi-disk.c | 4 |
2 files changed, 55 insertions, 28 deletions
diff --git a/hw/ide/core.c b/hw/ide/core.c index 6f1938a0a8..14ad0799c3 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -325,14 +325,26 @@ typedef struct TrimAIOCB { BlockDriverAIOCB common; QEMUBH *bh; int ret; + QEMUIOVector *qiov; + BlockDriverAIOCB *aiocb; + int i, j; } TrimAIOCB; static void trim_aio_cancel(BlockDriverAIOCB *acb) { TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common); + /* Exit the loop in case bdrv_aio_cancel calls ide_issue_trim_cb again. */ + iocb->j = iocb->qiov->niov - 1; + iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1; + + /* Tell ide_issue_trim_cb not to trigger the completion, too. */ qemu_bh_delete(iocb->bh); iocb->bh = NULL; + + if (iocb->aiocb) { + bdrv_aio_cancel(iocb->aiocb); + } qemu_aio_release(iocb); } @@ -349,43 +361,60 @@ static void ide_trim_bh_cb(void *opaque) qemu_bh_delete(iocb->bh); iocb->bh = NULL; - qemu_aio_release(iocb); } +static void ide_issue_trim_cb(void *opaque, int ret) +{ + TrimAIOCB *iocb = opaque; + if (ret >= 0) { + while (iocb->j < iocb->qiov->niov) { + int j = iocb->j; + while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) { + int i = iocb->i; + uint64_t *buffer = iocb->qiov->iov[j].iov_base; + + /* 6-byte LBA + 2-byte range per entry */ + uint64_t entry = le64_to_cpu(buffer[i]); + uint64_t sector = entry & 0x0000ffffffffffffULL; + uint16_t count = entry >> 48; + + if (count == 0) { + continue; + } + + /* Got an entry! Submit and exit. */ + iocb->aiocb = bdrv_aio_discard(iocb->common.bs, sector, count, + ide_issue_trim_cb, opaque); + return; + } + + iocb->j++; + iocb->i = -1; + } + } else { + iocb->ret = ret; + } + + iocb->aiocb = NULL; + if (iocb->bh) { + qemu_bh_schedule(iocb->bh); + } +} + BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { TrimAIOCB *iocb; - int i, j, ret; iocb = qemu_aio_get(&trim_aiocb_info, bs, cb, opaque); iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); iocb->ret = 0; - - for (j = 0; j < qiov->niov; j++) { - uint64_t *buffer = qiov->iov[j].iov_base; - - for (i = 0; i < qiov->iov[j].iov_len / 8; i++) { - /* 6-byte LBA + 2-byte range per entry */ - uint64_t entry = le64_to_cpu(buffer[i]); - uint64_t sector = entry & 0x0000ffffffffffffULL; - uint16_t count = entry >> 48; - - if (count == 0) { - break; - } - - ret = bdrv_discard(bs, sector, count); - if (!iocb->ret) { - iocb->ret = ret; - } - } - } - - qemu_bh_schedule(iocb->bh); - + iocb->qiov = qiov; + iocb->i = -1; + iocb->j = 0; + ide_issue_trim_cb(iocb, 0); return &iocb->common; } diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index f8d7ef3374..96db9a73c7 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -85,9 +85,7 @@ static void scsi_free_request(SCSIRequest *req) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); - if (r->iov.iov_base) { - qemu_vfree(r->iov.iov_base); - } + qemu_vfree(r->iov.iov_base); } /* Helper function for command completion with sense. */ |