Skip to content

Commit cfe29d8

Browse files
committed
block: Use a single global AioWait
When draining a block node, we recurse to its parent and for subtree drains also to its children. A single AIO_WAIT_WHILE() is then used to wait for bdrv_drain_poll() to become true, which depends on all of the nodes we recursed to. However, if the respective child or parent becomes quiescent and calls bdrv_wakeup(), only the AioWait of the child/parent is checked, while AIO_WAIT_WHILE() depends on the AioWait of the original node. Fix this by using a single AioWait for all callers of AIO_WAIT_WHILE(). This may mean that the draining thread gets a few more unnecessary wakeups because an unrelated operation got completed, but we already wake it up when something _could_ have changed rather than only if it has certainly changed. Apart from that, drain is a slow path anyway. In theory it would be possible to use wakeups more selectively and still correctly, but the gains are likely not worth the additional complexity. In fact, this patch is a nice simplification for some places in the code. Signed-off-by: Kevin Wolf <[email protected]> Reviewed-by: Eric Blake <[email protected]> Reviewed-by: Max Reitz <[email protected]>
1 parent 5599c16 commit cfe29d8

File tree

10 files changed

+26
-65
lines changed

10 files changed

+26
-65
lines changed

block.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4886,11 +4886,6 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs)
48864886
return bs ? bs->aio_context : qemu_get_aio_context();
48874887
}
48884888

4889-
AioWait *bdrv_get_aio_wait(BlockDriverState *bs)
4890-
{
4891-
return bs ? &bs->wait : NULL;
4892-
}
4893-
48944889
void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co)
48954890
{
48964891
aio_co_enter(bdrv_get_aio_context(bs), co);

block/block-backend.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ struct BlockBackend {
8888
* Accessed with atomic ops.
8989
*/
9090
unsigned int in_flight;
91-
AioWait wait;
9291
};
9392

9493
typedef struct BlockBackendAIOCB {
@@ -1298,7 +1297,7 @@ static void blk_inc_in_flight(BlockBackend *blk)
12981297
static void blk_dec_in_flight(BlockBackend *blk)
12991298
{
13001299
atomic_dec(&blk->in_flight);
1301-
aio_wait_kick(&blk->wait);
1300+
aio_wait_kick();
13021301
}
13031302

13041303
static void error_callback_bh(void *opaque)
@@ -1599,9 +1598,8 @@ void blk_drain(BlockBackend *blk)
15991598
}
16001599

16011600
/* We may have -ENOMEDIUM completions in flight */
1602-
AIO_WAIT_WHILE(&blk->wait,
1603-
blk_get_aio_context(blk),
1604-
atomic_mb_read(&blk->in_flight) > 0);
1601+
AIO_WAIT_WHILE(blk_get_aio_context(blk),
1602+
atomic_mb_read(&blk->in_flight) > 0);
16051603

16061604
if (bs) {
16071605
bdrv_drained_end(bs);
@@ -1620,8 +1618,7 @@ void blk_drain_all(void)
16201618
aio_context_acquire(ctx);
16211619

16221620
/* We may have -ENOMEDIUM completions in flight */
1623-
AIO_WAIT_WHILE(&blk->wait, ctx,
1624-
atomic_mb_read(&blk->in_flight) > 0);
1621+
AIO_WAIT_WHILE(ctx, atomic_mb_read(&blk->in_flight) > 0);
16251622

16261623
aio_context_release(ctx);
16271624
}

block/io.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838
/* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
3939
#define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
4040

41-
static AioWait drain_all_aio_wait;
42-
4341
static void bdrv_parent_cb_resize(BlockDriverState *bs);
4442
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
4543
int64_t offset, int bytes, BdrvRequestFlags flags);
@@ -557,7 +555,7 @@ void bdrv_drain_all_begin(void)
557555
}
558556

559557
/* Now poll the in-flight requests */
560-
AIO_WAIT_WHILE(&drain_all_aio_wait, NULL, bdrv_drain_all_poll());
558+
AIO_WAIT_WHILE(NULL, bdrv_drain_all_poll());
561559

562560
while ((bs = bdrv_next_all_states(bs))) {
563561
bdrv_drain_assert_idle(bs);
@@ -713,8 +711,7 @@ void bdrv_inc_in_flight(BlockDriverState *bs)
713711

714712
void bdrv_wakeup(BlockDriverState *bs)
715713
{
716-
aio_wait_kick(bdrv_get_aio_wait(bs));
717-
aio_wait_kick(&drain_all_aio_wait);
714+
aio_wait_kick();
718715
}
719716

720717
void bdrv_dec_in_flight(BlockDriverState *bs)

blockjob.c

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,9 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
221221
return 0;
222222
}
223223

224-
void block_job_wakeup_all_bdrv(BlockJob *job)
225-
{
226-
GSList *l;
227-
228-
for (l = job->nodes; l; l = l->next) {
229-
BdrvChild *c = l->data;
230-
bdrv_wakeup(c->bs);
231-
}
232-
}
233-
234224
static void block_job_on_idle(Notifier *n, void *opaque)
235225
{
236-
BlockJob *job = opaque;
237-
block_job_wakeup_all_bdrv(job);
226+
aio_wait_kick();
238227
}
239228

240229
bool block_job_is_internal(BlockJob *job)

include/block/aio-wait.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@
3030
/**
3131
* AioWait:
3232
*
33-
* An object that facilitates synchronous waiting on a condition. The main
34-
* loop can wait on an operation running in an IOThread as follows:
33+
* An object that facilitates synchronous waiting on a condition. A single
34+
* global AioWait object (global_aio_wait) is used internally.
35+
*
36+
* The main loop can wait on an operation running in an IOThread as follows:
3537
*
36-
* AioWait *wait = ...;
3738
* AioContext *ctx = ...;
3839
* MyWork work = { .done = false };
3940
* schedule_my_work_in_iothread(ctx, &work);
40-
* AIO_WAIT_WHILE(wait, ctx, !work.done);
41+
* AIO_WAIT_WHILE(ctx, !work.done);
4142
*
4243
* The IOThread must call aio_wait_kick() to notify the main loop when
4344
* work.done changes:
@@ -46,17 +47,18 @@
4647
* {
4748
* ...
4849
* work.done = true;
49-
* aio_wait_kick(wait);
50+
* aio_wait_kick();
5051
* }
5152
*/
5253
typedef struct {
5354
/* Number of waiting AIO_WAIT_WHILE() callers. Accessed with atomic ops. */
5455
unsigned num_waiters;
5556
} AioWait;
5657

58+
extern AioWait global_aio_wait;
59+
5760
/**
5861
* AIO_WAIT_WHILE:
59-
* @wait: the aio wait object
6062
* @ctx: the aio context, or NULL if multiple aio contexts (for which the
6163
* caller does not hold a lock) are involved in the polling condition.
6264
* @cond: wait while this conditional expression is true
@@ -72,9 +74,9 @@ typedef struct {
7274
* wait on conditions between two IOThreads since that could lead to deadlock,
7375
* go via the main loop instead.
7476
*/
75-
#define AIO_WAIT_WHILE(wait, ctx, cond) ({ \
77+
#define AIO_WAIT_WHILE(ctx, cond) ({ \
7678
bool waited_ = false; \
77-
AioWait *wait_ = (wait); \
79+
AioWait *wait_ = &global_aio_wait; \
7880
AioContext *ctx_ = (ctx); \
7981
/* Increment wait_->num_waiters before evaluating cond. */ \
8082
atomic_inc(&wait_->num_waiters); \
@@ -102,14 +104,12 @@ typedef struct {
102104

103105
/**
104106
* aio_wait_kick:
105-
* @wait: the aio wait object that should re-evaluate its condition
106-
*
107107
* Wake up the main thread if it is waiting on AIO_WAIT_WHILE(). During
108108
* synchronous operations performed in an IOThread, the main thread lets the
109109
* IOThread's event loop run, waiting for the operation to complete. A
110110
* aio_wait_kick() call will wake up the main thread.
111111
*/
112-
void aio_wait_kick(AioWait *wait);
112+
void aio_wait_kick(void);
113113

114114
/**
115115
* aio_wait_bh_oneshot:

include/block/block.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -410,13 +410,9 @@ void bdrv_drain_all_begin(void);
410410
void bdrv_drain_all_end(void);
411411
void bdrv_drain_all(void);
412412

413-
/* Returns NULL when bs == NULL */
414-
AioWait *bdrv_get_aio_wait(BlockDriverState *bs);
415-
416413
#define BDRV_POLL_WHILE(bs, cond) ({ \
417414
BlockDriverState *bs_ = (bs); \
418-
AIO_WAIT_WHILE(bdrv_get_aio_wait(bs_), \
419-
bdrv_get_aio_context(bs_), \
415+
AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \
420416
cond); })
421417

422418
int bdrv_pdiscard(BdrvChild *child, int64_t offset, int bytes);

include/block/block_int.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -794,9 +794,6 @@ struct BlockDriverState {
794794
unsigned int in_flight;
795795
unsigned int serialising_in_flight;
796796

797-
/* Kicked to signal main loop when a request completes. */
798-
AioWait wait;
799-
800797
/* counter for nested bdrv_io_plug.
801798
* Accessed with atomic ops.
802799
*/

include/block/blockjob.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,6 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
121121
*/
122122
void block_job_remove_all_bdrv(BlockJob *job);
123123

124-
/**
125-
* block_job_wakeup_all_bdrv:
126-
* @job: The block job
127-
*
128-
* Calls bdrv_wakeup() for all BlockDriverStates that have been added to the
129-
* job. This function is to be called whenever child_job_drained_poll() would
130-
* go from true to false to notify waiting drain requests.
131-
*/
132-
void block_job_wakeup_all_bdrv(BlockJob *job);
133-
134124
/**
135125
* block_job_set_speed:
136126
* @job: The job to set the speed for.

job.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,6 @@ void job_complete(Job *job, Error **errp)
978978
int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
979979
{
980980
Error *local_err = NULL;
981-
AioWait dummy_wait = {};
982981
int ret;
983982

984983
job_ref(job);
@@ -992,7 +991,7 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
992991
return -EBUSY;
993992
}
994993

995-
AIO_WAIT_WHILE(&dummy_wait, job->aio_context,
994+
AIO_WAIT_WHILE(job->aio_context,
996995
(job_drain(job), !job_is_completed(job)));
997996

998997
ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret;

util/aio-wait.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,22 @@
2626
#include "qemu/main-loop.h"
2727
#include "block/aio-wait.h"
2828

29+
AioWait global_aio_wait;
30+
2931
static void dummy_bh_cb(void *opaque)
3032
{
3133
/* The point is to make AIO_WAIT_WHILE()'s aio_poll() return */
3234
}
3335

34-
void aio_wait_kick(AioWait *wait)
36+
void aio_wait_kick(void)
3537
{
3638
/* The barrier (or an atomic op) is in the caller. */
37-
if (atomic_read(&wait->num_waiters)) {
39+
if (atomic_read(&global_aio_wait.num_waiters)) {
3840
aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
3941
}
4042
}
4143

4244
typedef struct {
43-
AioWait wait;
4445
bool done;
4546
QEMUBHFunc *cb;
4647
void *opaque;
@@ -54,7 +55,7 @@ static void aio_wait_bh(void *opaque)
5455
data->cb(data->opaque);
5556

5657
data->done = true;
57-
aio_wait_kick(&data->wait);
58+
aio_wait_kick();
5859
}
5960

6061
void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
@@ -67,5 +68,5 @@ void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
6768
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
6869

6970
aio_bh_schedule_oneshot(ctx, aio_wait_bh, &data);
70-
AIO_WAIT_WHILE(&data.wait, ctx, !data.done);
71+
AIO_WAIT_WHILE(ctx, !data.done);
7172
}

0 commit comments

Comments
 (0)