throttle-groups: protect throttled requests with a CoMutex
Another possibility is to use tg->lock, which we're holding anyway in both schedule_next_request and throttle_group_co_io_limits_intercept. This would require open-coding the CoQueue however, so I've chosen this alternative. Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20170605123908.18777-10-pbonzini@redhat.com> Signed-off-by: Fam Zheng <famz@redhat.com>
This commit is contained in:
parent
3b170dc867
commit
93001e9d87
@ -216,6 +216,7 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
|
|||||||
blk->shared_perm = shared_perm;
|
blk->shared_perm = shared_perm;
|
||||||
blk_set_enable_write_cache(blk, true);
|
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[0]);
|
||||||
qemu_co_queue_init(&blk->public.throttled_reqs[1]);
|
qemu_co_queue_init(&blk->public.throttled_reqs[1]);
|
||||||
|
|
||||||
|
@ -270,8 +270,13 @@ static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk,
|
|||||||
bool is_write)
|
bool is_write)
|
||||||
{
|
{
|
||||||
BlockBackendPublic *blkp = blk_get_public(blk);
|
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.
|
/* 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]) {
|
if (must_wait || blkp->pending_reqs[is_write]) {
|
||||||
blkp->pending_reqs[is_write]++;
|
blkp->pending_reqs[is_write]++;
|
||||||
qemu_mutex_unlock(&tg->lock);
|
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);
|
qemu_mutex_lock(&tg->lock);
|
||||||
blkp->pending_reqs[is_write]--;
|
blkp->pending_reqs[is_write]--;
|
||||||
}
|
}
|
||||||
|
@ -72,11 +72,8 @@ typedef struct BlockDevOps {
|
|||||||
* fields that must be public. This is in particular for QLIST_ENTRY() and
|
* 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 */
|
* friends so that BlockBackends can be kept in lists outside block-backend.c */
|
||||||
typedef struct BlockBackendPublic {
|
typedef struct BlockBackendPublic {
|
||||||
/* I/O throttling has its own locking, but also some fields are
|
/* throttled_reqs_lock protects the CoQueues for throttled requests. */
|
||||||
* protected by the AioContext lock.
|
CoMutex throttled_reqs_lock;
|
||||||
*/
|
|
||||||
|
|
||||||
/* Protected by AioContext lock. */
|
|
||||||
CoQueue throttled_reqs[2];
|
CoQueue throttled_reqs[2];
|
||||||
|
|
||||||
/* Nonzero if the I/O limits are currently being ignored; generally
|
/* Nonzero if the I/O limits are currently being ignored; generally
|
||||||
|
Loading…
Reference in New Issue
Block a user