From d3faa13e5ffda779dcd58f39e8745370adb05d67 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:38:50 +0200 Subject: block: access copy_on_read with atomic ops Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-2-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index cb78c4f..49f2ebb 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -595,11 +595,6 @@ struct BlockDriverState { /* Protected by AioContext lock */ - /* If true, copy read backing sectors into image. Can be >1 if more - * than one client has requested copy-on-read. - */ - int copy_on_read; - /* If we are reading a disk image, give its size in sectors. * Generally read-only; it is written to by load_snapshot and * save_snaphost, but the block layer is quiescent during those. @@ -633,6 +628,12 @@ struct BlockDriverState { QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; + /* If true, copy read backing sectors into image. Can be >1 if more + * than one client has requested copy-on-read. Accessed with atomic + * ops. + */ + int copy_on_read; + /* do we need to tell the quest if we have a volatile write cache? */ int enable_write_cache; -- cgit v1.1 From 414c2ec3585408a5c7b458664db180e91480bb03 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:38:51 +0200 Subject: block: access quiesce_counter with atomic ops Reviewed-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-3-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index 49f2ebb..1824e0e 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -637,6 +637,7 @@ struct BlockDriverState { /* do we need to tell the quest if we have a volatile write cache? */ int enable_write_cache; + /* Accessed with atomic ops. */ int quiesce_counter; }; -- cgit v1.1 From d993b85804b7ec099d4e1d377161ac8af398d855 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:38:52 +0200 Subject: block: access io_limits_disabled with atomic ops Reviewed-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-4-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/sysemu/block-backend.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 840ad61..24b63d6 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -80,7 +80,8 @@ typedef struct BlockBackendPublic { CoQueue throttled_reqs[2]; /* Nonzero if the I/O limits are currently being ignored; generally - * it is zero. */ + * it is zero. Accessed with atomic operations. + */ unsigned int io_limits_disabled; /* The following fields are protected by the ThrottleGroup lock. -- cgit v1.1 From 20fc71b25cfd8102b7f12a2b44133894ad90040a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:38:53 +0200 Subject: block: access serialising_in_flight with atomic ops Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-5-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index 1824e0e..39be34a 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -604,10 +604,6 @@ struct BlockDriverState { /* Callback before write request is processed */ NotifierWithReturnList before_write_notifiers; - /* number of in-flight requests; overall and serialising */ - unsigned int in_flight; - unsigned int serialising_in_flight; - bool wakeup; /* Offset after the highest byte written to */ @@ -634,6 +630,12 @@ struct BlockDriverState { */ int copy_on_read; + /* number of in-flight requests; overall and serialising. + * Accessed with atomic ops. + */ + unsigned int in_flight; + unsigned int serialising_in_flight; + /* do we need to tell the quest if we have a volatile write cache? */ int enable_write_cache; -- cgit v1.1 From e2a6ae7fe57c17199624e4d47826ec46ca57d546 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:38:54 +0200 Subject: block: access wakeup with atomic ops Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-6-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block.h | 5 +++-- include/block/block_int.h | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/block/block.h b/include/block/block.h index 9b355e9..a4f09df 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -402,7 +402,8 @@ void bdrv_drain_all(void); * block_job_defer_to_main_loop for how to do it). \ */ \ assert(!bs_->wakeup); \ - bs_->wakeup = true; \ + /* Set bs->wakeup before evaluating cond. */ \ + atomic_mb_set(&bs_->wakeup, true); \ while (busy_) { \ if ((cond)) { \ waited_ = busy_ = true; \ @@ -414,7 +415,7 @@ void bdrv_drain_all(void); waited_ |= busy_; \ } \ } \ - bs_->wakeup = false; \ + atomic_set(&bs_->wakeup, false); \ } \ waited_; }) diff --git a/include/block/block_int.h b/include/block/block_int.h index 39be34a..cf544b7 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -604,8 +604,6 @@ struct BlockDriverState { /* Callback before write request is processed */ NotifierWithReturnList before_write_notifiers; - bool wakeup; - /* Offset after the highest byte written to */ uint64_t wr_highest_offset; @@ -636,6 +634,11 @@ struct BlockDriverState { unsigned int in_flight; unsigned int serialising_in_flight; + /* Internal to BDRV_POLL_WHILE and bdrv_wakeup. Accessed with atomic + * ops. + */ + bool wakeup; + /* do we need to tell the quest if we have a volatile write cache? */ int enable_write_cache; -- cgit v1.1 From 850d54a2a9cf16f589f4aa40272515294671633f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:38:55 +0200 Subject: block: access io_plugged with atomic ops Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-7-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index cf544b7..091b5d3 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -611,9 +611,6 @@ struct BlockDriverState { uint64_t write_threshold_offset; NotifierWithReturn write_threshold_notifier; - /* counter for nested bdrv_io_plug */ - unsigned io_plugged; - QLIST_HEAD(, BdrvTrackedRequest) tracked_requests; CoQueue flush_queue; /* Serializing flush queue */ bool active_flush_req; /* Flush request in flight? */ @@ -639,6 +636,11 @@ struct BlockDriverState { */ bool wakeup; + /* counter for nested bdrv_io_plug. + * Accessed with atomic ops. + */ + unsigned io_plugged; + /* do we need to tell the quest if we have a volatile write cache? */ int enable_write_cache; -- cgit v1.1 From 93001e9d87ae40e7569eb0ece0eb86d9c9582e41 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:38:58 +0200 Subject: throttle-groups: protect throttled requests with a CoMutex Another possibility is to use tg->lock, which we're holding anyway in both schedule_next_request and throttle_group_co_io_limits_intercept. This would require open-coding the CoQueue however, so I've chosen this alternative. Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-10-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/sysemu/block-backend.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 24b63d6..999eb23 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -72,11 +72,8 @@ typedef struct BlockDevOps { * fields that must be public. This is in particular for QLIST_ENTRY() and * friends so that BlockBackends can be kept in lists outside block-backend.c */ typedef struct BlockBackendPublic { - /* I/O throttling has its own locking, but also some fields are - * protected by the AioContext lock. - */ - - /* Protected by AioContext lock. */ + /* throttled_reqs_lock protects the CoQueues for throttled requests. */ + CoMutex throttled_reqs_lock; CoQueue throttled_reqs[2]; /* Nonzero if the I/O limits are currently being ignored; generally -- cgit v1.1 From ae2d489c341ee98f2daad819a3812c6199481848 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:38:59 +0200 Subject: util: add stats64 module This module provides fast paths for 64-bit atomic operations on machines that only have 32-bit atomic access. Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Signed-off-by: Fam Zheng Message-Id: <20170605123908.18777-11-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/qemu/stats64.h | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 include/qemu/stats64.h (limited to 'include') diff --git a/include/qemu/stats64.h b/include/qemu/stats64.h new file mode 100644 index 0000000..4a357b3 --- /dev/null +++ b/include/qemu/stats64.h @@ -0,0 +1,193 @@ +/* + * Atomic operations on 64-bit quantities. + * + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Paolo Bonzini + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_STATS64_H +#define QEMU_STATS64_H 1 + +#include "qemu/atomic.h" + +/* This provides atomic operations on 64-bit type, using a reader-writer + * spinlock on architectures that do not have 64-bit accesses. Even on + * those architectures, it tries hard not to take the lock. + */ + +typedef struct Stat64 { +#ifdef CONFIG_ATOMIC64 + uint64_t value; +#else + uint32_t low, high; + uint32_t lock; +#endif +} Stat64; + +#ifdef CONFIG_ATOMIC64 +static inline void stat64_init(Stat64 *s, uint64_t value) +{ + /* This is not guaranteed to be atomic! */ + *s = (Stat64) { value }; +} + +static inline uint64_t stat64_get(const Stat64 *s) +{ + return atomic_read__nocheck(&s->value); +} + +static inline void stat64_add(Stat64 *s, uint64_t value) +{ + atomic_add(&s->value, value); +} + +static inline void stat64_min(Stat64 *s, uint64_t value) +{ + uint64_t orig = atomic_read__nocheck(&s->value); + while (orig > value) { + orig = atomic_cmpxchg__nocheck(&s->value, orig, value); + } +} + +static inline void stat64_max(Stat64 *s, uint64_t value) +{ + uint64_t orig = atomic_read__nocheck(&s->value); + while (orig < value) { + orig = atomic_cmpxchg__nocheck(&s->value, orig, value); + } +} +#else +uint64_t stat64_get(const Stat64 *s); +bool stat64_min_slow(Stat64 *s, uint64_t value); +bool stat64_max_slow(Stat64 *s, uint64_t value); +bool stat64_add32_carry(Stat64 *s, uint32_t low, uint32_t high); + +static inline void stat64_init(Stat64 *s, uint64_t value) +{ + /* This is not guaranteed to be atomic! */ + *s = (Stat64) { .low = value, .high = value >> 32, .lock = 0 }; +} + +static inline void stat64_add(Stat64 *s, uint64_t value) +{ + uint32_t low, high; + high = value >> 32; + low = (uint32_t) value; + if (!low) { + if (high) { + atomic_add(&s->high, high); + } + return; + } + + for (;;) { + uint32_t orig = s->low; + uint32_t result = orig + low; + uint32_t old; + + if (result < low || high) { + /* If the high part is affected, take the lock. */ + if (stat64_add32_carry(s, low, high)) { + return; + } + continue; + } + + /* No carry, try with a 32-bit cmpxchg. The result is independent of + * the high 32 bits, so it can race just fine with stat64_add32_carry + * and even stat64_get! + */ + old = atomic_cmpxchg(&s->low, orig, result); + if (orig == old) { + return; + } + } +} + +static inline void stat64_min(Stat64 *s, uint64_t value) +{ + uint32_t low, high; + uint32_t orig_low, orig_high; + + high = value >> 32; + low = (uint32_t) value; + do { + orig_high = atomic_read(&s->high); + if (orig_high < high) { + return; + } + + if (orig_high == high) { + /* High 32 bits are equal. Read low after high, otherwise we + * can get a false positive (e.g. 0x1235,0x0000 changes to + * 0x1234,0x8000 and we read it as 0x1234,0x0000). Pairs with + * the write barrier in stat64_min_slow. + */ + smp_rmb(); + orig_low = atomic_read(&s->low); + if (orig_low <= low) { + return; + } + + /* See if we were lucky and a writer raced against us. The + * barrier is theoretically unnecessary, but if we remove it + * we may miss being lucky. + */ + smp_rmb(); + orig_high = atomic_read(&s->high); + if (orig_high < high) { + return; + } + } + + /* If the value changes in any way, we have to take the lock. */ + } while (!stat64_min_slow(s, value)); +} + +static inline void stat64_max(Stat64 *s, uint64_t value) +{ + uint32_t low, high; + uint32_t orig_low, orig_high; + + high = value >> 32; + low = (uint32_t) value; + do { + orig_high = atomic_read(&s->high); + if (orig_high > high) { + return; + } + + if (orig_high == high) { + /* High 32 bits are equal. Read low after high, otherwise we + * can get a false positive (e.g. 0x1234,0x8000 changes to + * 0x1235,0x0000 and we read it as 0x1235,0x8000). Pairs with + * the write barrier in stat64_max_slow. + */ + smp_rmb(); + orig_low = atomic_read(&s->low); + if (orig_low >= low) { + return; + } + + /* See if we were lucky and a writer raced against us. The + * barrier is theoretically unnecessary, but if we remove it + * we may miss being lucky. + */ + smp_rmb(); + orig_high = atomic_read(&s->high); + if (orig_high > high) { + return; + } + } + + /* If the value changes in any way, we have to take the lock. */ + } while (!stat64_max_slow(s, value)); +} + +#endif + +#endif -- cgit v1.1 From f7946da274cf451d66e5207f21286fea14c4795d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:39:00 +0200 Subject: block: use Stat64 for wr_highest_offset Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-12-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index 091b5d3..28f8b1e 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -29,6 +29,7 @@ #include "qemu/option.h" #include "qemu/queue.h" #include "qemu/coroutine.h" +#include "qemu/stats64.h" #include "qemu/timer.h" #include "qapi-types.h" #include "qemu/hbitmap.h" @@ -604,9 +605,6 @@ struct BlockDriverState { /* Callback before write request is processed */ NotifierWithReturnList before_write_notifiers; - /* Offset after the highest byte written to */ - uint64_t wr_highest_offset; - /* threshold limit for writes, in bytes. "High water mark". */ uint64_t write_threshold_offset; NotifierWithReturn write_threshold_notifier; @@ -619,6 +617,9 @@ struct BlockDriverState { QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; + /* Offset after the highest byte written to */ + Stat64 wr_highest_offset; + /* If true, copy read backing sectors into image. Can be >1 if more * than one client has requested copy-on-read. Accessed with atomic * ops. -- cgit v1.1 From 47fec59941a7182380bc8dde3faf17cfb05b770f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:39:01 +0200 Subject: block: access write_gen with atomics Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-13-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index 28f8b1e..b7d0dfb 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -612,7 +612,6 @@ struct BlockDriverState { QLIST_HEAD(, BdrvTrackedRequest) tracked_requests; CoQueue flush_queue; /* Serializing flush queue */ bool active_flush_req; /* Flush request in flight? */ - unsigned int write_gen; /* Current data generation */ unsigned int flushed_gen; /* Flushed write generation */ QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; @@ -647,6 +646,7 @@ struct BlockDriverState { /* Accessed with atomic ops. */ int quiesce_counter; + unsigned int write_gen; /* Current data generation */ }; struct BlockBackendRootState { -- cgit v1.1 From 3783fa3dd3d0104e9780bde073f66f1e37f1ce1c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:39:02 +0200 Subject: block: protect tracked_requests and flush_queue with reqs_lock Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-14-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index b7d0dfb..ae74df9 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -609,11 +609,6 @@ struct BlockDriverState { uint64_t write_threshold_offset; NotifierWithReturn write_threshold_notifier; - QLIST_HEAD(, BdrvTrackedRequest) tracked_requests; - CoQueue flush_queue; /* Serializing flush queue */ - bool active_flush_req; /* Flush request in flight? */ - unsigned int flushed_gen; /* Flushed write generation */ - QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; /* Offset after the highest byte written to */ @@ -647,6 +642,15 @@ struct BlockDriverState { /* Accessed with atomic ops. */ int quiesce_counter; unsigned int write_gen; /* Current data generation */ + + /* Protected by reqs_lock. */ + CoMutex reqs_lock; + QLIST_HEAD(, BdrvTrackedRequest) tracked_requests; + CoQueue flush_queue; /* Serializing flush queue */ + bool active_flush_req; /* Flush request in flight? */ + + /* Only read/written by whoever has set active_flush_req to true. */ + unsigned int flushed_gen; /* Flushed write generation */ }; struct BlockBackendRootState { -- cgit v1.1 From 2119882c7eb7e2c612b24fc0c8d86f5887d6f1c3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:39:03 +0200 Subject: block: introduce dirty_bitmap_mutex It protects only the list of dirty bitmaps; in the next patch we will also protect their content. Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-15-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index ae74df9..21cb65b 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -609,6 +609,11 @@ struct BlockDriverState { uint64_t write_threshold_offset; NotifierWithReturn write_threshold_notifier; + /* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex. + * Reading from the list can be done with either the BQL or the + * dirty_bitmap_mutex. Modifying a bitmap requires the AioContext + * lock. */ + QemuMutex dirty_bitmap_mutex; QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; /* Offset after the highest byte written to */ -- cgit v1.1 From b64bd51efa9bbf30df1b2f91477d2805678d0b93 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:39:05 +0200 Subject: block: protect modification of dirty bitmaps with a mutex Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-17-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- include/block/block_int.h | 4 ++-- include/block/dirty-bitmap.h | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/block/block_int.h b/include/block/block_int.h index 21cb65b..7489700 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -611,8 +611,8 @@ struct BlockDriverState { /* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex. * Reading from the list can be done with either the BQL or the - * dirty_bitmap_mutex. Modifying a bitmap requires the AioContext - * lock. */ + * dirty_bitmap_mutex. Modifying a bitmap only requires + * dirty_bitmap_mutex. */ QemuMutex dirty_bitmap_mutex; QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps; diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index 9dea14b..ad6558a 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -36,8 +36,6 @@ bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap); const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap); int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap); DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap); -int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, - int64_t sector); void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap, int64_t cur_sector, int64_t nr_sectors); void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, @@ -45,6 +43,9 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector, int nb_sectors); +int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, int64_t sector, + int nb_sectors); void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector, int nb_sectors); @@ -52,11 +53,6 @@ BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap); BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap, uint64_t first_sector); void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter); -int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter); -void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num); -int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap); -int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap); -void bdrv_dirty_bitmap_truncate(BlockDriverState *bs); uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap, uint64_t start, uint64_t count); @@ -72,4 +68,19 @@ void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap, bool finish); void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); +/* Functions that require manual locking. */ +void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); +void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap); +int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, + int64_t sector); +void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + int64_t cur_sector, int64_t nr_sectors); +void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + int64_t cur_sector, int64_t nr_sectors); +int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter); +void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num); +int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap); +int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap); +void bdrv_dirty_bitmap_truncate(BlockDriverState *bs); + #endif -- cgit v1.1 From 9caa6f3dbe20f2c506df6698386fce941fc6238a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:39:07 +0200 Subject: block: split BlockAcctStats creation and setup block_acct_destroy is called unconditionally in blk_delete, but there is no BlockAcctStats function that is called unconditionally in blk_new. Split block_acct_init in two, so that it will be possible to create a QemuMutex in block_acct_init and destroy it in block_acct_cleanup. Cc: Alberto Garcia Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-19-pbonzini@redhat.com> Reviewed-by: Alberto Garcia Signed-off-by: Fam Zheng --- include/block/accounting.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/block/accounting.h b/include/block/accounting.h index 2089163..55cb06f 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -61,7 +61,8 @@ typedef struct BlockAcctCookie { enum BlockAcctType type; } BlockAcctCookie; -void block_acct_init(BlockAcctStats *stats, bool account_invalid, +void block_acct_init(BlockAcctStats *stats); +void block_acct_setup(BlockAcctStats *stats, bool account_invalid, bool account_failed); void block_acct_cleanup(BlockAcctStats *stats); void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length); -- cgit v1.1 From 5b50bf77ce6e773b04a303a2912876c9a1bfca43 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 5 Jun 2017 14:39:08 +0200 Subject: block: make accounting thread-safe I'm not trying too hard yet. Later, with multiqueue support, this may cause mutex contention or cacheline bouncing. Cc: Alberto Garcia Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Message-Id: <20170605123908.18777-20-pbonzini@redhat.com> Reviewed-by: Alberto Garcia Signed-off-by: Fam Zheng --- include/block/accounting.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/block/accounting.h b/include/block/accounting.h index 55cb06f..b833d26 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -26,8 +26,10 @@ #define BLOCK_ACCOUNTING_H #include "qemu/timed-average.h" +#include "qemu/thread.h" typedef struct BlockAcctTimedStats BlockAcctTimedStats; +typedef struct BlockAcctStats BlockAcctStats; enum BlockAcctType { BLOCK_ACCT_READ, @@ -37,12 +39,14 @@ enum BlockAcctType { }; struct BlockAcctTimedStats { + BlockAcctStats *stats; TimedAverage latency[BLOCK_MAX_IOTYPE]; unsigned interval_length; /* in seconds */ QSLIST_ENTRY(BlockAcctTimedStats) entries; }; -typedef struct BlockAcctStats { +struct BlockAcctStats { + QemuMutex lock; uint64_t nr_bytes[BLOCK_MAX_IOTYPE]; uint64_t nr_ops[BLOCK_MAX_IOTYPE]; uint64_t invalid_ops[BLOCK_MAX_IOTYPE]; @@ -53,7 +57,7 @@ typedef struct BlockAcctStats { QSLIST_HEAD(, BlockAcctTimedStats) intervals; bool account_invalid; bool account_failed; -} BlockAcctStats; +}; typedef struct BlockAcctCookie { int64_t bytes; -- cgit v1.1