Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
Am 04.11.2013 um 10:30 hat Fam Zheng geschrieben: Previously a BlockDriverState has only one dirty bitmap, so only one caller (e.g. a block job) can keep track of writing. This changes the dirty bitmap to a list and creates a BdrvDirtyBitmap for each caller, the lifecycle is managed with these new functions: bdrv_create_dirty_bitmap bdrv_release_dirty_bitmap Where BdrvDirtyBitmap is a linked list wrapper structure of HBitmap. In place of bdrv_set_dirty_tracking, a BdrvDirtyBitmap pointer argument is added to these functions, since each caller has its own dirty bitmap: bdrv_get_dirty bdrv_dirty_iter_init bdrv_get_dirty_count bdrv_set_dirty and bdrv_reset_dirty prototypes are unchanged but will internally walk the list of all dirty bitmaps and set them one by one. Signed-off-by: Fam Zheng f...@redhat.com diff --git a/block/qapi.c b/block/qapi.c index 5880b3e..6b0cdcf 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -204,14 +204,6 @@ void bdrv_query_info(BlockDriverState *bs, info-io_status = bs-iostatus; } -if (bs-dirty_bitmap) { -info-has_dirty = true; -info-dirty = g_malloc0(sizeof(*info-dirty)); -info-dirty-count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE; -info-dirty-granularity = - ((int64_t) BDRV_SECTOR_SIZE hbitmap_granularity(bs-dirty_bitmap)); -} - if (bs-drv) { info-has_inserted = true; info-inserted = g_malloc0(sizeof(*info-inserted)); The dirty field should probably be removed from qapi-schema.json if it never gets set any more. It was optional, so perhaps removing it doesn't cause any trouble indeed, but I'd like to hear Eric on this matter before merging the patch. Though if libvirt does make use of it, we have a problem because it doesn't really make sense any more after these changes. Kevin
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
On 11/12/2013 03:46 AM, Kevin Wolf wrote: +++ b/block/qapi.c @@ -204,14 +204,6 @@ void bdrv_query_info(BlockDriverState *bs, info-io_status = bs-iostatus; } -if (bs-dirty_bitmap) { -info-has_dirty = true; -info-dirty = g_malloc0(sizeof(*info-dirty)); -info-dirty-count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE; -info-dirty-granularity = - ((int64_t) BDRV_SECTOR_SIZE hbitmap_granularity(bs-dirty_bitmap)); -} - if (bs-drv) { info-has_inserted = true; info-inserted = g_malloc0(sizeof(*info-inserted)); The dirty field should probably be removed from qapi-schema.json if it never gets set any more. It was optional, so perhaps removing it doesn't cause any trouble indeed, but I'd like to hear Eric on this matter before merging the patch. Though if libvirt does make use of it, we have a problem because it doesn't really make sense any more after these changes. Removing an optional output-only field is okay (it is the same as stating that we are ALWAYS taking the option of not including it). Since it has always been marked optional, management can't be relying on it; more specifically, libvirt does not have any code checking for it. So I'm okay with removing it from the schema as a backwards-compatible change. [Removing an optional input field is wrong, but BlockInfo is an output type, not an input type.] Eventually, libvirt would like to use persistent dirty bitmaps, in order to resume long-running operations such as drive-mirror even across migration between different qemu processes, but I don't think we are quite there yet, and I also don't think that removal of 'dirty' from BlockInfo impedes in that goal. -- Eric Blake eblake redhat com+1-919-301-3266 Libvirt virtualization library http://libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
On Mon, Nov 04, 2013 at 11:55:47AM +0100, Paolo Bonzini wrote: Il 04/11/2013 11:47, Fam Zheng ha scritto: -void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity); -int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); +typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; +BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity); +void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); +int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector); void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); -void bdrv_dirty_iter_init(BlockDriverState *bs, struct HBitmapIter *hbi); -int64_t bdrv_get_dirty_count(BlockDriverState *bs); +void bdrv_dirty_iter_init(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi); +int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); You do not really need the BDS argument to the functions, do you? (Or do you have other plans?) I just wanted to keep the pattern of those bdrv_* family, no other plans for it. Kevin, Stefan, any second opinions? I was thinking the same thing and arrived at the conclusion that since it's bdrv_*() and not bbitmap_*() we should keep the explicit BDS argument. Stefan
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
On Mon, Nov 04, 2013 at 05:30:10PM +0800, Fam Zheng wrote: @@ -2785,9 +2792,7 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs, ret = bdrv_co_flush(bs); } -if (bs-dirty_bitmap) { bdrv_set_dirty(bs, sector_num, nb_sectors); -} Forgot to reduce indentation?
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
On Mon, Nov 04, 2013 at 05:30:10PM +0800, Fam Zheng wrote: Previously a BlockDriverState has only one dirty bitmap, so only one caller (e.g. a block job) can keep track of writing. This changes the dirty bitmap to a list and creates a BdrvDirtyBitmap for each caller, the lifecycle is managed with these new functions: bdrv_create_dirty_bitmap bdrv_release_dirty_bitmap Where BdrvDirtyBitmap is a linked list wrapper structure of HBitmap. In place of bdrv_set_dirty_tracking, a BdrvDirtyBitmap pointer argument is added to these functions, since each caller has its own dirty bitmap: bdrv_get_dirty bdrv_dirty_iter_init bdrv_get_dirty_count bdrv_set_dirty and bdrv_reset_dirty prototypes are unchanged but will internally walk the list of all dirty bitmaps and set them one by one. Signed-off-by: Fam Zheng f...@redhat.com --- v2: Added BdrvDirtyBitmap [Paolo] Signed-off-by: Fam Zheng f...@redhat.com --- block-migration.c | 22 + block.c | 81 --- block/mirror.c| 23 -- block/qapi.c | 8 - include/block/block.h | 11 --- include/block/block_int.h | 2 +- 6 files changed, 85 insertions(+), 62 deletions(-) Happy with this modulo the indentation fixup I commented on. Reviewed-by: Stefan Hajnoczi stefa...@redhat.com
[Qemu-devel] [PATCH v2] block: per caller dirty bitmap
Previously a BlockDriverState has only one dirty bitmap, so only one caller (e.g. a block job) can keep track of writing. This changes the dirty bitmap to a list and creates a BdrvDirtyBitmap for each caller, the lifecycle is managed with these new functions: bdrv_create_dirty_bitmap bdrv_release_dirty_bitmap Where BdrvDirtyBitmap is a linked list wrapper structure of HBitmap. In place of bdrv_set_dirty_tracking, a BdrvDirtyBitmap pointer argument is added to these functions, since each caller has its own dirty bitmap: bdrv_get_dirty bdrv_dirty_iter_init bdrv_get_dirty_count bdrv_set_dirty and bdrv_reset_dirty prototypes are unchanged but will internally walk the list of all dirty bitmaps and set them one by one. Signed-off-by: Fam Zheng f...@redhat.com --- v2: Added BdrvDirtyBitmap [Paolo] Signed-off-by: Fam Zheng f...@redhat.com --- block-migration.c | 22 + block.c | 81 --- block/mirror.c| 23 -- block/qapi.c | 8 - include/block/block.h | 11 --- include/block/block_int.h | 2 +- 6 files changed, 85 insertions(+), 62 deletions(-) diff --git a/block-migration.c b/block-migration.c index daf9ec1..8f4e826 100644 --- a/block-migration.c +++ b/block-migration.c @@ -58,6 +58,7 @@ typedef struct BlkMigDevState { /* Protected by block migration lock. */ unsigned long *aio_bitmap; int64_t completed_sectors; +BdrvDirtyBitmap *dirty_bitmap; } BlkMigDevState; typedef struct BlkMigBlock { @@ -309,12 +310,21 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) /* Called with iothread lock taken. */ -static void set_dirty_tracking(int enable) +static void set_dirty_tracking(void) { BlkMigDevState *bmds; QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { -bdrv_set_dirty_tracking(bmds-bs, enable ? BLOCK_SIZE : 0); +bmds-dirty_bitmap = bdrv_create_dirty_bitmap(bmds-bs, BLOCK_SIZE); +} +} + +static void unset_dirty_tracking(void) +{ +BlkMigDevState *bmds; + +QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { +bdrv_release_dirty_bitmap(bmds-bs, bmds-dirty_bitmap); } } @@ -432,7 +442,7 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, } else { blk_mig_unlock(); } -if (bdrv_get_dirty(bmds-bs, sector)) { +if (bdrv_get_dirty(bmds-bs, bmds-dirty_bitmap, sector)) { if (total_sectors - sector BDRV_SECTORS_PER_DIRTY_CHUNK) { nr_sectors = total_sectors - sector; @@ -554,7 +564,7 @@ static int64_t get_remaining_dirty(void) int64_t dirty = 0; QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { -dirty += bdrv_get_dirty_count(bmds-bs); +dirty += bdrv_get_dirty_count(bmds-bs, bmds-dirty_bitmap); } return dirty BDRV_SECTOR_BITS; @@ -569,7 +579,7 @@ static void blk_mig_cleanup(void) bdrv_drain_all(); -set_dirty_tracking(0); +unset_dirty_tracking(); blk_mig_lock(); while ((bmds = QSIMPLEQ_FIRST(block_mig_state.bmds_list)) != NULL) { @@ -604,7 +614,7 @@ static int block_save_setup(QEMUFile *f, void *opaque) init_blk_migration(f); /* start track dirty blocks */ -set_dirty_tracking(1); +set_dirty_tracking(); qemu_mutex_unlock_iothread(); ret = flush_blks(f); diff --git a/block.c b/block.c index 58efb5b..ef7a55f 100644 --- a/block.c +++ b/block.c @@ -49,6 +49,11 @@ #include windows.h #endif +typedef struct BdrvDirtyBitmap { +HBitmap *bitmap; +QLIST_ENTRY(BdrvDirtyBitmap) list; +} BdrvDirtyBitmap; + #define NOT_DONE 0x7fff /* used while emulated sync operation in progress */ typedef enum { @@ -323,6 +328,7 @@ BlockDriverState *bdrv_new(const char *device_name) BlockDriverState *bs; bs = g_malloc0(sizeof(BlockDriverState)); +QLIST_INIT(bs-dirty_bitmaps); pstrcpy(bs-device_name, sizeof(bs-device_name), device_name); if (device_name[0] != '\0') { QTAILQ_INSERT_TAIL(bdrv_states, bs, list); @@ -1615,7 +1621,7 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, bs_dest-iostatus = bs_src-iostatus; /* dirty bitmap */ -bs_dest-dirty_bitmap = bs_src-dirty_bitmap; +bs_dest-dirty_bitmaps = bs_src-dirty_bitmaps; /* reference count */ bs_dest-refcnt = bs_src-refcnt; @@ -1648,7 +1654,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) /* bs_new must be anonymous and shouldn't have anything fancy enabled */ assert(bs_new-device_name[0] == '\0'); -assert(bs_new-dirty_bitmap == NULL); +assert(QLIST_EMPTY(bs_new-dirty_bitmaps)); assert(bs_new-job == NULL); assert(bs_new-dev == NULL); assert(bs_new-in_use == 0); @@ -1709,6 +1715,7 @@ static void bdrv_delete(BlockDriverState *bs)
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
Il 04/11/2013 10:30, Fam Zheng ha scritto: diff --git a/include/block/block.h b/include/block/block.h index 3560deb..06f424c 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -388,12 +388,15 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size); bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); struct HBitmapIter; -void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity); -int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); +typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; +BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity); +void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); +int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector); void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); -void bdrv_dirty_iter_init(BlockDriverState *bs, struct HBitmapIter *hbi); -int64_t bdrv_get_dirty_count(BlockDriverState *bs); +void bdrv_dirty_iter_init(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi); +int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); You do not really need the BDS argument to the functions, do you? (Or do you have other plans?) Apart from this, looks good. Paolo
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
On 11/04/2013 06:37 PM, Paolo Bonzini wrote: Il 04/11/2013 10:30, Fam Zheng ha scritto: diff --git a/include/block/block.h b/include/block/block.h index 3560deb..06f424c 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -388,12 +388,15 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size); bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); struct HBitmapIter; -void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity); -int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); +typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; +BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity); +void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); +int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector); void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); -void bdrv_dirty_iter_init(BlockDriverState *bs, struct HBitmapIter *hbi); -int64_t bdrv_get_dirty_count(BlockDriverState *bs); +void bdrv_dirty_iter_init(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi); +int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); You do not really need the BDS argument to the functions, do you? (Or do you have other plans?) I just wanted to keep the pattern of those bdrv_* family, no other plans for it. Fam
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
Il 04/11/2013 11:47, Fam Zheng ha scritto: -void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity); -int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); +typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; +BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity); +void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); +int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector); void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); -void bdrv_dirty_iter_init(BlockDriverState *bs, struct HBitmapIter *hbi); -int64_t bdrv_get_dirty_count(BlockDriverState *bs); +void bdrv_dirty_iter_init(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi); +int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); You do not really need the BDS argument to the functions, do you? (Or do you have other plans?) I just wanted to keep the pattern of those bdrv_* family, no other plans for it. Kevin, Stefan, any second opinions? Paolo
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
Le Monday 04 Nov 2013 à 17:30:10 (+0800), Fam Zheng a écrit : Previously a BlockDriverState has only one dirty bitmap, so only one caller (e.g. a block job) can keep track of writing. This changes the dirty bitmap to a list and creates a BdrvDirtyBitmap for each caller, the lifecycle is managed with these new functions: bdrv_create_dirty_bitmap bdrv_release_dirty_bitmap Where BdrvDirtyBitmap is a linked list wrapper structure of HBitmap. In place of bdrv_set_dirty_tracking, a BdrvDirtyBitmap pointer argument is added to these functions, since each caller has its own dirty bitmap: bdrv_get_dirty bdrv_dirty_iter_init bdrv_get_dirty_count bdrv_set_dirty and bdrv_reset_dirty prototypes are unchanged but will internally walk the list of all dirty bitmaps and set them one by one. Signed-off-by: Fam Zheng f...@redhat.com --- v2: Added BdrvDirtyBitmap [Paolo] Signed-off-by: Fam Zheng f...@redhat.com --- block-migration.c | 22 + block.c | 81 --- block/mirror.c| 23 -- block/qapi.c | 8 - include/block/block.h | 11 --- include/block/block_int.h | 2 +- 6 files changed, 85 insertions(+), 62 deletions(-) diff --git a/block-migration.c b/block-migration.c index daf9ec1..8f4e826 100644 --- a/block-migration.c +++ b/block-migration.c @@ -58,6 +58,7 @@ typedef struct BlkMigDevState { /* Protected by block migration lock. */ unsigned long *aio_bitmap; int64_t completed_sectors; +BdrvDirtyBitmap *dirty_bitmap; } BlkMigDevState; typedef struct BlkMigBlock { @@ -309,12 +310,21 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) /* Called with iothread lock taken. */ -static void set_dirty_tracking(int enable) +static void set_dirty_tracking(void) { BlkMigDevState *bmds; QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { -bdrv_set_dirty_tracking(bmds-bs, enable ? BLOCK_SIZE : 0); +bmds-dirty_bitmap = bdrv_create_dirty_bitmap(bmds-bs, BLOCK_SIZE); +} +} + +static void unset_dirty_tracking(void) +{ +BlkMigDevState *bmds; + +QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { +bdrv_release_dirty_bitmap(bmds-bs, bmds-dirty_bitmap); } } @@ -432,7 +442,7 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, } else { blk_mig_unlock(); } -if (bdrv_get_dirty(bmds-bs, sector)) { +if (bdrv_get_dirty(bmds-bs, bmds-dirty_bitmap, sector)) { if (total_sectors - sector BDRV_SECTORS_PER_DIRTY_CHUNK) { nr_sectors = total_sectors - sector; @@ -554,7 +564,7 @@ static int64_t get_remaining_dirty(void) int64_t dirty = 0; QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { -dirty += bdrv_get_dirty_count(bmds-bs); +dirty += bdrv_get_dirty_count(bmds-bs, bmds-dirty_bitmap); } return dirty BDRV_SECTOR_BITS; @@ -569,7 +579,7 @@ static void blk_mig_cleanup(void) bdrv_drain_all(); -set_dirty_tracking(0); +unset_dirty_tracking(); blk_mig_lock(); while ((bmds = QSIMPLEQ_FIRST(block_mig_state.bmds_list)) != NULL) { @@ -604,7 +614,7 @@ static int block_save_setup(QEMUFile *f, void *opaque) init_blk_migration(f); /* start track dirty blocks */ -set_dirty_tracking(1); +set_dirty_tracking(); qemu_mutex_unlock_iothread(); ret = flush_blks(f); diff --git a/block.c b/block.c index 58efb5b..ef7a55f 100644 --- a/block.c +++ b/block.c @@ -49,6 +49,11 @@ #include windows.h #endif +typedef struct BdrvDirtyBitmap { +HBitmap *bitmap; +QLIST_ENTRY(BdrvDirtyBitmap) list; +} BdrvDirtyBitmap; + #define NOT_DONE 0x7fff /* used while emulated sync operation in progress */ typedef enum { @@ -323,6 +328,7 @@ BlockDriverState *bdrv_new(const char *device_name) BlockDriverState *bs; bs = g_malloc0(sizeof(BlockDriverState)); +QLIST_INIT(bs-dirty_bitmaps); pstrcpy(bs-device_name, sizeof(bs-device_name), device_name); if (device_name[0] != '\0') { QTAILQ_INSERT_TAIL(bdrv_states, bs, list); @@ -1615,7 +1621,7 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, bs_dest-iostatus = bs_src-iostatus; /* dirty bitmap */ -bs_dest-dirty_bitmap = bs_src-dirty_bitmap; +bs_dest-dirty_bitmaps = bs_src-dirty_bitmaps; /* reference count */ bs_dest-refcnt = bs_src-refcnt; @@ -1648,7 +1654,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) /* bs_new must be anonymous and shouldn't have anything fancy enabled */ assert(bs_new-device_name[0] == '\0'); -assert(bs_new-dirty_bitmap == NULL); +
Re: [Qemu-devel] [PATCH v2] block: per caller dirty bitmap
On 11/04/2013 10:38 PM, Benoît Canet wrote: Le Monday 04 Nov 2013 à 17:30:10 (+0800), Fam Zheng a écrit : Previously a BlockDriverState has only one dirty bitmap, so only one caller (e.g. a block job) can keep track of writing. This changes the dirty bitmap to a list and creates a BdrvDirtyBitmap for each caller, the lifecycle is managed with these new functions: bdrv_create_dirty_bitmap bdrv_release_dirty_bitmap Where BdrvDirtyBitmap is a linked list wrapper structure of HBitmap. In place of bdrv_set_dirty_tracking, a BdrvDirtyBitmap pointer argument is added to these functions, since each caller has its own dirty bitmap: bdrv_get_dirty bdrv_dirty_iter_init bdrv_get_dirty_count bdrv_set_dirty and bdrv_reset_dirty prototypes are unchanged but will internally walk the list of all dirty bitmaps and set them one by one. Signed-off-by: Fam Zheng f...@redhat.com --- v2: Added BdrvDirtyBitmap [Paolo] Signed-off-by: Fam Zheng f...@redhat.com --- block-migration.c | 22 + block.c | 81 --- block/mirror.c| 23 -- block/qapi.c | 8 - include/block/block.h | 11 --- include/block/block_int.h | 2 +- 6 files changed, 85 insertions(+), 62 deletions(-) diff --git a/block-migration.c b/block-migration.c index daf9ec1..8f4e826 100644 --- a/block-migration.c +++ b/block-migration.c @@ -58,6 +58,7 @@ typedef struct BlkMigDevState { /* Protected by block migration lock. */ unsigned long *aio_bitmap; int64_t completed_sectors; +BdrvDirtyBitmap *dirty_bitmap; } BlkMigDevState; typedef struct BlkMigBlock { @@ -309,12 +310,21 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) /* Called with iothread lock taken. */ -static void set_dirty_tracking(int enable) +static void set_dirty_tracking(void) { BlkMigDevState *bmds; QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { -bdrv_set_dirty_tracking(bmds-bs, enable ? BLOCK_SIZE : 0); +bmds-dirty_bitmap = bdrv_create_dirty_bitmap(bmds-bs, BLOCK_SIZE); +} +} + +static void unset_dirty_tracking(void) +{ +BlkMigDevState *bmds; + +QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { +bdrv_release_dirty_bitmap(bmds-bs, bmds-dirty_bitmap); } } @@ -432,7 +442,7 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, } else { blk_mig_unlock(); } -if (bdrv_get_dirty(bmds-bs, sector)) { +if (bdrv_get_dirty(bmds-bs, bmds-dirty_bitmap, sector)) { if (total_sectors - sector BDRV_SECTORS_PER_DIRTY_CHUNK) { nr_sectors = total_sectors - sector; @@ -554,7 +564,7 @@ static int64_t get_remaining_dirty(void) int64_t dirty = 0; QSIMPLEQ_FOREACH(bmds, block_mig_state.bmds_list, entry) { -dirty += bdrv_get_dirty_count(bmds-bs); +dirty += bdrv_get_dirty_count(bmds-bs, bmds-dirty_bitmap); } return dirty BDRV_SECTOR_BITS; @@ -569,7 +579,7 @@ static void blk_mig_cleanup(void) bdrv_drain_all(); -set_dirty_tracking(0); +unset_dirty_tracking(); blk_mig_lock(); while ((bmds = QSIMPLEQ_FIRST(block_mig_state.bmds_list)) != NULL) { @@ -604,7 +614,7 @@ static int block_save_setup(QEMUFile *f, void *opaque) init_blk_migration(f); /* start track dirty blocks */ -set_dirty_tracking(1); +set_dirty_tracking(); qemu_mutex_unlock_iothread(); ret = flush_blks(f); diff --git a/block.c b/block.c index 58efb5b..ef7a55f 100644 --- a/block.c +++ b/block.c @@ -49,6 +49,11 @@ #include windows.h #endif +typedef struct BdrvDirtyBitmap { +HBitmap *bitmap; +QLIST_ENTRY(BdrvDirtyBitmap) list; +} BdrvDirtyBitmap; + #define NOT_DONE 0x7fff /* used while emulated sync operation in progress */ typedef enum { @@ -323,6 +328,7 @@ BlockDriverState *bdrv_new(const char *device_name) BlockDriverState *bs; bs = g_malloc0(sizeof(BlockDriverState)); +QLIST_INIT(bs-dirty_bitmaps); pstrcpy(bs-device_name, sizeof(bs-device_name), device_name); if (device_name[0] != '\0') { QTAILQ_INSERT_TAIL(bdrv_states, bs, list); @@ -1615,7 +1621,7 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, bs_dest-iostatus = bs_src-iostatus; /* dirty bitmap */ -bs_dest-dirty_bitmap = bs_src-dirty_bitmap; +bs_dest-dirty_bitmaps = bs_src-dirty_bitmaps; /* reference count */ bs_dest-refcnt = bs_src-refcnt; @@ -1648,7 +1654,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) /* bs_new must be anonymous and shouldn't have anything fancy enabled */ assert(bs_new-device_name[0] == '\0'); -assert(bs_new-dirty_bitmap == NULL); +