Blame SOURCES/kvm-block-move-ThrottleGroup-membership-to-ThrottleGroup.patch

9bac43
From 6b39617d8b6ec2930c61e8965452317afbdf8030 Mon Sep 17 00:00:00 2001
9bac43
From: Stefan Hajnoczi <stefanha@redhat.com>
9bac43
Date: Fri, 17 Nov 2017 11:19:00 +0100
9bac43
Subject: [PATCH 01/15] block: move ThrottleGroup membership to
9bac43
 ThrottleGroupMember
9bac43
9bac43
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
9bac43
Message-id: <20171117111908.8815-2-stefanha@redhat.com>
9bac43
Patchwork-id: 77737
9bac43
O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/9] block: move ThrottleGroup membership to ThrottleGroupMember
9bac43
Bugzilla: 1492295
9bac43
RH-Acked-by: John Snow <jsnow@redhat.com>
9bac43
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
9bac43
RH-Acked-by: Thomas Huth <thuth@redhat.com>
9bac43
9bac43
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
9bac43
9bac43
This commit eliminates the 1:1 relationship between BlockBackend and
9bac43
throttle group state.  Users will be able to create multiple throttle
9bac43
nodes, each with its own throttle group state, in the future.  The
9bac43
throttle group state cannot be per-BlockBackend anymore, it must be
9bac43
per-throttle node. This is done by gathering ThrottleGroup membership
9bac43
details from BlockBackendPublic into ThrottleGroupMember and refactoring
9bac43
existing code to use the structure.
9bac43
9bac43
Reviewed-by: Alberto Garcia <berto@igalia.com>
9bac43
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9bac43
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
9bac43
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9bac43
(cherry picked from commit 022cdc9f407434ad6eb7ace80362a1218a009bcc)
9bac43
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9bac43
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9bac43
---
9bac43
 block/block-backend.c           |  66 +++++----
9bac43
 block/qapi.c                    |   8 +-
9bac43
 block/throttle-groups.c         | 288 ++++++++++++++++++++--------------------
9bac43
 blockdev.c                      |   4 +-
9bac43
 include/block/throttle-groups.h |  39 +++++-
9bac43
 include/sysemu/block-backend.h  |  20 +--
9bac43
 tests/test-throttle.c           |  53 ++++----
9bac43
 7 files changed, 252 insertions(+), 226 deletions(-)
9bac43
9bac43
diff --git a/block/block-backend.c b/block/block-backend.c
9bac43
index 0819b3a..e61f072 100644
9bac43
--- a/block/block-backend.c
9bac43
+++ b/block/block-backend.c
9bac43
@@ -273,9 +273,9 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
9bac43
     blk->shared_perm = shared_perm;
9bac43
     blk_set_enable_write_cache(blk, true);
9bac43
 
9bac43
-    qemu_co_mutex_init(&blk->public.throttled_reqs_lock);
9bac43
-    qemu_co_queue_init(&blk->public.throttled_reqs[0]);
9bac43
-    qemu_co_queue_init(&blk->public.throttled_reqs[1]);
9bac43
+    qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_lock);
9bac43
+    qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0]);
9bac43
+    qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1]);
9bac43
     block_acct_init(&blk->stats);
9bac43
 
9bac43
     notifier_list_init(&blk->remove_bs_notifiers);
9bac43
@@ -343,7 +343,7 @@ static void blk_delete(BlockBackend *blk)
9bac43
     assert(!blk->refcnt);
9bac43
     assert(!blk->name);
9bac43
     assert(!blk->dev);
9bac43
-    if (blk->public.throttle_state) {
9bac43
+    if (blk->public.throttle_group_member.throttle_state) {
9bac43
         blk_io_limits_disable(blk);
9bac43
     }
9bac43
     if (blk->root) {
9bac43
@@ -658,9 +658,12 @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
9bac43
  */
9bac43
 void blk_remove_bs(BlockBackend *blk)
9bac43
 {
9bac43
+    ThrottleTimers *tt;
9bac43
+
9bac43
     notifier_list_notify(&blk->remove_bs_notifiers, blk);
9bac43
-    if (blk->public.throttle_state) {
9bac43
-        throttle_timers_detach_aio_context(&blk->public.throttle_timers);
9bac43
+    if (blk->public.throttle_group_member.throttle_state) {
9bac43
+        tt = &blk->public.throttle_group_member.throttle_timers;
9bac43
+        throttle_timers_detach_aio_context(tt);
9bac43
     }
9bac43
 
9bac43
     blk_update_root_state(blk);
9bac43
@@ -682,9 +685,10 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
9bac43
     bdrv_ref(bs);
9bac43
 
9bac43
     notifier_list_notify(&blk->insert_bs_notifiers, blk);
9bac43
-    if (blk->public.throttle_state) {
9bac43
+    if (blk->public.throttle_group_member.throttle_state) {
9bac43
         throttle_timers_attach_aio_context(
9bac43
-            &blk->public.throttle_timers, bdrv_get_aio_context(bs));
9bac43
+            &blk->public.throttle_group_member.throttle_timers,
9bac43
+            bdrv_get_aio_context(bs));
9bac43
     }
9bac43
 
9bac43
     return 0;
9bac43
@@ -1046,8 +1050,9 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
9bac43
     bdrv_inc_in_flight(bs);
9bac43
 
9bac43
     /* throttling disk I/O */
9bac43
-    if (blk->public.throttle_state) {
9bac43
-        throttle_group_co_io_limits_intercept(blk, bytes, false);
9bac43
+    if (blk->public.throttle_group_member.throttle_state) {
9bac43
+        throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
9bac43
+                bytes, false);
9bac43
     }
9bac43
 
9bac43
     ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
9bac43
@@ -1070,10 +1075,10 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
9bac43
     }
9bac43
 
9bac43
     bdrv_inc_in_flight(bs);
9bac43
-
9bac43
     /* throttling disk I/O */
9bac43
-    if (blk->public.throttle_state) {
9bac43
-        throttle_group_co_io_limits_intercept(blk, bytes, true);
9bac43
+    if (blk->public.throttle_group_member.throttle_state) {
9bac43
+        throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
9bac43
+                bytes, true);
9bac43
     }
9bac43
 
9bac43
     if (!blk->enable_write_cache) {
9bac43
@@ -1761,15 +1766,17 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
9bac43
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
9bac43
 {
9bac43
     BlockDriverState *bs = blk_bs(blk);
9bac43
+    ThrottleTimers *tt;
9bac43
 
9bac43
     if (bs) {
9bac43
-        if (blk->public.throttle_state) {
9bac43
-            throttle_timers_detach_aio_context(&blk->public.throttle_timers);
9bac43
+        if (blk->public.throttle_group_member.throttle_state) {
9bac43
+            tt = &blk->public.throttle_group_member.throttle_timers;
9bac43
+            throttle_timers_detach_aio_context(tt);
9bac43
         }
9bac43
         bdrv_set_aio_context(bs, new_context);
9bac43
-        if (blk->public.throttle_state) {
9bac43
-            throttle_timers_attach_aio_context(&blk->public.throttle_timers,
9bac43
-                                               new_context);
9bac43
+        if (blk->public.throttle_group_member.throttle_state) {
9bac43
+            tt = &blk->public.throttle_group_member.throttle_timers;
9bac43
+            throttle_timers_attach_aio_context(tt, new_context);
9bac43
         }
9bac43
     }
9bac43
 }
9bac43
@@ -1988,33 +1995,34 @@ int blk_commit_all(void)
9bac43
 /* throttling disk I/O limits */
9bac43
 void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
9bac43
 {
9bac43
-    throttle_group_config(blk, cfg);
9bac43
+    throttle_group_config(&blk->public.throttle_group_member, cfg);
9bac43
 }
9bac43
 
9bac43
 void blk_io_limits_disable(BlockBackend *blk)
9bac43
 {
9bac43
-    assert(blk->public.throttle_state);
9bac43
+    assert(blk->public.throttle_group_member.throttle_state);
9bac43
     bdrv_drained_begin(blk_bs(blk));
9bac43
-    throttle_group_unregister_blk(blk);
9bac43
+    throttle_group_unregister_tgm(&blk->public.throttle_group_member);
9bac43
     bdrv_drained_end(blk_bs(blk));
9bac43
 }
9bac43
 
9bac43
 /* should be called before blk_set_io_limits if a limit is set */
9bac43
 void blk_io_limits_enable(BlockBackend *blk, const char *group)
9bac43
 {
9bac43
-    assert(!blk->public.throttle_state);
9bac43
-    throttle_group_register_blk(blk, group);
9bac43
+    assert(!blk->public.throttle_group_member.throttle_state);
9bac43
+    throttle_group_register_tgm(&blk->public.throttle_group_member, group);
9bac43
 }
9bac43
 
9bac43
 void blk_io_limits_update_group(BlockBackend *blk, const char *group)
9bac43
 {
9bac43
     /* this BB is not part of any group */
9bac43
-    if (!blk->public.throttle_state) {
9bac43
+    if (!blk->public.throttle_group_member.throttle_state) {
9bac43
         return;
9bac43
     }
9bac43
 
9bac43
     /* this BB is a part of the same group than the one we want */
9bac43
-    if (!g_strcmp0(throttle_group_get_name(blk), group)) {
9bac43
+    if (!g_strcmp0(throttle_group_get_name(&blk->public.throttle_group_member),
9bac43
+                group)) {
9bac43
         return;
9bac43
     }
9bac43
 
9bac43
@@ -2036,8 +2044,8 @@ static void blk_root_drained_begin(BdrvChild *child)
9bac43
     /* Note that blk->root may not be accessible here yet if we are just
9bac43
      * attaching to a BlockDriverState that is drained. Use child instead. */
9bac43
 
9bac43
-    if (atomic_fetch_inc(&blk->public.io_limits_disabled) == 0) {
9bac43
-        throttle_group_restart_blk(blk);
9bac43
+    if (atomic_fetch_inc(&blk->public.throttle_group_member.io_limits_disabled) == 0) {
9bac43
+        throttle_group_restart_tgm(&blk->public.throttle_group_member);
9bac43
     }
9bac43
 }
9bac43
 
9bac43
@@ -2046,8 +2054,8 @@ static void blk_root_drained_end(BdrvChild *child)
9bac43
     BlockBackend *blk = child->opaque;
9bac43
     assert(blk->quiesce_counter);
9bac43
 
9bac43
-    assert(blk->public.io_limits_disabled);
9bac43
-    atomic_dec(&blk->public.io_limits_disabled);
9bac43
+    assert(blk->public.throttle_group_member.io_limits_disabled);
9bac43
+    atomic_dec(&blk->public.throttle_group_member.io_limits_disabled);
9bac43
 
9bac43
     if (--blk->quiesce_counter == 0) {
9bac43
         if (blk->dev_ops && blk->dev_ops->drained_end) {
9bac43
diff --git a/block/qapi.c b/block/qapi.c
9bac43
index 5f1a71f..7fa2437 100644
9bac43
--- a/block/qapi.c
9bac43
+++ b/block/qapi.c
9bac43
@@ -66,10 +66,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
9bac43
 
9bac43
     info->detect_zeroes = bs->detect_zeroes;
9bac43
 
9bac43
-    if (blk && blk_get_public(blk)->throttle_state) {
9bac43
+    if (blk && blk_get_public(blk)->throttle_group_member.throttle_state) {
9bac43
         ThrottleConfig cfg;
9bac43
+        BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
 
9bac43
-        throttle_group_get_config(blk, &cfg;;
9bac43
+        throttle_group_get_config(&blkp->throttle_group_member, &cfg;;
9bac43
 
9bac43
         info->bps     = cfg.buckets[THROTTLE_BPS_TOTAL].avg;
9bac43
         info->bps_rd  = cfg.buckets[THROTTLE_BPS_READ].avg;
9bac43
@@ -117,7 +118,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
9bac43
         info->iops_size = cfg.op_size;
9bac43
 
9bac43
         info->has_group = true;
9bac43
-        info->group = g_strdup(throttle_group_get_name(blk));
9bac43
+        info->group =
9bac43
+            g_strdup(throttle_group_get_name(&blkp->throttle_group_member));
9bac43
     }
9bac43
 
9bac43
     info->write_threshold = bdrv_write_threshold_get(bs);
9bac43
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
9bac43
index 890bfde..c8ed16d 100644
9bac43
--- a/block/throttle-groups.c
9bac43
+++ b/block/throttle-groups.c
9bac43
@@ -30,7 +30,7 @@
9bac43
 #include "sysemu/qtest.h"
9bac43
 
9bac43
 /* The ThrottleGroup structure (with its ThrottleState) is shared
9bac43
- * among different BlockBackends and it's independent from
9bac43
+ * among different ThrottleGroupMembers and it's independent from
9bac43
  * AioContext, so in order to use it from different threads it needs
9bac43
  * its own locking.
9bac43
  *
9bac43
@@ -40,26 +40,26 @@
9bac43
  * The whole ThrottleGroup structure is private and invisible to
9bac43
  * outside users, that only use it through its ThrottleState.
9bac43
  *
9bac43
- * In addition to the ThrottleGroup structure, BlockBackendPublic has
9bac43
+ * In addition to the ThrottleGroup structure, ThrottleGroupMember has
9bac43
  * fields that need to be accessed by other members of the group and
9bac43
  * therefore also need to be protected by this lock. Once a
9bac43
- * BlockBackend is registered in a group those fields can be accessed
9bac43
+ * ThrottleGroupMember is registered in a group those fields can be accessed
9bac43
  * by other threads any time.
9bac43
  *
9bac43
  * Again, all this is handled internally and is mostly transparent to
9bac43
  * the outside. The 'throttle_timers' field however has an additional
9bac43
  * constraint because it may be temporarily invalid (see for example
9bac43
  * blk_set_aio_context()). Therefore in this file a thread will
9bac43
- * access some other BlockBackend's timers only after verifying that
9bac43
- * that BlockBackend has throttled requests in the queue.
9bac43
+ * access some other ThrottleGroupMember's timers only after verifying that
9bac43
+ * that ThrottleGroupMember has throttled requests in the queue.
9bac43
  */
9bac43
 typedef struct ThrottleGroup {
9bac43
     char *name; /* This is constant during the lifetime of the group */
9bac43
 
9bac43
     QemuMutex lock; /* This lock protects the following four fields */
9bac43
     ThrottleState ts;
9bac43
-    QLIST_HEAD(, BlockBackendPublic) head;
9bac43
-    BlockBackend *tokens[2];
9bac43
+    QLIST_HEAD(, ThrottleGroupMember) head;
9bac43
+    ThrottleGroupMember *tokens[2];
9bac43
     bool any_timer_armed[2];
9bac43
     QEMUClockType clock_type;
9bac43
 
9bac43
@@ -140,114 +140,112 @@ void throttle_group_unref(ThrottleState *ts)
9bac43
     qemu_mutex_unlock(&throttle_groups_lock);
9bac43
 }
9bac43
 
9bac43
-/* Get the name from a BlockBackend's ThrottleGroup. The name (and the pointer)
9bac43
+/* Get the name from a ThrottleGroupMember's group. The name (and the pointer)
9bac43
  * is guaranteed to remain constant during the lifetime of the group.
9bac43
  *
9bac43
- * @blk:  a BlockBackend that is member of a throttling group
9bac43
+ * @tgm:  a ThrottleGroupMember
9bac43
  * @ret:  the name of the group.
9bac43
  */
9bac43
-const char *throttle_group_get_name(BlockBackend *blk)
9bac43
+const char *throttle_group_get_name(ThrottleGroupMember *tgm)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
9bac43
+    ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
9bac43
     return tg->name;
9bac43
 }
9bac43
 
9bac43
-/* Return the next BlockBackend in the round-robin sequence, simulating a
9bac43
- * circular list.
9bac43
+/* Return the next ThrottleGroupMember in the round-robin sequence, simulating
9bac43
+ * a circular list.
9bac43
  *
9bac43
  * This assumes that tg->lock is held.
9bac43
  *
9bac43
- * @blk: the current BlockBackend
9bac43
- * @ret: the next BlockBackend in the sequence
9bac43
+ * @tgm: the current ThrottleGroupMember
9bac43
+ * @ret: the next ThrottleGroupMember in the sequence
9bac43
  */
9bac43
-static BlockBackend *throttle_group_next_blk(BlockBackend *blk)
9bac43
+static ThrottleGroupMember *throttle_group_next_tgm(ThrottleGroupMember *tgm)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleState *ts = blkp->throttle_state;
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
     ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
-    BlockBackendPublic *next = QLIST_NEXT(blkp, round_robin);
9bac43
+    ThrottleGroupMember *next = QLIST_NEXT(tgm, round_robin);
9bac43
 
9bac43
     if (!next) {
9bac43
         next = QLIST_FIRST(&tg->head);
9bac43
     }
9bac43
 
9bac43
-    return blk_by_public(next);
9bac43
+    return next;
9bac43
 }
9bac43
 
9bac43
 /*
9bac43
- * Return whether a BlockBackend has pending requests.
9bac43
+ * Return whether a ThrottleGroupMember has pending requests.
9bac43
  *
9bac43
  * This assumes that tg->lock is held.
9bac43
  *
9bac43
- * @blk: the BlockBackend
9bac43
- * @is_write:  the type of operation (read/write)
9bac43
- * @ret:       whether the BlockBackend has pending requests.
9bac43
+ * @tgm:        the ThrottleGroupMember
9bac43
+ * @is_write:   the type of operation (read/write)
9bac43
+ * @ret:        whether the ThrottleGroupMember has pending requests.
9bac43
  */
9bac43
-static inline bool blk_has_pending_reqs(BlockBackend *blk,
9bac43
+static inline bool tgm_has_pending_reqs(ThrottleGroupMember *tgm,
9bac43
                                         bool is_write)
9bac43
 {
9bac43
-    const BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    return blkp->pending_reqs[is_write];
9bac43
+    return tgm->pending_reqs[is_write];
9bac43
 }
9bac43
 
9bac43
-/* Return the next BlockBackend in the round-robin sequence with pending I/O
9bac43
- * requests.
9bac43
+/* Return the next ThrottleGroupMember in the round-robin sequence with pending
9bac43
+ * I/O requests.
9bac43
  *
9bac43
  * This assumes that tg->lock is held.
9bac43
  *
9bac43
- * @blk:       the current BlockBackend
9bac43
+ * @tgm:       the current ThrottleGroupMember
9bac43
  * @is_write:  the type of operation (read/write)
9bac43
- * @ret:       the next BlockBackend with pending requests, or blk if there is
9bac43
- *             none.
9bac43
+ * @ret:       the next ThrottleGroupMember with pending requests, or tgm if
9bac43
+ *             there is none.
9bac43
  */
9bac43
-static BlockBackend *next_throttle_token(BlockBackend *blk, bool is_write)
9bac43
+static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
9bac43
+                                                bool is_write)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
9bac43
-    BlockBackend *token, *start;
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
+    ThrottleGroupMember *token, *start;
9bac43
 
9bac43
     start = token = tg->tokens[is_write];
9bac43
 
9bac43
     /* get next bs round in round robin style */
9bac43
-    token = throttle_group_next_blk(token);
9bac43
-    while (token != start && !blk_has_pending_reqs(token, is_write)) {
9bac43
-        token = throttle_group_next_blk(token);
9bac43
+    token = throttle_group_next_tgm(token);
9bac43
+    while (token != start && !tgm_has_pending_reqs(token, is_write)) {
9bac43
+        token = throttle_group_next_tgm(token);
9bac43
     }
9bac43
 
9bac43
     /* If no IO are queued for scheduling on the next round robin token
9bac43
-     * then decide the token is the current bs because chances are
9bac43
-     * the current bs get the current request queued.
9bac43
+     * then decide the token is the current tgm because chances are
9bac43
+     * the current tgm got the current request queued.
9bac43
      */
9bac43
-    if (token == start && !blk_has_pending_reqs(token, is_write)) {
9bac43
-        token = blk;
9bac43
+    if (token == start && !tgm_has_pending_reqs(token, is_write)) {
9bac43
+        token = tgm;
9bac43
     }
9bac43
 
9bac43
-    /* Either we return the original BB, or one with pending requests */
9bac43
-    assert(token == blk || blk_has_pending_reqs(token, is_write));
9bac43
+    /* Either we return the original TGM, or one with pending requests */
9bac43
+    assert(token == tgm || tgm_has_pending_reqs(token, is_write));
9bac43
 
9bac43
     return token;
9bac43
 }
9bac43
 
9bac43
-/* Check if the next I/O request for a BlockBackend needs to be throttled or
9bac43
- * not. If there's no timer set in this group, set one and update the token
9bac43
- * accordingly.
9bac43
+/* Check if the next I/O request for a ThrottleGroupMember needs to be
9bac43
+ * throttled or not. If there's no timer set in this group, set one and update
9bac43
+ * the token accordingly.
9bac43
  *
9bac43
  * This assumes that tg->lock is held.
9bac43
  *
9bac43
- * @blk:        the current BlockBackend
9bac43
+ * @tgm:        the current ThrottleGroupMember
9bac43
  * @is_write:   the type of operation (read/write)
9bac43
  * @ret:        whether the I/O request needs to be throttled or not
9bac43
  */
9bac43
-static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write)
9bac43
+static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
9bac43
+                                          bool is_write)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleState *ts = blkp->throttle_state;
9bac43
-    ThrottleTimers *tt = &blkp->throttle_timers;
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
     ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
+    ThrottleTimers *tt = &tgm->throttle_timers;
9bac43
     bool must_wait;
9bac43
 
9bac43
-    if (atomic_read(&blkp->io_limits_disabled)) {
9bac43
+    if (atomic_read(&tgm->io_limits_disabled)) {
9bac43
         return false;
9bac43
     }
9bac43
 
9bac43
@@ -258,30 +256,29 @@ static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write)
9bac43
 
9bac43
     must_wait = throttle_schedule_timer(ts, tt, is_write);
9bac43
 
9bac43
-    /* If a timer just got armed, set blk as the current token */
9bac43
+    /* If a timer just got armed, set tgm as the current token */
9bac43
     if (must_wait) {
9bac43
-        tg->tokens[is_write] = blk;
9bac43
+        tg->tokens[is_write] = tgm;
9bac43
         tg->any_timer_armed[is_write] = true;
9bac43
     }
9bac43
 
9bac43
     return must_wait;
9bac43
 }
9bac43
 
9bac43
-/* Start the next pending I/O request for a BlockBackend.  Return whether
9bac43
+/* Start the next pending I/O request for a ThrottleGroupMember. Return whether
9bac43
  * any request was actually pending.
9bac43
  *
9bac43
- * @blk:       the current BlockBackend
9bac43
+ * @tgm:       the current ThrottleGroupMember
9bac43
  * @is_write:  the type of operation (read/write)
9bac43
  */
9bac43
-static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk,
9bac43
+static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMember *tgm,
9bac43
                                                          bool is_write)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
     bool ret;
9bac43
 
9bac43
-    qemu_co_mutex_lock(&blkp->throttled_reqs_lock);
9bac43
-    ret = qemu_co_queue_next(&blkp->throttled_reqs[is_write]);
9bac43
-    qemu_co_mutex_unlock(&blkp->throttled_reqs_lock);
9bac43
+    qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
9bac43
+    ret = qemu_co_queue_next(&tgm->throttled_reqs[is_write]);
9bac43
+    qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
9bac43
 
9bac43
     return ret;
9bac43
 }
9bac43
@@ -290,19 +287,19 @@ static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk,
9bac43
  *
9bac43
  * This assumes that tg->lock is held.
9bac43
  *
9bac43
- * @blk:       the current BlockBackend
9bac43
+ * @tgm:       the current ThrottleGroupMember
9bac43
  * @is_write:  the type of operation (read/write)
9bac43
  */
9bac43
-static void schedule_next_request(BlockBackend *blk, bool is_write)
9bac43
+static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
     bool must_wait;
9bac43
-    BlockBackend *token;
9bac43
+    ThrottleGroupMember *token;
9bac43
 
9bac43
     /* Check if there's any pending request to schedule next */
9bac43
-    token = next_throttle_token(blk, is_write);
9bac43
-    if (!blk_has_pending_reqs(token, is_write)) {
9bac43
+    token = next_throttle_token(tgm, is_write);
9bac43
+    if (!tgm_has_pending_reqs(token, is_write)) {
9bac43
         return;
9bac43
     }
9bac43
 
9bac43
@@ -311,12 +308,12 @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
9bac43
 
9bac43
     /* If it doesn't have to wait, queue it for immediate execution */
9bac43
     if (!must_wait) {
9bac43
-        /* Give preference to requests from the current blk */
9bac43
+        /* Give preference to requests from the current tgm */
9bac43
         if (qemu_in_coroutine() &&
9bac43
-            throttle_group_co_restart_queue(blk, is_write)) {
9bac43
-            token = blk;
9bac43
+            throttle_group_co_restart_queue(tgm, is_write)) {
9bac43
+            token = tgm;
9bac43
         } else {
9bac43
-            ThrottleTimers *tt = &blk_get_public(token)->throttle_timers;
9bac43
+            ThrottleTimers *tt = &token->throttle_timers;
9bac43
             int64_t now = qemu_clock_get_ns(tg->clock_type);
9bac43
             timer_mod(tt->timers[is_write], now);
9bac43
             tg->any_timer_armed[is_write] = true;
9bac43
@@ -329,76 +326,77 @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
9bac43
  * if necessary, and schedule the next request using a round robin
9bac43
  * algorithm.
9bac43
  *
9bac43
- * @blk:       the current BlockBackend
9bac43
+ * @tgm:       the current ThrottleGroupMember
9bac43
  * @bytes:     the number of bytes for this I/O
9bac43
  * @is_write:  the type of operation (read/write)
9bac43
  */
9bac43
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
9bac43
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
9bac43
                                                         unsigned int bytes,
9bac43
                                                         bool is_write)
9bac43
 {
9bac43
     bool must_wait;
9bac43
-    BlockBackend *token;
9bac43
-
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
9bac43
+    ThrottleGroupMember *token;
9bac43
+    ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
9bac43
     qemu_mutex_lock(&tg->lock);
9bac43
 
9bac43
     /* First we check if this I/O has to be throttled. */
9bac43
-    token = next_throttle_token(blk, is_write);
9bac43
+    token = next_throttle_token(tgm, is_write);
9bac43
     must_wait = throttle_group_schedule_timer(token, is_write);
9bac43
 
9bac43
     /* Wait if there's a timer set or queued requests of this type */
9bac43
-    if (must_wait || blkp->pending_reqs[is_write]) {
9bac43
-        blkp->pending_reqs[is_write]++;
9bac43
+    if (must_wait || tgm->pending_reqs[is_write]) {
9bac43
+        tgm->pending_reqs[is_write]++;
9bac43
         qemu_mutex_unlock(&tg->lock);
9bac43
-        qemu_co_mutex_lock(&blkp->throttled_reqs_lock);
9bac43
-        qemu_co_queue_wait(&blkp->throttled_reqs[is_write],
9bac43
-                           &blkp->throttled_reqs_lock);
9bac43
-        qemu_co_mutex_unlock(&blkp->throttled_reqs_lock);
9bac43
+        qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
9bac43
+        qemu_co_queue_wait(&tgm->throttled_reqs[is_write],
9bac43
+                           &tgm->throttled_reqs_lock);
9bac43
+        qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
9bac43
         qemu_mutex_lock(&tg->lock);
9bac43
-        blkp->pending_reqs[is_write]--;
9bac43
+        tgm->pending_reqs[is_write]--;
9bac43
     }
9bac43
 
9bac43
     /* The I/O will be executed, so do the accounting */
9bac43
-    throttle_account(blkp->throttle_state, is_write, bytes);
9bac43
+    throttle_account(tgm->throttle_state, is_write, bytes);
9bac43
 
9bac43
     /* Schedule the next request */
9bac43
-    schedule_next_request(blk, is_write);
9bac43
+    schedule_next_request(tgm, is_write);
9bac43
 
9bac43
     qemu_mutex_unlock(&tg->lock);
9bac43
 }
9bac43
 
9bac43
 typedef struct {
9bac43
-    BlockBackend *blk;
9bac43
+    ThrottleGroupMember *tgm;
9bac43
     bool is_write;
9bac43
 } RestartData;
9bac43
 
9bac43
 static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
9bac43
 {
9bac43
     RestartData *data = opaque;
9bac43
-    BlockBackend *blk = data->blk;
9bac43
+    ThrottleGroupMember *tgm = data->tgm;
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
     bool is_write = data->is_write;
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
9bac43
     bool empty_queue;
9bac43
 
9bac43
-    empty_queue = !throttle_group_co_restart_queue(blk, is_write);
9bac43
+    empty_queue = !throttle_group_co_restart_queue(tgm, is_write);
9bac43
 
9bac43
     /* If the request queue was empty then we have to take care of
9bac43
      * scheduling the next one */
9bac43
     if (empty_queue) {
9bac43
         qemu_mutex_lock(&tg->lock);
9bac43
-        schedule_next_request(blk, is_write);
9bac43
+        schedule_next_request(tgm, is_write);
9bac43
         qemu_mutex_unlock(&tg->lock);
9bac43
     }
9bac43
 }
9bac43
 
9bac43
-static void throttle_group_restart_queue(BlockBackend *blk, bool is_write)
9bac43
+static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write)
9bac43
 {
9bac43
+    BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
9bac43
+            throttle_group_member);
9bac43
+    BlockBackend *blk = blk_by_public(blkp);
9bac43
     Coroutine *co;
9bac43
     RestartData rd = {
9bac43
-        .blk = blk,
9bac43
+        .tgm = tgm,
9bac43
         .is_write = is_write
9bac43
     };
9bac43
 
9bac43
@@ -406,13 +404,11 @@ static void throttle_group_restart_queue(BlockBackend *blk, bool is_write)
9bac43
     aio_co_enter(blk_get_aio_context(blk), co);
9bac43
 }
9bac43
 
9bac43
-void throttle_group_restart_blk(BlockBackend *blk)
9bac43
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-
9bac43
-    if (blkp->throttle_state) {
9bac43
-        throttle_group_restart_queue(blk, 0);
9bac43
-        throttle_group_restart_queue(blk, 1);
9bac43
+    if (tgm->throttle_state) {
9bac43
+        throttle_group_restart_queue(tgm, 0);
9bac43
+        throttle_group_restart_queue(tgm, 1);
9bac43
     }
9bac43
 }
9bac43
 
9bac43
@@ -420,32 +416,30 @@ void throttle_group_restart_blk(BlockBackend *blk)
9bac43
  * to throttle_config(), but guarantees atomicity within the
9bac43
  * throttling group.
9bac43
  *
9bac43
- * @blk: a BlockBackend that is a member of the group
9bac43
+ * @tgm:    a ThrottleGroupMember that is a member of the group
9bac43
  * @cfg: the configuration to set
9bac43
  */
9bac43
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg)
9bac43
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleState *ts = blkp->throttle_state;
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
     ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
     qemu_mutex_lock(&tg->lock);
9bac43
     throttle_config(ts, tg->clock_type, cfg);
9bac43
     qemu_mutex_unlock(&tg->lock);
9bac43
 
9bac43
-    throttle_group_restart_blk(blk);
9bac43
+    throttle_group_restart_tgm(tgm);
9bac43
 }
9bac43
 
9bac43
 /* Get the throttle configuration from a particular group. Similar to
9bac43
  * throttle_get_config(), but guarantees atomicity within the
9bac43
  * throttling group.
9bac43
  *
9bac43
- * @blk: a BlockBackend that is a member of the group
9bac43
+ * @tgm:    a ThrottleGroupMember that is a member of the group
9bac43
  * @cfg: the configuration will be written here
9bac43
  */
9bac43
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg)
9bac43
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleState *ts = blkp->throttle_state;
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
     ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
     qemu_mutex_lock(&tg->lock);
9bac43
     throttle_get_config(ts, cfg);
9bac43
@@ -461,7 +455,8 @@ void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg)
9bac43
 static void timer_cb(BlockBackend *blk, bool is_write)
9bac43
 {
9bac43
     BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleState *ts = blkp->throttle_state;
9bac43
+    ThrottleGroupMember *tgm = &blkp->throttle_group_member;
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
     ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
 
9bac43
     /* The timer has just been fired, so we can update the flag */
9bac43
@@ -470,7 +465,7 @@ static void timer_cb(BlockBackend *blk, bool is_write)
9bac43
     qemu_mutex_unlock(&tg->lock);
9bac43
 
9bac43
     /* Run the request that was waiting for this timer */
9bac43
-    throttle_group_restart_queue(blk, is_write);
9bac43
+    throttle_group_restart_queue(tgm, is_write);
9bac43
 }
9bac43
 
9bac43
 static void read_timer_cb(void *opaque)
9bac43
@@ -483,32 +478,36 @@ static void write_timer_cb(void *opaque)
9bac43
     timer_cb(opaque, true);
9bac43
 }
9bac43
 
9bac43
-/* Register a BlockBackend in the throttling group, also initializing its
9bac43
- * timers and updating its throttle_state pointer to point to it. If a
9bac43
+/* Register a ThrottleGroupMember from the throttling group, also initializing
9bac43
+ * its timers and updating its throttle_state pointer to point to it. If a
9bac43
  * throttling group with that name does not exist yet, it will be created.
9bac43
  *
9bac43
- * @blk:       the BlockBackend to insert
9bac43
+ * @tgm:       the ThrottleGroupMember to insert
9bac43
  * @groupname: the name of the group
9bac43
  */
9bac43
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname)
9bac43
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
9bac43
+                                 const char *groupname)
9bac43
 {
9bac43
     int i;
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
+    BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
9bac43
+            throttle_group_member);
9bac43
+    BlockBackend *blk = blk_by_public(blkp);
9bac43
     ThrottleState *ts = throttle_group_incref(groupname);
9bac43
     ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
-    blkp->throttle_state = ts;
9bac43
+
9bac43
+    tgm->throttle_state = ts;
9bac43
 
9bac43
     qemu_mutex_lock(&tg->lock);
9bac43
-    /* If the ThrottleGroup is new set this BlockBackend as the token */
9bac43
+    /* If the ThrottleGroup is new set this ThrottleGroupMember as the token */
9bac43
     for (i = 0; i < 2; i++) {
9bac43
         if (!tg->tokens[i]) {
9bac43
-            tg->tokens[i] = blk;
9bac43
+            tg->tokens[i] = tgm;
9bac43
         }
9bac43
     }
9bac43
 
9bac43
-    QLIST_INSERT_HEAD(&tg->head, blkp, round_robin);
9bac43
+    QLIST_INSERT_HEAD(&tg->head, tgm, round_robin);
9bac43
 
9bac43
-    throttle_timers_init(&blkp->throttle_timers,
9bac43
+    throttle_timers_init(&tgm->throttle_timers,
9bac43
                          blk_get_aio_context(blk),
9bac43
                          tg->clock_type,
9bac43
                          read_timer_cb,
9bac43
@@ -518,45 +517,46 @@ void throttle_group_register_blk(BlockBackend *blk, const char *groupname)
9bac43
     qemu_mutex_unlock(&tg->lock);
9bac43
 }
9bac43
 
9bac43
-/* Unregister a BlockBackend from its group, removing it from the list,
9bac43
+/* Unregister a ThrottleGroupMember from its group, removing it from the list,
9bac43
  * destroying the timers and setting the throttle_state pointer to NULL.
9bac43
  *
9bac43
- * The BlockBackend must not have pending throttled requests, so the caller has
9bac43
- * to drain them first.
9bac43
+ * The ThrottleGroupMember must not have pending throttled requests, so the
9bac43
+ * caller has to drain them first.
9bac43
  *
9bac43
  * The group will be destroyed if it's empty after this operation.
9bac43
  *
9bac43
- * @blk: the BlockBackend to remove
9bac43
+ * @tgm the ThrottleGroupMember to remove
9bac43
  */
9bac43
-void throttle_group_unregister_blk(BlockBackend *blk)
9bac43
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
9bac43
 {
9bac43
-    BlockBackendPublic *blkp = blk_get_public(blk);
9bac43
-    ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
9bac43
+    ThrottleState *ts = tgm->throttle_state;
9bac43
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
9bac43
+    ThrottleGroupMember *token;
9bac43
     int i;
9bac43
 
9bac43
-    assert(blkp->pending_reqs[0] == 0 && blkp->pending_reqs[1] == 0);
9bac43
-    assert(qemu_co_queue_empty(&blkp->throttled_reqs[0]));
9bac43
-    assert(qemu_co_queue_empty(&blkp->throttled_reqs[1]));
9bac43
+    assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
9bac43
+    assert(qemu_co_queue_empty(&tgm->throttled_reqs[0]));
9bac43
+    assert(qemu_co_queue_empty(&tgm->throttled_reqs[1]));
9bac43
 
9bac43
     qemu_mutex_lock(&tg->lock);
9bac43
     for (i = 0; i < 2; i++) {
9bac43
-        if (tg->tokens[i] == blk) {
9bac43
-            BlockBackend *token = throttle_group_next_blk(blk);
9bac43
-            /* Take care of the case where this is the last blk in the group */
9bac43
-            if (token == blk) {
9bac43
+        if (tg->tokens[i] == tgm) {
9bac43
+            token = throttle_group_next_tgm(tgm);
9bac43
+            /* Take care of the case where this is the last tgm in the group */
9bac43
+            if (token == tgm) {
9bac43
                 token = NULL;
9bac43
             }
9bac43
             tg->tokens[i] = token;
9bac43
         }
9bac43
     }
9bac43
 
9bac43
-    /* remove the current blk from the list */
9bac43
-    QLIST_REMOVE(blkp, round_robin);
9bac43
-    throttle_timers_destroy(&blkp->throttle_timers);
9bac43
+    /* remove the current tgm from the list */
9bac43
+    QLIST_REMOVE(tgm, round_robin);
9bac43
+    throttle_timers_destroy(&tgm->throttle_timers);
9bac43
     qemu_mutex_unlock(&tg->lock);
9bac43
 
9bac43
     throttle_group_unref(&tg->ts);
9bac43
-    blkp->throttle_state = NULL;
9bac43
+    tgm->throttle_state = NULL;
9bac43
 }
9bac43
 
9bac43
 static void throttle_groups_init(void)
9bac43
diff --git a/blockdev.c b/blockdev.c
9bac43
index d54ea6f..0f063ec 100644
9bac43
--- a/blockdev.c
9bac43
+++ b/blockdev.c
9bac43
@@ -2729,7 +2729,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
9bac43
     if (throttle_enabled(&cfg)) {
9bac43
         /* Enable I/O limits if they're not enabled yet, otherwise
9bac43
          * just update the throttling group. */
9bac43
-        if (!blk_get_public(blk)->throttle_state) {
9bac43
+        if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
9bac43
             blk_io_limits_enable(blk,
9bac43
                                  arg->has_group ? arg->group :
9bac43
                                  arg->has_device ? arg->device :
9bac43
@@ -2739,7 +2739,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
9bac43
         }
9bac43
         /* Set the new throttling configuration */
9bac43
         blk_set_io_limits(blk, &cfg;;
9bac43
-    } else if (blk_get_public(blk)->throttle_state) {
9bac43
+    } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
9bac43
         /* If all throttling settings are set to 0, disable I/O limits */
9bac43
         blk_io_limits_disable(blk);
9bac43
     }
9bac43
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
9bac43
index d983d34..1a6bcda 100644
9bac43
--- a/include/block/throttle-groups.h
9bac43
+++ b/include/block/throttle-groups.h
9bac43
@@ -28,19 +28,44 @@
9bac43
 #include "qemu/throttle.h"
9bac43
 #include "block/block_int.h"
9bac43
 
9bac43
-const char *throttle_group_get_name(BlockBackend *blk);
9bac43
+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
9bac43
+ * and holds related data.
9bac43
+ */
9bac43
+
9bac43
+typedef struct ThrottleGroupMember {
9bac43
+    /* throttled_reqs_lock protects the CoQueues for throttled requests.  */
9bac43
+    CoMutex      throttled_reqs_lock;
9bac43
+    CoQueue      throttled_reqs[2];
9bac43
+
9bac43
+    /* Nonzero if the I/O limits are currently being ignored; generally
9bac43
+     * it is zero.  Accessed with atomic operations.
9bac43
+     */
9bac43
+    unsigned int io_limits_disabled;
9bac43
+
9bac43
+    /* The following fields are protected by the ThrottleGroup lock.
9bac43
+     * See the ThrottleGroup documentation for details.
9bac43
+     * throttle_state tells us if I/O limits are configured. */
9bac43
+    ThrottleState *throttle_state;
9bac43
+    ThrottleTimers throttle_timers;
9bac43
+    unsigned       pending_reqs[2];
9bac43
+    QLIST_ENTRY(ThrottleGroupMember) round_robin;
9bac43
+
9bac43
+} ThrottleGroupMember;
9bac43
+
9bac43
+const char *throttle_group_get_name(ThrottleGroupMember *tgm);
9bac43
 
9bac43
 ThrottleState *throttle_group_incref(const char *name);
9bac43
 void throttle_group_unref(ThrottleState *ts);
9bac43
 
9bac43
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg);
9bac43
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg);
9bac43
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
9bac43
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
9bac43
 
9bac43
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname);
9bac43
-void throttle_group_unregister_blk(BlockBackend *blk);
9bac43
-void throttle_group_restart_blk(BlockBackend *blk);
9bac43
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
9bac43
+                                const char *groupname);
9bac43
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
9bac43
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
9bac43
 
9bac43
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
9bac43
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
9bac43
                                                         unsigned int bytes,
9bac43
                                                         bool is_write);
9bac43
 
9bac43
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
9bac43
index aadc733..c4e52a5 100644
9bac43
--- a/include/sysemu/block-backend.h
9bac43
+++ b/include/sysemu/block-backend.h
9bac43
@@ -70,24 +70,10 @@ typedef struct BlockDevOps {
9bac43
 
9bac43
 /* This struct is embedded in (the private) BlockBackend struct and contains
9bac43
  * fields that must be public. This is in particular for QLIST_ENTRY() and
9bac43
- * friends so that BlockBackends can be kept in lists outside block-backend.c */
9bac43
+ * friends so that BlockBackends can be kept in lists outside block-backend.c
9bac43
+ * */
9bac43
 typedef struct BlockBackendPublic {
9bac43
-    /* throttled_reqs_lock protects the CoQueues for throttled requests.  */
9bac43
-    CoMutex      throttled_reqs_lock;
9bac43
-    CoQueue      throttled_reqs[2];
9bac43
-
9bac43
-    /* Nonzero if the I/O limits are currently being ignored; generally
9bac43
-     * it is zero.  Accessed with atomic operations.
9bac43
-     */
9bac43
-    unsigned int io_limits_disabled;
9bac43
-
9bac43
-    /* The following fields are protected by the ThrottleGroup lock.
9bac43
-     * See the ThrottleGroup documentation for details.
9bac43
-     * throttle_state tells us if I/O limits are configured. */
9bac43
-    ThrottleState *throttle_state;
9bac43
-    ThrottleTimers throttle_timers;
9bac43
-    unsigned       pending_reqs[2];
9bac43
-    QLIST_ENTRY(BlockBackendPublic) round_robin;
9bac43
+    ThrottleGroupMember throttle_group_member;
9bac43
 } BlockBackendPublic;
9bac43
 
9bac43
 BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
9bac43
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
9bac43
index 768f11d..6e6d926 100644
9bac43
--- a/tests/test-throttle.c
9bac43
+++ b/tests/test-throttle.c
9bac43
@@ -592,6 +592,7 @@ static void test_groups(void)
9bac43
     ThrottleConfig cfg1, cfg2;
9bac43
     BlockBackend *blk1, *blk2, *blk3;
9bac43
     BlockBackendPublic *blkp1, *blkp2, *blkp3;
9bac43
+    ThrottleGroupMember *tgm1, *tgm2, *tgm3;
9bac43
 
9bac43
     /* No actual I/O is performed on these devices */
9bac43
     blk1 = blk_new(0, BLK_PERM_ALL);
9bac43
@@ -602,21 +603,25 @@ static void test_groups(void)
9bac43
     blkp2 = blk_get_public(blk2);
9bac43
     blkp3 = blk_get_public(blk3);
9bac43
 
9bac43
-    g_assert(blkp1->throttle_state == NULL);
9bac43
-    g_assert(blkp2->throttle_state == NULL);
9bac43
-    g_assert(blkp3->throttle_state == NULL);
9bac43
+    tgm1 = &blkp1->throttle_group_member;
9bac43
+    tgm2 = &blkp2->throttle_group_member;
9bac43
+    tgm3 = &blkp3->throttle_group_member;
9bac43
 
9bac43
-    throttle_group_register_blk(blk1, "bar");
9bac43
-    throttle_group_register_blk(blk2, "foo");
9bac43
-    throttle_group_register_blk(blk3, "bar");
9bac43
+    g_assert(tgm1->throttle_state == NULL);
9bac43
+    g_assert(tgm2->throttle_state == NULL);
9bac43
+    g_assert(tgm3->throttle_state == NULL);
9bac43
 
9bac43
-    g_assert(blkp1->throttle_state != NULL);
9bac43
-    g_assert(blkp2->throttle_state != NULL);
9bac43
-    g_assert(blkp3->throttle_state != NULL);
9bac43
+    throttle_group_register_tgm(tgm1, "bar");
9bac43
+    throttle_group_register_tgm(tgm2, "foo");
9bac43
+    throttle_group_register_tgm(tgm3, "bar");
9bac43
 
9bac43
-    g_assert(!strcmp(throttle_group_get_name(blk1), "bar"));
9bac43
-    g_assert(!strcmp(throttle_group_get_name(blk2), "foo"));
9bac43
-    g_assert(blkp1->throttle_state == blkp3->throttle_state);
9bac43
+    g_assert(tgm1->throttle_state != NULL);
9bac43
+    g_assert(tgm2->throttle_state != NULL);
9bac43
+    g_assert(tgm3->throttle_state != NULL);
9bac43
+
9bac43
+    g_assert(!strcmp(throttle_group_get_name(tgm1), "bar"));
9bac43
+    g_assert(!strcmp(throttle_group_get_name(tgm2), "foo"));
9bac43
+    g_assert(tgm1->throttle_state == tgm3->throttle_state);
9bac43
 
9bac43
     /* Setting the config of a group member affects the whole group */
9bac43
     throttle_config_init(&cfg1);
9bac43
@@ -624,29 +629,29 @@ static void test_groups(void)
9bac43
     cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
9bac43
     cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
9bac43
     cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
9bac43
-    throttle_group_config(blk1, &cfg1);
9bac43
+    throttle_group_config(tgm1, &cfg1);
9bac43
 
9bac43
-    throttle_group_get_config(blk1, &cfg1);
9bac43
-    throttle_group_get_config(blk3, &cfg2);
9bac43
+    throttle_group_get_config(tgm1, &cfg1);
9bac43
+    throttle_group_get_config(tgm3, &cfg2);
9bac43
     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
9bac43
 
9bac43
     cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
9bac43
     cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
9bac43
     cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
9bac43
     cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
9bac43
-    throttle_group_config(blk3, &cfg1);
9bac43
+    throttle_group_config(tgm3, &cfg1);
9bac43
 
9bac43
-    throttle_group_get_config(blk1, &cfg1);
9bac43
-    throttle_group_get_config(blk3, &cfg2);
9bac43
+    throttle_group_get_config(tgm1, &cfg1);
9bac43
+    throttle_group_get_config(tgm3, &cfg2);
9bac43
     g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
9bac43
 
9bac43
-    throttle_group_unregister_blk(blk1);
9bac43
-    throttle_group_unregister_blk(blk2);
9bac43
-    throttle_group_unregister_blk(blk3);
9bac43
+    throttle_group_unregister_tgm(tgm1);
9bac43
+    throttle_group_unregister_tgm(tgm2);
9bac43
+    throttle_group_unregister_tgm(tgm3);
9bac43
 
9bac43
-    g_assert(blkp1->throttle_state == NULL);
9bac43
-    g_assert(blkp2->throttle_state == NULL);
9bac43
-    g_assert(blkp3->throttle_state == NULL);
9bac43
+    g_assert(tgm1->throttle_state == NULL);
9bac43
+    g_assert(tgm2->throttle_state == NULL);
9bac43
+    g_assert(tgm3->throttle_state == NULL);
9bac43
 }
9bac43
 
9bac43
 int main(int argc, char **argv)
9bac43
-- 
9bac43
1.8.3.1
9bac43