From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33253) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bjkYg-0005SX-Be for qemu-devel@nongnu.org; Tue, 13 Sep 2016 06:03:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bjkYZ-0001nL-LD for qemu-devel@nongnu.org; Tue, 13 Sep 2016 06:03:15 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36018) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bjkYZ-0001me-Dl for qemu-devel@nongnu.org; Tue, 13 Sep 2016 06:03:11 -0400 From: Stefan Hajnoczi Date: Tue, 13 Sep 2016 11:02:36 +0100 Message-Id: <1473760967-31840-9-git-send-email-stefanha@redhat.com> In-Reply-To: <1473760967-31840-1-git-send-email-stefanha@redhat.com> References: <1473760967-31840-1-git-send-email-stefanha@redhat.com> Subject: [Qemu-devel] [PULL v2 08/19] Backup: export interfaces for extra serialization List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Peter Maydell , Changlong Xie , Wen Congyang , Wang WeiWei , Stefan Hajnoczi From: Changlong Xie Normal backup(sync='none') workflow: step 1. NBD peformance I/O write from client to server qcow2_co_writev bdrv_co_writev ... bdrv_aligned_pwritev notifier_with_return_list_notify -> backup_do_cow bdrv_driver_pwritev // write new contents step 2. drive-backup sync=none backup_do_cow { wait_for_overlapping_requests cow_request_begin for(; start < end; start++) { bdrv_co_readv_no_serialising //read old contents from Secondary disk bdrv_co_writev // write old contents to hidden-disk } cow_request_end } step 3. Then roll back to "step 1" to write new contents to Secondary disk. And for replication, we must make sure that we only read the old contents from Secondary disk in order to keep contents consistent. 1) Replication workflow of Secondary virtio-blk ^ -------> 1 NBD | || server 3 replication || ^ ^ || | backing backing | || Secondary disk 6<-------- hidden-disk 5 <-------- active-disk 4 || | ^ || '-------------------------' || drive-backup sync=none 2 Hence, we need these interfaces to implement coarse-grained serialization between COW of Secondary disk and the read operation of replication. Example codes about how to use them: *#include "block/block_backup.h" static coroutine_fn int xxx_co_readv() { CowRequest req; BlockJob *job = secondary_disk->bs->job; if (job) { backup_wait_for_overlapping_requests(job, start, end); backup_cow_request_begin(&req, job, start, end); ret = bdrv_co_readv(); backup_cow_request_end(&req); goto out; } ret = bdrv_co_readv(); out: return ret; } Signed-off-by: Changlong Xie Signed-off-by: Wen Congyang Signed-off-by: Wang WeiWei Reviewed-by: Stefan Hajnoczi Message-id: 1469602913-20979-4-git-send-email-xiecl.fnst@cn.fujitsu.com Signed-off-by: Stefan Hajnoczi --- block/backup.c | 41 ++++++++++++++++++++++++++++++++++------- include/block/block_backup.h | 14 ++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/block/backup.c b/block/backup.c index dbe54e2..582bd0f 100644 --- a/block/backup.c +++ b/block/backup.c @@ -28,13 +28,6 @@ #define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16) #define SLICE_TIME 100000000ULL /* ns */ -typedef struct CowRequest { - int64_t start; - int64_t end; - QLIST_ENTRY(CowRequest) list; - CoQueue wait_queue; /* coroutines blocked on this request */ -} CowRequest; - typedef struct BackupBlockJob { BlockJob common; BlockBackend *target; @@ -273,6 +266,40 @@ void backup_do_checkpoint(BlockJob *job, Error **errp) bitmap_zero(backup_job->done_bitmap, len); } +void backup_wait_for_overlapping_requests(BlockJob *job, int64_t sector_num, + int nb_sectors) +{ + BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common); + int64_t sectors_per_cluster = cluster_size_sectors(backup_job); + int64_t start, end; + + assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP); + + start = sector_num / sectors_per_cluster; + end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster); + wait_for_overlapping_requests(backup_job, start, end); +} + +void backup_cow_request_begin(CowRequest *req, BlockJob *job, + int64_t sector_num, + int nb_sectors) +{ + BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common); + int64_t sectors_per_cluster = cluster_size_sectors(backup_job); + int64_t start, end; + + assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP); + + start = sector_num / sectors_per_cluster; + end = DIV_ROUND_UP(sector_num + nb_sectors, sectors_per_cluster); + cow_request_begin(req, backup_job, start, end); +} + +void backup_cow_request_end(CowRequest *req) +{ + cow_request_end(req); +} + static const BlockJobDriver backup_job_driver = { .instance_size = sizeof(BackupBlockJob), .job_type = BLOCK_JOB_TYPE_BACKUP, diff --git a/include/block/block_backup.h b/include/block/block_backup.h index 157596c..8a75947 100644 --- a/include/block/block_backup.h +++ b/include/block/block_backup.h @@ -20,6 +20,20 @@ #include "block/block_int.h" +typedef struct CowRequest { + int64_t start; + int64_t end; + QLIST_ENTRY(CowRequest) list; + CoQueue wait_queue; /* coroutines blocked on this request */ +} CowRequest; + +void backup_wait_for_overlapping_requests(BlockJob *job, int64_t sector_num, + int nb_sectors); +void backup_cow_request_begin(CowRequest *req, BlockJob *job, + int64_t sector_num, + int nb_sectors); +void backup_cow_request_end(CowRequest *req); + void backup_do_checkpoint(BlockJob *job, Error **errp); #endif -- 2.7.4