Commit 93001e9d authored by Paolo Bonzini's avatar Paolo Bonzini Committed by Fam Zheng
Browse files

throttle-groups: protect throttled requests with a CoMutex



Another possibility is to use tg->lock, which we're holding anyway in
both schedule_next_request and throttle_group_co_io_limits_intercept.
This would require open-coding the CoQueue however, so I've chosen this
alternative.

Reviewed-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Message-Id: <20170605123908.18777-10-pbonzini@redhat.com>
Signed-off-by: default avatarFam Zheng <famz@redhat.com>
parent 3b170dc8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -216,6 +216,7 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
    blk->shared_perm = shared_perm;
    blk_set_enable_write_cache(blk, true);

    qemu_co_mutex_init(&blk->public.throttled_reqs_lock);
    qemu_co_queue_init(&blk->public.throttled_reqs[0]);
    qemu_co_queue_init(&blk->public.throttled_reqs[1]);

+10 −2
Original line number Diff line number Diff line
@@ -270,8 +270,13 @@ static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk,
                                                         bool is_write)
{
    BlockBackendPublic *blkp = blk_get_public(blk);
    bool ret;

    return qemu_co_queue_next(&blkp->throttled_reqs[is_write]);
    qemu_co_mutex_lock(&blkp->throttled_reqs_lock);
    ret = qemu_co_queue_next(&blkp->throttled_reqs[is_write]);
    qemu_co_mutex_unlock(&blkp->throttled_reqs_lock);

    return ret;
}

/* Look for the next pending I/O request and schedule it.
@@ -340,7 +345,10 @@ void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
    if (must_wait || blkp->pending_reqs[is_write]) {
        blkp->pending_reqs[is_write]++;
        qemu_mutex_unlock(&tg->lock);
        qemu_co_queue_wait(&blkp->throttled_reqs[is_write], NULL);
        qemu_co_mutex_lock(&blkp->throttled_reqs_lock);
        qemu_co_queue_wait(&blkp->throttled_reqs[is_write],
                           &blkp->throttled_reqs_lock);
        qemu_co_mutex_unlock(&blkp->throttled_reqs_lock);
        qemu_mutex_lock(&tg->lock);
        blkp->pending_reqs[is_write]--;
    }
+2 −5
Original line number Diff line number Diff line
@@ -72,11 +72,8 @@ typedef struct BlockDevOps {
 * fields that must be public. This is in particular for QLIST_ENTRY() and
 * friends so that BlockBackends can be kept in lists outside block-backend.c */
typedef struct BlockBackendPublic {
    /* I/O throttling has its own locking, but also some fields are
     * protected by the AioContext lock.
     */

    /* Protected by AioContext lock.  */
    /* throttled_reqs_lock protects the CoQueues for throttled requests.  */
    CoMutex      throttled_reqs_lock;
    CoQueue      throttled_reqs[2];

    /* Nonzero if the I/O limits are currently being ignored; generally