]> git.proxmox.com Git - mirror_qemu.git/blobdiff - tests/test-blockjob-txn.c
Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2019-06-24' into staging
[mirror_qemu.git] / tests / test-blockjob-txn.c
index 4ccbda14affdeed5dc41393034ec7b86d1c0b5be..86606f92b3790cb697b1fe224e8e631abdbdcf03 100644 (file)
@@ -24,38 +24,31 @@ typedef struct {
     int *result;
 } TestBlockJob;
 
-static void test_block_job_complete(BlockJob *job, void *opaque)
+static void test_block_job_clean(Job *job)
 {
-    BlockDriverState *bs = blk_bs(job->blk);
-    int rc = (intptr_t)opaque;
+    BlockJob *bjob = container_of(job, BlockJob, job);
+    BlockDriverState *bs = blk_bs(bjob->blk);
 
-    if (block_job_is_cancelled(job)) {
-        rc = -ECANCELED;
-    }
-
-    block_job_completed(job, rc);
     bdrv_unref(bs);
 }
 
-static void coroutine_fn test_block_job_run(void *opaque)
+static int coroutine_fn test_block_job_run(Job *job, Error **errp)
 {
-    TestBlockJob *s = opaque;
-    BlockJob *job = &s->common;
+    TestBlockJob *s = container_of(job, TestBlockJob, common.job);
 
     while (s->iterations--) {
         if (s->use_timer) {
-            block_job_sleep_ns(job, QEMU_CLOCK_REALTIME, 0);
+            job_sleep_ns(job, 0);
         } else {
-            block_job_yield(job);
+            job_yield(job);
         }
 
-        if (block_job_is_cancelled(job)) {
+        if (job_is_cancelled(job)) {
             break;
         }
     }
 
-    block_job_defer_to_main_loop(job, test_block_job_complete,
-                                 (void *)(intptr_t)s->rc);
+    return s->rc;
 }
 
 typedef struct {
@@ -66,7 +59,7 @@ typedef struct {
 static void test_block_job_cb(void *opaque, int ret)
 {
     TestBlockJobCBData *data = opaque;
-    if (!ret && block_job_is_cancelled(&data->job->common)) {
+    if (!ret && job_is_cancelled(&data->job->common.job)) {
         ret = -ECANCELED;
     }
     *data->result = ret;
@@ -74,8 +67,14 @@ static void test_block_job_cb(void *opaque, int ret)
 }
 
 static const BlockJobDriver test_block_job_driver = {
-    .instance_size = sizeof(TestBlockJob),
-    .start = test_block_job_run,
+    .job_driver = {
+        .instance_size = sizeof(TestBlockJob),
+        .free          = block_job_free,
+        .user_resume   = block_job_user_resume,
+        .drain         = block_job_drain,
+        .run           = test_block_job_run,
+        .clean         = test_block_job_clean,
+    },
 };
 
 /* Create a block job that completes with a given return code after a given
@@ -87,7 +86,7 @@ static const BlockJobDriver test_block_job_driver = {
  */
 static BlockJob *test_block_job_start(unsigned int iterations,
                                       bool use_timer,
-                                      int rc, int *result)
+                                      int rc, int *result, JobTxn *txn)
 {
     BlockDriverState *bs;
     TestBlockJob *s;
@@ -101,8 +100,8 @@ static BlockJob *test_block_job_start(unsigned int iterations,
     g_assert_nonnull(bs);
 
     snprintf(job_id, sizeof(job_id), "job%u", counter++);
-    s = block_job_create(job_id, &test_block_job_driver, bs,
-                         0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT,
+    s = block_job_create(job_id, &test_block_job_driver, txn, bs,
+                         0, BLK_PERM_ALL, 0, JOB_DEFAULT,
                          test_block_job_cb, data, &error_abort);
     s->iterations = iterations;
     s->use_timer = use_timer;
@@ -110,22 +109,21 @@ static BlockJob *test_block_job_start(unsigned int iterations,
     s->result = result;
     data->job = s;
     data->result = result;
-    block_job_start(&s->common);
     return &s->common;
 }
 
 static void test_single_job(int expected)
 {
     BlockJob *job;
-    BlockJobTxn *txn;
+    JobTxn *txn;
     int result = -EINPROGRESS;
 
-    txn = block_job_txn_new();
-    job = test_block_job_start(1, true, expected, &result);
-    block_job_txn_add_job(txn, job);
+    txn = job_txn_new();
+    job = test_block_job_start(1, true, expected, &result, txn);
+    job_start(&job->job);
 
     if (expected == -ECANCELED) {
-        block_job_cancel(job);
+        job_cancel(&job->job, false);
     }
 
     while (result == -EINPROGRESS) {
@@ -133,7 +131,7 @@ static void test_single_job(int expected)
     }
     g_assert_cmpint(result, ==, expected);
 
-    block_job_txn_unref(txn);
+    job_txn_unref(txn);
 }
 
 static void test_single_job_success(void)
@@ -155,21 +153,26 @@ static void test_pair_jobs(int expected1, int expected2)
 {
     BlockJob *job1;
     BlockJob *job2;
-    BlockJobTxn *txn;
+    JobTxn *txn;
     int result1 = -EINPROGRESS;
     int result2 = -EINPROGRESS;
 
-    txn = block_job_txn_new();
-    job1 = test_block_job_start(1, true, expected1, &result1);
-    block_job_txn_add_job(txn, job1);
-    job2 = test_block_job_start(2, true, expected2, &result2);
-    block_job_txn_add_job(txn, job2);
+    txn = job_txn_new();
+    job1 = test_block_job_start(1, true, expected1, &result1, txn);
+    job2 = test_block_job_start(2, true, expected2, &result2, txn);
+    job_start(&job1->job);
+    job_start(&job2->job);
+
+    /* Release our reference now to trigger as many nice
+     * use-after-free bugs as possible.
+     */
+    job_txn_unref(txn);
 
     if (expected1 == -ECANCELED) {
-        block_job_cancel(job1);
+        job_cancel(&job1->job, false);
     }
     if (expected2 == -ECANCELED) {
-        block_job_cancel(job2);
+        job_cancel(&job2->job, false);
     }
 
     while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) {
@@ -185,8 +188,6 @@ static void test_pair_jobs(int expected1, int expected2)
 
     g_assert_cmpint(result1, ==, expected1);
     g_assert_cmpint(result2, ==, expected2);
-
-    block_job_txn_unref(txn);
 }
 
 static void test_pair_jobs_success(void)
@@ -214,23 +215,23 @@ static void test_pair_jobs_fail_cancel_race(void)
 {
     BlockJob *job1;
     BlockJob *job2;
-    BlockJobTxn *txn;
+    JobTxn *txn;
     int result1 = -EINPROGRESS;
     int result2 = -EINPROGRESS;
 
-    txn = block_job_txn_new();
-    job1 = test_block_job_start(1, true, -ECANCELED, &result1);
-    block_job_txn_add_job(txn, job1);
-    job2 = test_block_job_start(2, false, 0, &result2);
-    block_job_txn_add_job(txn, job2);
+    txn = job_txn_new();
+    job1 = test_block_job_start(1, true, -ECANCELED, &result1, txn);
+    job2 = test_block_job_start(2, false, 0, &result2, txn);
+    job_start(&job1->job);
+    job_start(&job2->job);
 
-    block_job_cancel(job1);
+    job_cancel(&job1->job, false);
 
     /* Now make job2 finish before the main loop kicks jobs.  This simulates
      * the race between a pending kick and another job completing.
      */
-    block_job_enter(job2);
-    block_job_enter(job2);
+    job_enter(&job2->job);
+    job_enter(&job2->job);
 
     while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) {
         aio_poll(qemu_get_aio_context(), true);
@@ -239,7 +240,7 @@ static void test_pair_jobs_fail_cancel_race(void)
     g_assert_cmpint(result1, ==, -ECANCELED);
     g_assert_cmpint(result2, ==, -ECANCELED);
 
-    block_job_txn_unref(txn);
+    job_txn_unref(txn);
 }
 
 int main(int argc, char **argv)