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

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