... | ... | ||
---|---|---|---|
3 | 3 | ||
4 | Fixes: d354c7eccf ("aio: add generic thread-pool facility") | 4 | Fixes: d354c7eccf ("aio: add generic thread-pool facility") |
5 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2822 | 5 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2822 |
6 | Signed-off-by: Vitalii Mordan <mordan@ispras.ru> | 6 | Signed-off-by: Vitalii Mordan <mordan@ispras.ru> |
7 | --- | 7 | --- |
8 | util/thread-pool.c | 13 ++++++------- | 8 | v2: Addressed the Paolo Bonzini comments. |
9 | 1 file changed, 6 insertions(+), 7 deletions(-) | 9 | util/thread-pool.c | 18 +++++++++--------- |
10 | 1 file changed, 9 insertions(+), 9 deletions(-) | ||
10 | 11 | ||
11 | diff --git a/util/thread-pool.c b/util/thread-pool.c | 12 | diff --git a/util/thread-pool.c b/util/thread-pool.c |
12 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/util/thread-pool.c | 14 | --- a/util/thread-pool.c |
14 | +++ b/util/thread-pool.c | 15 | +++ b/util/thread-pool.c |
... | ... | ||
27 | @@ -XXX,XX +XXX,XX @@ static void thread_pool_completion_bh(void *opaque) | 28 | @@ -XXX,XX +XXX,XX @@ static void thread_pool_completion_bh(void *opaque) |
28 | 29 | ||
29 | restart: | 30 | restart: |
30 | QLIST_FOREACH_SAFE(elem, &pool->head, all, next) { | 31 | QLIST_FOREACH_SAFE(elem, &pool->head, all, next) { |
31 | - if (elem->state != THREAD_DONE) { | 32 | - if (elem->state != THREAD_DONE) { |
33 | + /* Atomically access the state field to synchronize with the | ||
34 | + * worker_thread and thread_pool_cancel. | ||
35 | + */ | ||
32 | + if (qatomic_load_acquire(&elem->state) != THREAD_DONE) { | 36 | + if (qatomic_load_acquire(&elem->state) != THREAD_DONE) { |
33 | continue; | 37 | continue; |
34 | } | 38 | } |
35 | 39 | ||
40 | @@ -XXX,XX +XXX,XX @@ restart: | ||
41 | QLIST_REMOVE(elem, all); | ||
42 | |||
43 | if (elem->common.cb) { | ||
44 | - /* Read state before ret. */ | ||
45 | - smp_rmb(); | ||
46 | - | ||
47 | /* Schedule ourselves in case elem->common.cb() calls aio_poll() to | ||
48 | * wait for another request that completed at the same time. | ||
49 | */ | ||
36 | @@ -XXX,XX +XXX,XX @@ static void thread_pool_cancel(BlockAIOCB *acb) | 50 | @@ -XXX,XX +XXX,XX @@ static void thread_pool_cancel(BlockAIOCB *acb) |
37 | trace_thread_pool_cancel(elem, elem->common.opaque); | 51 | trace_thread_pool_cancel(elem, elem->common.opaque); |
38 | 52 | ||
39 | QEMU_LOCK_GUARD(&pool->lock); | 53 | QEMU_LOCK_GUARD(&pool->lock); |
40 | - if (elem->state == THREAD_QUEUED) { | 54 | - if (elem->state == THREAD_QUEUED) { |
41 | + if (qatomic_load_acquire(&elem->state) == THREAD_QUEUED) { | 55 | + if (qatomic_read(&elem->state) == THREAD_QUEUED) { |
42 | QTAILQ_REMOVE(&pool->request_list, elem, reqs); | 56 | QTAILQ_REMOVE(&pool->request_list, elem, reqs); |
43 | qemu_bh_schedule(pool->completion_bh); | 57 | qemu_bh_schedule(pool->completion_bh); |
44 | 58 | ||
45 | - elem->state = THREAD_DONE; | 59 | - elem->state = THREAD_DONE; |
46 | elem->ret = -ECANCELED; | 60 | elem->ret = -ECANCELED; |
61 | + /* Atomically update state after setting ret. */ | ||
47 | + qatomic_store_release(&elem->state, THREAD_DONE); | 62 | + qatomic_store_release(&elem->state, THREAD_DONE); |
48 | } | 63 | } |
49 | 64 | ||
50 | } | 65 | } |
51 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, | ||
52 | req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque); | ||
53 | req->func = func; | ||
54 | req->arg = arg; | ||
55 | - req->state = THREAD_QUEUED; | ||
56 | req->pool = pool; | ||
57 | + qatomic_store_release(&req->state, THREAD_QUEUED); | ||
58 | |||
59 | QLIST_INSERT_HEAD(&pool->head, req, all); | ||
60 | |||
61 | -- | 66 | -- |
62 | 2.34.1 | 67 | 2.34.1 | diff view generated by jsdifflib |