19ef8112aSAlberto Garcia /* 29ef8112aSAlberto Garcia * Blockjob tests 39ef8112aSAlberto Garcia * 49ef8112aSAlberto Garcia * Copyright Igalia, S.L. 2016 59ef8112aSAlberto Garcia * 69ef8112aSAlberto Garcia * Authors: 79ef8112aSAlberto Garcia * Alberto Garcia <berto@igalia.com> 89ef8112aSAlberto Garcia * 99ef8112aSAlberto Garcia * This work is licensed under the terms of the GNU LGPL, version 2 or later. 109ef8112aSAlberto Garcia * See the COPYING.LIB file in the top-level directory. 119ef8112aSAlberto Garcia */ 129ef8112aSAlberto Garcia 139ef8112aSAlberto Garcia #include "qemu/osdep.h" 149ef8112aSAlberto Garcia #include "qapi/error.h" 159ef8112aSAlberto Garcia #include "qemu/main-loop.h" 16c87621eaSJohn Snow #include "block/blockjob_int.h" 179ef8112aSAlberto Garcia #include "sysemu/block-backend.h" 18ca1ef1e6SAndrey Shinkevich #include "qapi/qmp/qdict.h" 19c2c731a4SMax Reitz #include "iothread.h" 209ef8112aSAlberto Garcia 219ef8112aSAlberto Garcia static const BlockJobDriver test_block_job_driver = { 2233e9e9bdSKevin Wolf .job_driver = { 239ef8112aSAlberto Garcia .instance_size = sizeof(BlockJob), 2480fa2c75SKevin Wolf .free = block_job_free, 25b15de828SKevin Wolf .user_resume = block_job_user_resume, 2633e9e9bdSKevin Wolf }, 279ef8112aSAlberto Garcia }; 289ef8112aSAlberto Garcia 299ef8112aSAlberto Garcia static void block_job_cb(void *opaque, int ret) 309ef8112aSAlberto Garcia { 319ef8112aSAlberto Garcia } 329ef8112aSAlberto Garcia 33fb367e03SJohn Snow static BlockJob *mk_job(BlockBackend *blk, const char *id, 34fb367e03SJohn Snow const BlockJobDriver *drv, bool should_succeed, 35fb367e03SJohn Snow int flags) 369ef8112aSAlberto Garcia { 379ef8112aSAlberto Garcia BlockJob *job; 388ca63ba8SMarkus Armbruster Error *err = NULL; 399ef8112aSAlberto Garcia 40fb367e03SJohn Snow job = block_job_create(id, drv, NULL, blk_bs(blk), 41fb367e03SJohn Snow 0, BLK_PERM_ALL, 0, flags, block_job_cb, 428ca63ba8SMarkus Armbruster NULL, &err); 439ef8112aSAlberto Garcia if (should_succeed) { 448ca63ba8SMarkus Armbruster g_assert_null(err); 459ef8112aSAlberto Garcia g_assert_nonnull(job); 469ef8112aSAlberto Garcia if (id) { 4733e9e9bdSKevin Wolf g_assert_cmpstr(job->job.id, ==, id); 489ef8112aSAlberto Garcia } else { 4933e9e9bdSKevin Wolf g_assert_cmpstr(job->job.id, ==, blk_name(blk)); 509ef8112aSAlberto Garcia } 519ef8112aSAlberto Garcia } else { 520cf9e2b4SMarkus Armbruster error_free_or_abort(&err); 539ef8112aSAlberto Garcia g_assert_null(job); 549ef8112aSAlberto Garcia } 559ef8112aSAlberto Garcia 569ef8112aSAlberto Garcia return job; 579ef8112aSAlberto Garcia } 589ef8112aSAlberto Garcia 59fb367e03SJohn Snow static BlockJob *do_test_id(BlockBackend *blk, const char *id, 60fb367e03SJohn Snow bool should_succeed) 61fb367e03SJohn Snow { 62fb367e03SJohn Snow return mk_job(blk, id, &test_block_job_driver, 63bb02b65cSKevin Wolf should_succeed, JOB_DEFAULT); 64fb367e03SJohn Snow } 65fb367e03SJohn Snow 669ef8112aSAlberto Garcia /* This creates a BlockBackend (optionally with a name) with a 679ef8112aSAlberto Garcia * BlockDriverState inserted. */ 689ef8112aSAlberto Garcia static BlockBackend *create_blk(const char *name) 699ef8112aSAlberto Garcia { 702807c0cdSKevin Wolf /* No I/O is performed on this device */ 71d861ab3aSKevin Wolf BlockBackend *blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); 72d185cf0eSKevin Wolf BlockDriverState *bs; 73d185cf0eSKevin Wolf 74ca1ef1e6SAndrey Shinkevich QDict *opt = qdict_new(); 75ca1ef1e6SAndrey Shinkevich qdict_put_str(opt, "file.read-zeroes", "on"); 76ca1ef1e6SAndrey Shinkevich bs = bdrv_open("null-co://", NULL, opt, 0, &error_abort); 77d185cf0eSKevin Wolf g_assert_nonnull(bs); 789ef8112aSAlberto Garcia 79d7086422SKevin Wolf blk_insert_bs(blk, bs, &error_abort); 809ef8112aSAlberto Garcia bdrv_unref(bs); 819ef8112aSAlberto Garcia 829ef8112aSAlberto Garcia if (name) { 838ca63ba8SMarkus Armbruster Error *err = NULL; 848ca63ba8SMarkus Armbruster monitor_add_blk(blk, name, &err); 858ca63ba8SMarkus Armbruster g_assert_null(err); 869ef8112aSAlberto Garcia } 879ef8112aSAlberto Garcia 889ef8112aSAlberto Garcia return blk; 899ef8112aSAlberto Garcia } 909ef8112aSAlberto Garcia 919ef8112aSAlberto Garcia /* This destroys the backend */ 929ef8112aSAlberto Garcia static void destroy_blk(BlockBackend *blk) 939ef8112aSAlberto Garcia { 949ef8112aSAlberto Garcia if (blk_name(blk)[0] != '\0') { 959ef8112aSAlberto Garcia monitor_remove_blk(blk); 969ef8112aSAlberto Garcia } 979ef8112aSAlberto Garcia 989ef8112aSAlberto Garcia blk_remove_bs(blk); 999ef8112aSAlberto Garcia blk_unref(blk); 1009ef8112aSAlberto Garcia } 1019ef8112aSAlberto Garcia 1029ef8112aSAlberto Garcia static void test_job_ids(void) 1039ef8112aSAlberto Garcia { 1049ef8112aSAlberto Garcia BlockBackend *blk[3]; 1059ef8112aSAlberto Garcia BlockJob *job[3]; 1069ef8112aSAlberto Garcia 1079ef8112aSAlberto Garcia blk[0] = create_blk(NULL); 1089ef8112aSAlberto Garcia blk[1] = create_blk("drive1"); 1099ef8112aSAlberto Garcia blk[2] = create_blk("drive2"); 1109ef8112aSAlberto Garcia 1119ef8112aSAlberto Garcia /* No job ID provided and the block backend has no name */ 1129ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], NULL, false); 1139ef8112aSAlberto Garcia 1149ef8112aSAlberto Garcia /* These are all invalid job IDs */ 1159ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "0id", false); 1169ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "", false); 1179ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], " ", false); 1189ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "123", false); 1199ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "_id", false); 1209ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "-id", false); 1219ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], ".id", false); 1229ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "#id", false); 1239ef8112aSAlberto Garcia 1249ef8112aSAlberto Garcia /* This one is valid */ 1259ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "id0", true); 1269ef8112aSAlberto Garcia 127b23c580cSVladimir Sementsov-Ogievskiy /* We can have two jobs in the same BDS */ 128b23c580cSVladimir Sementsov-Ogievskiy job[1] = do_test_id(blk[0], "id1", true); 129b23c580cSVladimir Sementsov-Ogievskiy job_early_fail(&job[1]->job); 1309ef8112aSAlberto Garcia 1319ef8112aSAlberto Garcia /* Duplicate job IDs are not allowed */ 1329ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], "id0", false); 1339ef8112aSAlberto Garcia 1349ef8112aSAlberto Garcia /* But once job[0] finishes we can reuse its ID */ 1354ad35181SKevin Wolf job_early_fail(&job[0]->job); 1369ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], "id0", true); 1379ef8112aSAlberto Garcia 1389ef8112aSAlberto Garcia /* No job ID specified, defaults to the backend name ('drive1') */ 1394ad35181SKevin Wolf job_early_fail(&job[1]->job); 1409ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], NULL, true); 1419ef8112aSAlberto Garcia 1429ef8112aSAlberto Garcia /* Duplicate job ID */ 1439ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], "drive1", false); 1449ef8112aSAlberto Garcia 1459ef8112aSAlberto Garcia /* The ID of job[2] would default to 'drive2' but it is already in use */ 1469ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "drive2", true); 1479ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], NULL, false); 1489ef8112aSAlberto Garcia 1499ef8112aSAlberto Garcia /* This one is valid */ 1509ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], "id_2", true); 1519ef8112aSAlberto Garcia 1524ad35181SKevin Wolf job_early_fail(&job[0]->job); 1534ad35181SKevin Wolf job_early_fail(&job[1]->job); 1544ad35181SKevin Wolf job_early_fail(&job[2]->job); 1559ef8112aSAlberto Garcia 1569ef8112aSAlberto Garcia destroy_blk(blk[0]); 1579ef8112aSAlberto Garcia destroy_blk(blk[1]); 1589ef8112aSAlberto Garcia destroy_blk(blk[2]); 1599ef8112aSAlberto Garcia } 1609ef8112aSAlberto Garcia 161fb367e03SJohn Snow typedef struct CancelJob { 162fb367e03SJohn Snow BlockJob common; 163fb367e03SJohn Snow BlockBackend *blk; 164fb367e03SJohn Snow bool should_converge; 165fb367e03SJohn Snow bool should_complete; 166fb367e03SJohn Snow } CancelJob; 167fb367e03SJohn Snow 1683453d972SKevin Wolf static void cancel_job_complete(Job *job, Error **errp) 169fb367e03SJohn Snow { 1703453d972SKevin Wolf CancelJob *s = container_of(job, CancelJob, common.job); 171fb367e03SJohn Snow s->should_complete = true; 172fb367e03SJohn Snow } 173fb367e03SJohn Snow 174f67432a2SJohn Snow static int coroutine_fn cancel_job_run(Job *job, Error **errp) 175fb367e03SJohn Snow { 176f67432a2SJohn Snow CancelJob *s = container_of(job, CancelJob, common.job); 177fb367e03SJohn Snow 178fb367e03SJohn Snow while (!s->should_complete) { 179daa7f2f9SKevin Wolf if (job_is_cancelled(&s->common.job)) { 180eb23654dSJohn Snow return 0; 181fb367e03SJohn Snow } 182fb367e03SJohn Snow 183df956ae2SKevin Wolf if (!job_is_ready(&s->common.job) && s->should_converge) { 1842e1795b5SKevin Wolf job_transition_to_ready(&s->common.job); 185fb367e03SJohn Snow } 186fb367e03SJohn Snow 1875d43e86eSKevin Wolf job_sleep_ns(&s->common.job, 100000); 188fb367e03SJohn Snow } 189fb367e03SJohn Snow 190f67432a2SJohn Snow return 0; 191fb367e03SJohn Snow } 192fb367e03SJohn Snow 193fb367e03SJohn Snow static const BlockJobDriver test_cancel_driver = { 19433e9e9bdSKevin Wolf .job_driver = { 195fb367e03SJohn Snow .instance_size = sizeof(CancelJob), 19680fa2c75SKevin Wolf .free = block_job_free, 197b15de828SKevin Wolf .user_resume = block_job_user_resume, 198f67432a2SJohn Snow .run = cancel_job_run, 199fb367e03SJohn Snow .complete = cancel_job_complete, 2003453d972SKevin Wolf }, 201fb367e03SJohn Snow }; 202fb367e03SJohn Snow 2030cc4643bSJohn Snow static CancelJob *create_common(Job **pjob) 204fb367e03SJohn Snow { 205fb367e03SJohn Snow BlockBackend *blk; 2060cc4643bSJohn Snow Job *job; 2070cc4643bSJohn Snow BlockJob *bjob; 208fb367e03SJohn Snow CancelJob *s; 209fb367e03SJohn Snow 210fb367e03SJohn Snow blk = create_blk(NULL); 2110cc4643bSJohn Snow bjob = mk_job(blk, "Steve", &test_cancel_driver, true, 212bb02b65cSKevin Wolf JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); 2130cc4643bSJohn Snow job = &bjob->job; 214*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 215*191e7af3SEmanuele Giuseppe Esposito job_ref_locked(job); 2160cc4643bSJohn Snow assert(job->status == JOB_STATUS_CREATED); 217*191e7af3SEmanuele Giuseppe Esposito } 218*191e7af3SEmanuele Giuseppe Esposito 2190cc4643bSJohn Snow s = container_of(bjob, CancelJob, common); 220fb367e03SJohn Snow s->blk = blk; 221fb367e03SJohn Snow 222fb367e03SJohn Snow *pjob = job; 223fb367e03SJohn Snow return s; 224fb367e03SJohn Snow } 225fb367e03SJohn Snow 226fb367e03SJohn Snow static void cancel_common(CancelJob *s) 227fb367e03SJohn Snow { 228fb367e03SJohn Snow BlockJob *job = &s->common; 229fb367e03SJohn Snow BlockBackend *blk = s->blk; 230a50c2ab8SKevin Wolf JobStatus sts = job->job.status; 23130c070a5SKevin Wolf AioContext *ctx; 23230c070a5SKevin Wolf 23330c070a5SKevin Wolf ctx = job->job.aio_context; 23430c070a5SKevin Wolf aio_context_acquire(ctx); 235fb367e03SJohn Snow 2364cfb3f05SHanna Reitz job_cancel_sync(&job->job, true); 237*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 238a50c2ab8SKevin Wolf if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { 2395f9a6a08SKevin Wolf Job *dummy = &job->job; 240*191e7af3SEmanuele Giuseppe Esposito job_dismiss_locked(&dummy, &error_abort); 241fb367e03SJohn Snow } 242a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_NULL); 243*191e7af3SEmanuele Giuseppe Esposito job_unref_locked(&job->job); 244*191e7af3SEmanuele Giuseppe Esposito } 245fb367e03SJohn Snow destroy_blk(blk); 24630c070a5SKevin Wolf 24730c070a5SKevin Wolf aio_context_release(ctx); 248fb367e03SJohn Snow } 249fb367e03SJohn Snow 250fb367e03SJohn Snow static void test_cancel_created(void) 251fb367e03SJohn Snow { 2520cc4643bSJohn Snow Job *job; 253fb367e03SJohn Snow CancelJob *s; 254fb367e03SJohn Snow 255fb367e03SJohn Snow s = create_common(&job); 256fb367e03SJohn Snow cancel_common(s); 257fb367e03SJohn Snow } 258fb367e03SJohn Snow 259*191e7af3SEmanuele Giuseppe Esposito static void assert_job_status_is(Job *job, int status) 260*191e7af3SEmanuele Giuseppe Esposito { 261*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 262*191e7af3SEmanuele Giuseppe Esposito assert(job->status == status); 263*191e7af3SEmanuele Giuseppe Esposito } 264*191e7af3SEmanuele Giuseppe Esposito } 265*191e7af3SEmanuele Giuseppe Esposito 266fb367e03SJohn Snow static void test_cancel_running(void) 267fb367e03SJohn Snow { 2680cc4643bSJohn Snow Job *job; 269fb367e03SJohn Snow CancelJob *s; 270fb367e03SJohn Snow 271fb367e03SJohn Snow s = create_common(&job); 272fb367e03SJohn Snow 2730cc4643bSJohn Snow job_start(job); 274*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_RUNNING); 275fb367e03SJohn Snow 276fb367e03SJohn Snow cancel_common(s); 277fb367e03SJohn Snow } 278fb367e03SJohn Snow 279fb367e03SJohn Snow static void test_cancel_paused(void) 280fb367e03SJohn Snow { 2810cc4643bSJohn Snow Job *job; 282fb367e03SJohn Snow CancelJob *s; 283fb367e03SJohn Snow 284fb367e03SJohn Snow s = create_common(&job); 285fb367e03SJohn Snow 2860cc4643bSJohn Snow job_start(job); 287*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 2880cc4643bSJohn Snow assert(job->status == JOB_STATUS_RUNNING); 289*191e7af3SEmanuele Giuseppe Esposito job_user_pause_locked(job, &error_abort); 290*191e7af3SEmanuele Giuseppe Esposito } 2910cc4643bSJohn Snow job_enter(job); 292*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_PAUSED); 293fb367e03SJohn Snow 294fb367e03SJohn Snow cancel_common(s); 295fb367e03SJohn Snow } 296fb367e03SJohn Snow 297fb367e03SJohn Snow static void test_cancel_ready(void) 298fb367e03SJohn Snow { 2990cc4643bSJohn Snow Job *job; 300fb367e03SJohn Snow CancelJob *s; 301fb367e03SJohn Snow 302fb367e03SJohn Snow s = create_common(&job); 303fb367e03SJohn Snow 3040cc4643bSJohn Snow job_start(job); 305*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_RUNNING); 306fb367e03SJohn Snow 307fb367e03SJohn Snow s->should_converge = true; 3080cc4643bSJohn Snow job_enter(job); 309*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_READY); 310fb367e03SJohn Snow 311fb367e03SJohn Snow cancel_common(s); 312fb367e03SJohn Snow } 313fb367e03SJohn Snow 314fb367e03SJohn Snow static void test_cancel_standby(void) 315fb367e03SJohn Snow { 3160cc4643bSJohn Snow Job *job; 317fb367e03SJohn Snow CancelJob *s; 318fb367e03SJohn Snow 319fb367e03SJohn Snow s = create_common(&job); 320fb367e03SJohn Snow 3210cc4643bSJohn Snow job_start(job); 322*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_RUNNING); 323fb367e03SJohn Snow 324fb367e03SJohn Snow s->should_converge = true; 3250cc4643bSJohn Snow job_enter(job); 326*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 3270cc4643bSJohn Snow assert(job->status == JOB_STATUS_READY); 328*191e7af3SEmanuele Giuseppe Esposito job_user_pause_locked(job, &error_abort); 329*191e7af3SEmanuele Giuseppe Esposito } 3300cc4643bSJohn Snow job_enter(job); 331*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_STANDBY); 332fb367e03SJohn Snow 333fb367e03SJohn Snow cancel_common(s); 334fb367e03SJohn Snow } 335fb367e03SJohn Snow 336fb367e03SJohn Snow static void test_cancel_pending(void) 337fb367e03SJohn Snow { 3380cc4643bSJohn Snow Job *job; 339fb367e03SJohn Snow CancelJob *s; 340fb367e03SJohn Snow 341fb367e03SJohn Snow s = create_common(&job); 342fb367e03SJohn Snow 3430cc4643bSJohn Snow job_start(job); 344*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_RUNNING); 345fb367e03SJohn Snow 346fb367e03SJohn Snow s->should_converge = true; 3470cc4643bSJohn Snow job_enter(job); 348*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 3490cc4643bSJohn Snow assert(job->status == JOB_STATUS_READY); 350*191e7af3SEmanuele Giuseppe Esposito job_complete_locked(job, &error_abort); 351*191e7af3SEmanuele Giuseppe Esposito } 3520cc4643bSJohn Snow job_enter(job); 353977d26fdSJohn Snow while (!job->deferred_to_main_loop) { 354fb367e03SJohn Snow aio_poll(qemu_get_aio_context(), true); 355fb367e03SJohn Snow } 356*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_READY); 357977d26fdSJohn Snow aio_poll(qemu_get_aio_context(), true); 358*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_PENDING); 359fb367e03SJohn Snow 360fb367e03SJohn Snow cancel_common(s); 361fb367e03SJohn Snow } 362fb367e03SJohn Snow 363fb367e03SJohn Snow static void test_cancel_concluded(void) 364fb367e03SJohn Snow { 3650cc4643bSJohn Snow Job *job; 366fb367e03SJohn Snow CancelJob *s; 367fb367e03SJohn Snow 368fb367e03SJohn Snow s = create_common(&job); 369fb367e03SJohn Snow 3700cc4643bSJohn Snow job_start(job); 371*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_RUNNING); 372fb367e03SJohn Snow 373fb367e03SJohn Snow s->should_converge = true; 3740cc4643bSJohn Snow job_enter(job); 375*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 3760cc4643bSJohn Snow assert(job->status == JOB_STATUS_READY); 377*191e7af3SEmanuele Giuseppe Esposito job_complete_locked(job, &error_abort); 378*191e7af3SEmanuele Giuseppe Esposito } 3790cc4643bSJohn Snow job_enter(job); 380977d26fdSJohn Snow while (!job->deferred_to_main_loop) { 381fb367e03SJohn Snow aio_poll(qemu_get_aio_context(), true); 382fb367e03SJohn Snow } 383*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_READY); 384977d26fdSJohn Snow aio_poll(qemu_get_aio_context(), true); 385*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_PENDING); 386fb367e03SJohn Snow 387b660a84bSStefan Reiter aio_context_acquire(job->aio_context); 388*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 389*191e7af3SEmanuele Giuseppe Esposito job_finalize_locked(job, &error_abort); 390*191e7af3SEmanuele Giuseppe Esposito } 391b660a84bSStefan Reiter aio_context_release(job->aio_context); 392*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_CONCLUDED); 393fb367e03SJohn Snow 394fb367e03SJohn Snow cancel_common(s); 395fb367e03SJohn Snow } 396fb367e03SJohn Snow 397c2c731a4SMax Reitz /* (See test_yielding_driver for the job description) */ 398c2c731a4SMax Reitz typedef struct YieldingJob { 399c2c731a4SMax Reitz BlockJob common; 400c2c731a4SMax Reitz bool should_complete; 401c2c731a4SMax Reitz } YieldingJob; 402c2c731a4SMax Reitz 403c2c731a4SMax Reitz static void yielding_job_complete(Job *job, Error **errp) 404c2c731a4SMax Reitz { 405c2c731a4SMax Reitz YieldingJob *s = container_of(job, YieldingJob, common.job); 406c2c731a4SMax Reitz s->should_complete = true; 407c2c731a4SMax Reitz job_enter(job); 408c2c731a4SMax Reitz } 409c2c731a4SMax Reitz 410c2c731a4SMax Reitz static int coroutine_fn yielding_job_run(Job *job, Error **errp) 411c2c731a4SMax Reitz { 412c2c731a4SMax Reitz YieldingJob *s = container_of(job, YieldingJob, common.job); 413c2c731a4SMax Reitz 414c2c731a4SMax Reitz job_transition_to_ready(job); 415c2c731a4SMax Reitz 416c2c731a4SMax Reitz while (!s->should_complete) { 417c2c731a4SMax Reitz job_yield(job); 418c2c731a4SMax Reitz } 419c2c731a4SMax Reitz 420c2c731a4SMax Reitz return 0; 421c2c731a4SMax Reitz } 422c2c731a4SMax Reitz 423c2c731a4SMax Reitz /* 424c2c731a4SMax Reitz * This job transitions immediately to the READY state, and then 425c2c731a4SMax Reitz * yields until it is to complete. 426c2c731a4SMax Reitz */ 427c2c731a4SMax Reitz static const BlockJobDriver test_yielding_driver = { 428c2c731a4SMax Reitz .job_driver = { 429c2c731a4SMax Reitz .instance_size = sizeof(YieldingJob), 430c2c731a4SMax Reitz .free = block_job_free, 431c2c731a4SMax Reitz .user_resume = block_job_user_resume, 432c2c731a4SMax Reitz .run = yielding_job_run, 433c2c731a4SMax Reitz .complete = yielding_job_complete, 434c2c731a4SMax Reitz }, 435c2c731a4SMax Reitz }; 436c2c731a4SMax Reitz 437c2c731a4SMax Reitz /* 438c2c731a4SMax Reitz * Test that job_complete() works even on jobs that are in a paused 439c2c731a4SMax Reitz * state (i.e., STANDBY). 440c2c731a4SMax Reitz * 441c2c731a4SMax Reitz * To do this, run YieldingJob in an IO thread, get it into the READY 442c2c731a4SMax Reitz * state, then have a drained section. Before ending the section, 443c2c731a4SMax Reitz * acquire the context so the job will not be entered and will thus 444c2c731a4SMax Reitz * remain on STANDBY. 445c2c731a4SMax Reitz * 446c2c731a4SMax Reitz * job_complete() should still work without error. 447c2c731a4SMax Reitz * 448c2c731a4SMax Reitz * Note that on the QMP interface, it is impossible to lock an IO 449c2c731a4SMax Reitz * thread before a drained section ends. In practice, the 450c2c731a4SMax Reitz * bdrv_drain_all_end() and the aio_context_acquire() will be 451c2c731a4SMax Reitz * reversed. However, that makes for worse reproducibility here: 452c2c731a4SMax Reitz * Sometimes, the job would no longer be in STANDBY then but already 453c2c731a4SMax Reitz * be started. We cannot prevent that, because the IO thread runs 454c2c731a4SMax Reitz * concurrently. We can only prevent it by taking the lock before 455c2c731a4SMax Reitz * ending the drained section, so we do that. 456c2c731a4SMax Reitz * 457c2c731a4SMax Reitz * (You can reverse the order of operations and most of the time the 458c2c731a4SMax Reitz * test will pass, but sometimes the assert(status == STANDBY) will 459c2c731a4SMax Reitz * fail.) 460c2c731a4SMax Reitz */ 461c2c731a4SMax Reitz static void test_complete_in_standby(void) 462c2c731a4SMax Reitz { 463c2c731a4SMax Reitz BlockBackend *blk; 464c2c731a4SMax Reitz IOThread *iothread; 465c2c731a4SMax Reitz AioContext *ctx; 466c2c731a4SMax Reitz Job *job; 467c2c731a4SMax Reitz BlockJob *bjob; 468c2c731a4SMax Reitz 469c2c731a4SMax Reitz /* Create a test drive, move it to an IO thread */ 470c2c731a4SMax Reitz blk = create_blk(NULL); 471c2c731a4SMax Reitz iothread = iothread_new(); 472c2c731a4SMax Reitz 473c2c731a4SMax Reitz ctx = iothread_get_aio_context(iothread); 474c2c731a4SMax Reitz blk_set_aio_context(blk, ctx, &error_abort); 475c2c731a4SMax Reitz 476c2c731a4SMax Reitz /* Create our test job */ 477c2c731a4SMax Reitz bjob = mk_job(blk, "job", &test_yielding_driver, true, 478c2c731a4SMax Reitz JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); 479c2c731a4SMax Reitz job = &bjob->job; 480*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_CREATED); 481c2c731a4SMax Reitz 482c2c731a4SMax Reitz /* Wait for the job to become READY */ 483c2c731a4SMax Reitz job_start(job); 484c2c731a4SMax Reitz aio_context_acquire(ctx); 485*191e7af3SEmanuele Giuseppe Esposito /* 486*191e7af3SEmanuele Giuseppe Esposito * Here we are waiting for the status to change, so don't bother 487*191e7af3SEmanuele Giuseppe Esposito * protecting the read every time. 488*191e7af3SEmanuele Giuseppe Esposito */ 489c2c731a4SMax Reitz AIO_WAIT_WHILE(ctx, job->status != JOB_STATUS_READY); 490c2c731a4SMax Reitz aio_context_release(ctx); 491c2c731a4SMax Reitz 492c2c731a4SMax Reitz /* Begin the drained section, pausing the job */ 493c2c731a4SMax Reitz bdrv_drain_all_begin(); 494*191e7af3SEmanuele Giuseppe Esposito assert_job_status_is(job, JOB_STATUS_STANDBY); 495*191e7af3SEmanuele Giuseppe Esposito 496c2c731a4SMax Reitz /* Lock the IO thread to prevent the job from being run */ 497c2c731a4SMax Reitz aio_context_acquire(ctx); 498c2c731a4SMax Reitz /* This will schedule the job to resume it */ 499c2c731a4SMax Reitz bdrv_drain_all_end(); 500c2c731a4SMax Reitz 501*191e7af3SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 502c2c731a4SMax Reitz /* But the job cannot run, so it will remain on standby */ 503c2c731a4SMax Reitz assert(job->status == JOB_STATUS_STANDBY); 504c2c731a4SMax Reitz 505c2c731a4SMax Reitz /* Even though the job is on standby, this should work */ 506*191e7af3SEmanuele Giuseppe Esposito job_complete_locked(job, &error_abort); 507c2c731a4SMax Reitz 508c2c731a4SMax Reitz /* The test is done now, clean up. */ 509*191e7af3SEmanuele Giuseppe Esposito job_finish_sync_locked(job, NULL, &error_abort); 510c2c731a4SMax Reitz assert(job->status == JOB_STATUS_PENDING); 511c2c731a4SMax Reitz 512*191e7af3SEmanuele Giuseppe Esposito job_finalize_locked(job, &error_abort); 513c2c731a4SMax Reitz assert(job->status == JOB_STATUS_CONCLUDED); 514c2c731a4SMax Reitz 515*191e7af3SEmanuele Giuseppe Esposito job_dismiss_locked(&job, &error_abort); 516*191e7af3SEmanuele Giuseppe Esposito } 517c2c731a4SMax Reitz 518c2c731a4SMax Reitz destroy_blk(blk); 519c2c731a4SMax Reitz aio_context_release(ctx); 520c2c731a4SMax Reitz iothread_join(iothread); 521c2c731a4SMax Reitz } 522c2c731a4SMax Reitz 5239ef8112aSAlberto Garcia int main(int argc, char **argv) 5249ef8112aSAlberto Garcia { 5259ef8112aSAlberto Garcia qemu_init_main_loop(&error_abort); 526d185cf0eSKevin Wolf bdrv_init(); 5279ef8112aSAlberto Garcia 5289ef8112aSAlberto Garcia g_test_init(&argc, &argv, NULL); 5299ef8112aSAlberto Garcia g_test_add_func("/blockjob/ids", test_job_ids); 530fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/created", test_cancel_created); 531fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/running", test_cancel_running); 532fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/paused", test_cancel_paused); 533fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/ready", test_cancel_ready); 534fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/standby", test_cancel_standby); 535fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/pending", test_cancel_pending); 536fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded); 537c2c731a4SMax Reitz g_test_add_func("/blockjob/complete_in_standby", test_complete_in_standby); 5389ef8112aSAlberto Garcia return g_test_run(); 5399ef8112aSAlberto Garcia } 540