From 7d11399fba4ff06abc5f2cf7a13e828e91b1fdb1 Mon Sep 17 00:00:00 2001 From: Jeffrey Cody Date: Wed, 21 Mar 2012 21:55:04 +0100 Subject: [PATCH 37/55] block: make copy-on-read a per-request flag RH-Author: Jeffrey Cody Message-id: Patchwork-id: 38887 O-Subject: [RHEL6.3 qemu-kvm PATCH v8 37/54] block: make copy-on-read a per-request flag Bugzilla: 582475 RH-Acked-by: Paolo Bonzini RH-Acked-by: Marcelo Tosatti RH-Acked-by: Kevin Wolf From: Stefan Hajnoczi Previously copy-on-read could only be enabled for all requests to a block device. This means requests coming from the guest as well as QEMU's internal requests would perform copy-on-read when enabled. For image streaming we want to support finer-grained behavior than just populating the image file from its backing image. Image streaming supports partial streaming where a common backing image is preserved. In this case guest requests should not perform copy-on-read because they would indiscriminately copy data which should be left in a backing image from the backing chain. Introduce a per-request flag for copy-on-read so that a block device can process both regular and copy-on-read requests. Overlapping reads and writes still need to be serialized for correctness when copy-on-read is happening, so add an in-flight reference count to track this. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf (cherry picked from commit 470c05047a09cda3de16bb3f98a130d9537357a4) Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori Signed-off-by: Jeff Cody --- block.c | 49 ++++++++++++++++++++++++++++++++++++++----------- block.h | 2 ++ block_int.h | 3 +++ trace-events | 3 ++- 4 files changed, 45 insertions(+), 12 deletions(-) Signed-off-by: Michal Novotny --- block.c | 49 ++++++++++++++++++++++++++++++++++++++----------- block.h | 2 ++ block_int.h | 3 +++ trace-events | 3 ++- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/block.c b/block.c index b9f5ff1..0ee0b55 100644 --- a/block.c +++ b/block.c @@ -46,6 +46,10 @@ #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ +typedef enum { + BDRV_REQ_COPY_ON_READ = 0x1, +} BdrvRequestFlags; + static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load); static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, @@ -60,7 +64,8 @@ static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *iov); static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, + BdrvRequestFlags flags); static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, @@ -1296,7 +1301,7 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque) if (!rwco->is_write) { rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num, - rwco->nb_sectors, rwco->qiov); + rwco->nb_sectors, rwco->qiov, 0); } else { rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num, rwco->nb_sectors, rwco->qiov); @@ -1498,7 +1503,7 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset, return 0; } -static int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, +static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) { /* Perform I/O through a temporary buffer so that users who scribble over @@ -1521,8 +1526,8 @@ static int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, round_to_clusters(bs, sector_num, nb_sectors, &cluster_sector_num, &cluster_nb_sectors); - trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, - cluster_sector_num, cluster_nb_sectors); + trace_bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors, + cluster_sector_num, cluster_nb_sectors); iov.iov_len = cluster_nb_sectors * BDRV_SECTOR_SIZE; iov.iov_base = bounce_buffer = qemu_blockalign(bs, iov.iov_len); @@ -1557,7 +1562,8 @@ err: * Handle a read request in coroutine context */ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, + BdrvRequestFlags flags) { BlockDriver *drv = bs->drv; BdrvTrackedRequest req; @@ -1571,12 +1577,19 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, } if (bs->copy_on_read) { + flags |= BDRV_REQ_COPY_ON_READ; + } + if (flags & BDRV_REQ_COPY_ON_READ) { + bs->copy_on_read_in_flight++; + } + + if (bs->copy_on_read_in_flight) { wait_for_overlapping_requests(bs, sector_num, nb_sectors); } tracked_request_begin(&req, bs, sector_num, nb_sectors, false); - if (bs->copy_on_read) { + if (flags & BDRV_REQ_COPY_ON_READ) { int pnum; ret = bdrv_co_is_allocated(bs, sector_num, nb_sectors, &pnum); @@ -1585,7 +1598,7 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, } if (!ret || pnum != nb_sectors) { - ret = bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, qiov); + ret = bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors, qiov); goto out; } } @@ -1594,6 +1607,11 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, out: tracked_request_end(&req); + + if (flags & BDRV_REQ_COPY_ON_READ) { + bs->copy_on_read_in_flight--; + } + return ret; } @@ -1602,7 +1620,16 @@ int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num, { trace_bdrv_co_readv(bs, sector_num, nb_sectors); - return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov); + return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, 0); +} + +int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) +{ + trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors); + + return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, + BDRV_REQ_COPY_ON_READ); } /* @@ -1625,7 +1652,7 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs, return -EIO; } - if (bs->copy_on_read) { + if (bs->copy_on_read_in_flight) { wait_for_overlapping_requests(bs, sector_num, nb_sectors); } @@ -2901,7 +2928,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque) if (!acb->is_write) { acb->req.error = bdrv_co_do_readv(bs, acb->req.sector, - acb->req.nb_sectors, acb->req.qiov); + acb->req.nb_sectors, acb->req.qiov, 0); } else { acb->req.error = bdrv_co_do_writev(bs, acb->req.sector, acb->req.nb_sectors, acb->req.qiov); diff --git a/block.h b/block.h index e935392..5567d7c 100644 --- a/block.h +++ b/block.h @@ -146,6 +146,8 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset, const void *buf, int count); int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); +int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num, diff --git a/block_int.h b/block_int.h index bdda1af..d8e1474 100644 --- a/block_int.h +++ b/block_int.h @@ -185,6 +185,9 @@ struct BlockDriverState { BlockDriverState *backing_hd; BlockDriverState *file; + /* number of in-flight copy-on-read requests */ + unsigned int copy_on_read_in_flight; + /* async read/write emulation */ void *sync_aiocb; diff --git a/trace-events b/trace-events index 3903905..6725413 100644 --- a/trace-events +++ b/trace-events @@ -59,7 +59,8 @@ disable bdrv_lock_medium(void *bs, int locked) "bs %p locked %d" disable bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" disable bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" disable bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p" -disable bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d" +disable bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" +disable bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d" # hw/virtio-blk.c disable virtio_blk_req_complete(void *req, int status) "req %p status %d" -- 1.7.7.6