Skip to content

Commit f8222bf

Browse files
vmordankevmw
authored andcommitted
test-bdrv-drain: Fix data races
This patch addresses potential data races involving access to Job fields in the test-bdrv-drain test. Fixes: 7253220 ("test-bdrv-drain: Test drain vs. block jobs") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2900 Signed-off-by: Vitalii Mordan <[email protected]> Message-ID: <[email protected]> [kwolf: Fixed up coding style and one missing atomic access] Reviewed-by: Kevin Wolf <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
1 parent 61b6d9b commit f8222bf

File tree

3 files changed

+28
-13
lines changed

3 files changed

+28
-13
lines changed

include/qemu/job.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,9 @@ bool job_is_ready(Job *job);
545545
/* Same as job_is_ready(), but called with job lock held. */
546546
bool job_is_ready_locked(Job *job);
547547

548+
/** Returns whether the job is paused. Called with job_mutex *not* held. */
549+
bool job_is_paused(Job *job);
550+
548551
/**
549552
* Request @job to pause at the next pause point. Must be paired with
550553
* job_resume(). If the job is supposed to be resumed by user action, call

job.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ bool job_is_cancelled_locked(Job *job)
251251
return job->force_cancel;
252252
}
253253

254+
bool job_is_paused(Job *job)
255+
{
256+
JOB_LOCK_GUARD();
257+
return job->paused;
258+
}
259+
254260
bool job_is_cancelled(Job *job)
255261
{
256262
JOB_LOCK_GUARD();

tests/unit/test-bdrv-drain.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,8 @@ typedef struct TestBlockJob {
632632
BlockDriverState *bs;
633633
int run_ret;
634634
int prepare_ret;
635+
636+
/* Accessed with atomics */
635637
bool running;
636638
bool should_complete;
637639
} TestBlockJob;
@@ -667,10 +669,10 @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
667669

668670
/* We are running the actual job code past the pause point in
669671
* job_co_entry(). */
670-
s->running = true;
672+
qatomic_set(&s->running, true);
671673

672674
job_transition_to_ready(&s->common.job);
673-
while (!s->should_complete) {
675+
while (!qatomic_read(&s->should_complete)) {
674676
/* Avoid job_sleep_ns() because it marks the job as !busy. We want to
675677
* emulate some actual activity (probably some I/O) here so that drain
676678
* has to wait for this activity to stop. */
@@ -685,7 +687,7 @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
685687
static void test_job_complete(Job *job, Error **errp)
686688
{
687689
TestBlockJob *s = container_of(job, TestBlockJob, common.job);
688-
s->should_complete = true;
690+
qatomic_set(&s->should_complete, true);
689691
}
690692

691693
BlockJobDriver test_job_driver = {
@@ -791,15 +793,15 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
791793
/* job_co_entry() is run in the I/O thread, wait for the actual job
792794
* code to start (we don't want to catch the job in the pause point in
793795
* job_co_entry(). */
794-
while (!tjob->running) {
796+
while (!qatomic_read(&tjob->running)) {
795797
aio_poll(qemu_get_aio_context(), false);
796798
}
797799
}
798800

799801
WITH_JOB_LOCK_GUARD() {
800802
g_assert_cmpint(job->job.pause_count, ==, 0);
801803
g_assert_false(job->job.paused);
802-
g_assert_true(tjob->running);
804+
g_assert_true(qatomic_read(&tjob->running));
803805
g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */
804806
}
805807

@@ -825,7 +827,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
825827
*
826828
* paused is reset in the I/O thread, wait for it
827829
*/
828-
while (job->job.paused) {
830+
while (job_is_paused(&job->job)) {
829831
aio_poll(qemu_get_aio_context(), false);
830832
}
831833
}
@@ -858,7 +860,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
858860
*
859861
* paused is reset in the I/O thread, wait for it
860862
*/
861-
while (job->job.paused) {
863+
while (job_is_paused(&job->job)) {
862864
aio_poll(qemu_get_aio_context(), false);
863865
}
864866
}
@@ -1411,18 +1413,20 @@ static void test_set_aio_context(void)
14111413

14121414
typedef struct TestDropBackingBlockJob {
14131415
BlockJob common;
1414-
bool should_complete;
14151416
bool *did_complete;
14161417
BlockDriverState *detach_also;
14171418
BlockDriverState *bs;
1419+
1420+
/* Accessed with atomics */
1421+
bool should_complete;
14181422
} TestDropBackingBlockJob;
14191423

14201424
static int coroutine_fn test_drop_backing_job_run(Job *job, Error **errp)
14211425
{
14221426
TestDropBackingBlockJob *s =
14231427
container_of(job, TestDropBackingBlockJob, common.job);
14241428

1425-
while (!s->should_complete) {
1429+
while (!qatomic_read(&s->should_complete)) {
14261430
job_sleep_ns(job, 0);
14271431
}
14281432

@@ -1541,7 +1545,7 @@ static void test_blockjob_commit_by_drained_end(void)
15411545

15421546
job_start(&job->common.job);
15431547

1544-
job->should_complete = true;
1548+
qatomic_set(&job->should_complete, true);
15451549
bdrv_drained_begin(bs_child);
15461550
g_assert(!job_has_completed);
15471551
bdrv_drained_end(bs_child);
@@ -1557,15 +1561,17 @@ static void test_blockjob_commit_by_drained_end(void)
15571561

15581562
typedef struct TestSimpleBlockJob {
15591563
BlockJob common;
1560-
bool should_complete;
15611564
bool *did_complete;
1565+
1566+
/* Accessed with atomics */
1567+
bool should_complete;
15621568
} TestSimpleBlockJob;
15631569

15641570
static int coroutine_fn test_simple_job_run(Job *job, Error **errp)
15651571
{
15661572
TestSimpleBlockJob *s = container_of(job, TestSimpleBlockJob, common.job);
15671573

1568-
while (!s->should_complete) {
1574+
while (!qatomic_read(&s->should_complete)) {
15691575
job_sleep_ns(job, 0);
15701576
}
15711577

@@ -1700,7 +1706,7 @@ static void test_drop_intermediate_poll(void)
17001706
job->did_complete = &job_has_completed;
17011707

17021708
job_start(&job->common.job);
1703-
job->should_complete = true;
1709+
qatomic_set(&job->should_complete, true);
17041710

17051711
g_assert(!job_has_completed);
17061712
ret = bdrv_drop_intermediate(chain[1], chain[0], NULL, false);

0 commit comments

Comments
 (0)