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" 199ef8112aSAlberto Garcia 209ef8112aSAlberto Garcia static const BlockJobDriver test_block_job_driver = { 2133e9e9bdSKevin Wolf .job_driver = { 229ef8112aSAlberto Garcia .instance_size = sizeof(BlockJob), 2380fa2c75SKevin Wolf .free = block_job_free, 24b15de828SKevin Wolf .user_resume = block_job_user_resume, 2533e9e9bdSKevin Wolf }, 269ef8112aSAlberto Garcia }; 279ef8112aSAlberto Garcia 289ef8112aSAlberto Garcia static void block_job_cb(void *opaque, int ret) 299ef8112aSAlberto Garcia { 309ef8112aSAlberto Garcia } 319ef8112aSAlberto Garcia 32fb367e03SJohn Snow static BlockJob *mk_job(BlockBackend *blk, const char *id, 33fb367e03SJohn Snow const BlockJobDriver *drv, bool should_succeed, 34fb367e03SJohn Snow int flags) 359ef8112aSAlberto Garcia { 369ef8112aSAlberto Garcia BlockJob *job; 378ca63ba8SMarkus Armbruster Error *err = NULL; 389ef8112aSAlberto Garcia 39fb367e03SJohn Snow job = block_job_create(id, drv, NULL, blk_bs(blk), 40fb367e03SJohn Snow 0, BLK_PERM_ALL, 0, flags, block_job_cb, 418ca63ba8SMarkus Armbruster NULL, &err); 429ef8112aSAlberto Garcia if (should_succeed) { 438ca63ba8SMarkus Armbruster g_assert_null(err); 449ef8112aSAlberto Garcia g_assert_nonnull(job); 459ef8112aSAlberto Garcia if (id) { 4633e9e9bdSKevin Wolf g_assert_cmpstr(job->job.id, ==, id); 479ef8112aSAlberto Garcia } else { 4833e9e9bdSKevin Wolf g_assert_cmpstr(job->job.id, ==, blk_name(blk)); 499ef8112aSAlberto Garcia } 509ef8112aSAlberto Garcia } else { 51*0cf9e2b4SMarkus Armbruster error_free_or_abort(&err); 529ef8112aSAlberto Garcia g_assert_null(job); 539ef8112aSAlberto Garcia } 549ef8112aSAlberto Garcia 559ef8112aSAlberto Garcia return job; 569ef8112aSAlberto Garcia } 579ef8112aSAlberto Garcia 58fb367e03SJohn Snow static BlockJob *do_test_id(BlockBackend *blk, const char *id, 59fb367e03SJohn Snow bool should_succeed) 60fb367e03SJohn Snow { 61fb367e03SJohn Snow return mk_job(blk, id, &test_block_job_driver, 62bb02b65cSKevin Wolf should_succeed, JOB_DEFAULT); 63fb367e03SJohn Snow } 64fb367e03SJohn Snow 659ef8112aSAlberto Garcia /* This creates a BlockBackend (optionally with a name) with a 669ef8112aSAlberto Garcia * BlockDriverState inserted. */ 679ef8112aSAlberto Garcia static BlockBackend *create_blk(const char *name) 689ef8112aSAlberto Garcia { 692807c0cdSKevin Wolf /* No I/O is performed on this device */ 70d861ab3aSKevin Wolf BlockBackend *blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); 71d185cf0eSKevin Wolf BlockDriverState *bs; 72d185cf0eSKevin Wolf 73ca1ef1e6SAndrey Shinkevich QDict *opt = qdict_new(); 74ca1ef1e6SAndrey Shinkevich qdict_put_str(opt, "file.read-zeroes", "on"); 75ca1ef1e6SAndrey Shinkevich bs = bdrv_open("null-co://", NULL, opt, 0, &error_abort); 76d185cf0eSKevin Wolf g_assert_nonnull(bs); 779ef8112aSAlberto Garcia 78d7086422SKevin Wolf blk_insert_bs(blk, bs, &error_abort); 799ef8112aSAlberto Garcia bdrv_unref(bs); 809ef8112aSAlberto Garcia 819ef8112aSAlberto Garcia if (name) { 828ca63ba8SMarkus Armbruster Error *err = NULL; 838ca63ba8SMarkus Armbruster monitor_add_blk(blk, name, &err); 848ca63ba8SMarkus Armbruster g_assert_null(err); 859ef8112aSAlberto Garcia } 869ef8112aSAlberto Garcia 879ef8112aSAlberto Garcia return blk; 889ef8112aSAlberto Garcia } 899ef8112aSAlberto Garcia 909ef8112aSAlberto Garcia /* This destroys the backend */ 919ef8112aSAlberto Garcia static void destroy_blk(BlockBackend *blk) 929ef8112aSAlberto Garcia { 939ef8112aSAlberto Garcia if (blk_name(blk)[0] != '\0') { 949ef8112aSAlberto Garcia monitor_remove_blk(blk); 959ef8112aSAlberto Garcia } 969ef8112aSAlberto Garcia 979ef8112aSAlberto Garcia blk_remove_bs(blk); 989ef8112aSAlberto Garcia blk_unref(blk); 999ef8112aSAlberto Garcia } 1009ef8112aSAlberto Garcia 1019ef8112aSAlberto Garcia static void test_job_ids(void) 1029ef8112aSAlberto Garcia { 1039ef8112aSAlberto Garcia BlockBackend *blk[3]; 1049ef8112aSAlberto Garcia BlockJob *job[3]; 1059ef8112aSAlberto Garcia 1069ef8112aSAlberto Garcia blk[0] = create_blk(NULL); 1079ef8112aSAlberto Garcia blk[1] = create_blk("drive1"); 1089ef8112aSAlberto Garcia blk[2] = create_blk("drive2"); 1099ef8112aSAlberto Garcia 1109ef8112aSAlberto Garcia /* No job ID provided and the block backend has no name */ 1119ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], NULL, false); 1129ef8112aSAlberto Garcia 1139ef8112aSAlberto Garcia /* These are all invalid job IDs */ 1149ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "0id", false); 1159ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "", false); 1169ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], " ", false); 1179ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "123", false); 1189ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "_id", 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 1239ef8112aSAlberto Garcia /* This one is valid */ 1249ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "id0", true); 1259ef8112aSAlberto Garcia 126b23c580cSVladimir Sementsov-Ogievskiy /* We can have two jobs in the same BDS */ 127b23c580cSVladimir Sementsov-Ogievskiy job[1] = do_test_id(blk[0], "id1", true); 128b23c580cSVladimir Sementsov-Ogievskiy job_early_fail(&job[1]->job); 1299ef8112aSAlberto Garcia 1309ef8112aSAlberto Garcia /* Duplicate job IDs are not allowed */ 1319ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], "id0", false); 1329ef8112aSAlberto Garcia 1339ef8112aSAlberto Garcia /* But once job[0] finishes we can reuse its ID */ 1344ad35181SKevin Wolf job_early_fail(&job[0]->job); 1359ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], "id0", true); 1369ef8112aSAlberto Garcia 1379ef8112aSAlberto Garcia /* No job ID specified, defaults to the backend name ('drive1') */ 1384ad35181SKevin Wolf job_early_fail(&job[1]->job); 1399ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], NULL, true); 1409ef8112aSAlberto Garcia 1419ef8112aSAlberto Garcia /* Duplicate job ID */ 1429ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], "drive1", false); 1439ef8112aSAlberto Garcia 1449ef8112aSAlberto Garcia /* The ID of job[2] would default to 'drive2' but it is already in use */ 1459ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "drive2", true); 1469ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], NULL, false); 1479ef8112aSAlberto Garcia 1489ef8112aSAlberto Garcia /* This one is valid */ 1499ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], "id_2", true); 1509ef8112aSAlberto Garcia 1514ad35181SKevin Wolf job_early_fail(&job[0]->job); 1524ad35181SKevin Wolf job_early_fail(&job[1]->job); 1534ad35181SKevin Wolf job_early_fail(&job[2]->job); 1549ef8112aSAlberto Garcia 1559ef8112aSAlberto Garcia destroy_blk(blk[0]); 1569ef8112aSAlberto Garcia destroy_blk(blk[1]); 1579ef8112aSAlberto Garcia destroy_blk(blk[2]); 1589ef8112aSAlberto Garcia } 1599ef8112aSAlberto Garcia 160fb367e03SJohn Snow typedef struct CancelJob { 161fb367e03SJohn Snow BlockJob common; 162fb367e03SJohn Snow BlockBackend *blk; 163fb367e03SJohn Snow bool should_converge; 164fb367e03SJohn Snow bool should_complete; 165fb367e03SJohn Snow } CancelJob; 166fb367e03SJohn Snow 1673453d972SKevin Wolf static void cancel_job_complete(Job *job, Error **errp) 168fb367e03SJohn Snow { 1693453d972SKevin Wolf CancelJob *s = container_of(job, CancelJob, common.job); 170fb367e03SJohn Snow s->should_complete = true; 171fb367e03SJohn Snow } 172fb367e03SJohn Snow 173f67432a2SJohn Snow static int coroutine_fn cancel_job_run(Job *job, Error **errp) 174fb367e03SJohn Snow { 175f67432a2SJohn Snow CancelJob *s = container_of(job, CancelJob, common.job); 176fb367e03SJohn Snow 177fb367e03SJohn Snow while (!s->should_complete) { 178daa7f2f9SKevin Wolf if (job_is_cancelled(&s->common.job)) { 179eb23654dSJohn Snow return 0; 180fb367e03SJohn Snow } 181fb367e03SJohn Snow 182df956ae2SKevin Wolf if (!job_is_ready(&s->common.job) && s->should_converge) { 1832e1795b5SKevin Wolf job_transition_to_ready(&s->common.job); 184fb367e03SJohn Snow } 185fb367e03SJohn Snow 1865d43e86eSKevin Wolf job_sleep_ns(&s->common.job, 100000); 187fb367e03SJohn Snow } 188fb367e03SJohn Snow 189f67432a2SJohn Snow return 0; 190fb367e03SJohn Snow } 191fb367e03SJohn Snow 192fb367e03SJohn Snow static const BlockJobDriver test_cancel_driver = { 19333e9e9bdSKevin Wolf .job_driver = { 194fb367e03SJohn Snow .instance_size = sizeof(CancelJob), 19580fa2c75SKevin Wolf .free = block_job_free, 196b15de828SKevin Wolf .user_resume = block_job_user_resume, 197f67432a2SJohn Snow .run = cancel_job_run, 198fb367e03SJohn Snow .complete = cancel_job_complete, 1993453d972SKevin Wolf }, 200fb367e03SJohn Snow }; 201fb367e03SJohn Snow 2020cc4643bSJohn Snow static CancelJob *create_common(Job **pjob) 203fb367e03SJohn Snow { 204fb367e03SJohn Snow BlockBackend *blk; 2050cc4643bSJohn Snow Job *job; 2060cc4643bSJohn Snow BlockJob *bjob; 207fb367e03SJohn Snow CancelJob *s; 208fb367e03SJohn Snow 209fb367e03SJohn Snow blk = create_blk(NULL); 2100cc4643bSJohn Snow bjob = mk_job(blk, "Steve", &test_cancel_driver, true, 211bb02b65cSKevin Wolf JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); 2120cc4643bSJohn Snow job = &bjob->job; 2130cc4643bSJohn Snow job_ref(job); 2140cc4643bSJohn Snow assert(job->status == JOB_STATUS_CREATED); 2150cc4643bSJohn Snow s = container_of(bjob, CancelJob, common); 216fb367e03SJohn Snow s->blk = blk; 217fb367e03SJohn Snow 218fb367e03SJohn Snow *pjob = job; 219fb367e03SJohn Snow return s; 220fb367e03SJohn Snow } 221fb367e03SJohn Snow 222fb367e03SJohn Snow static void cancel_common(CancelJob *s) 223fb367e03SJohn Snow { 224fb367e03SJohn Snow BlockJob *job = &s->common; 225fb367e03SJohn Snow BlockBackend *blk = s->blk; 226a50c2ab8SKevin Wolf JobStatus sts = job->job.status; 22730c070a5SKevin Wolf AioContext *ctx; 22830c070a5SKevin Wolf 22930c070a5SKevin Wolf ctx = job->job.aio_context; 23030c070a5SKevin Wolf aio_context_acquire(ctx); 231fb367e03SJohn Snow 2323d70ff53SKevin Wolf job_cancel_sync(&job->job); 233a50c2ab8SKevin Wolf if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { 2345f9a6a08SKevin Wolf Job *dummy = &job->job; 2355f9a6a08SKevin Wolf job_dismiss(&dummy, &error_abort); 236fb367e03SJohn Snow } 237a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_NULL); 23880fa2c75SKevin Wolf job_unref(&job->job); 239fb367e03SJohn Snow destroy_blk(blk); 24030c070a5SKevin Wolf 24130c070a5SKevin Wolf aio_context_release(ctx); 242fb367e03SJohn Snow } 243fb367e03SJohn Snow 244fb367e03SJohn Snow static void test_cancel_created(void) 245fb367e03SJohn Snow { 2460cc4643bSJohn Snow Job *job; 247fb367e03SJohn Snow CancelJob *s; 248fb367e03SJohn Snow 249fb367e03SJohn Snow s = create_common(&job); 250fb367e03SJohn Snow cancel_common(s); 251fb367e03SJohn Snow } 252fb367e03SJohn Snow 253fb367e03SJohn Snow static void test_cancel_running(void) 254fb367e03SJohn Snow { 2550cc4643bSJohn Snow Job *job; 256fb367e03SJohn Snow CancelJob *s; 257fb367e03SJohn Snow 258fb367e03SJohn Snow s = create_common(&job); 259fb367e03SJohn Snow 2600cc4643bSJohn Snow job_start(job); 2610cc4643bSJohn Snow assert(job->status == JOB_STATUS_RUNNING); 262fb367e03SJohn Snow 263fb367e03SJohn Snow cancel_common(s); 264fb367e03SJohn Snow } 265fb367e03SJohn Snow 266fb367e03SJohn Snow static void test_cancel_paused(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); 2740cc4643bSJohn Snow assert(job->status == JOB_STATUS_RUNNING); 275fb367e03SJohn Snow 2760cc4643bSJohn Snow job_user_pause(job, &error_abort); 2770cc4643bSJohn Snow job_enter(job); 2780cc4643bSJohn Snow assert(job->status == JOB_STATUS_PAUSED); 279fb367e03SJohn Snow 280fb367e03SJohn Snow cancel_common(s); 281fb367e03SJohn Snow } 282fb367e03SJohn Snow 283fb367e03SJohn Snow static void test_cancel_ready(void) 284fb367e03SJohn Snow { 2850cc4643bSJohn Snow Job *job; 286fb367e03SJohn Snow CancelJob *s; 287fb367e03SJohn Snow 288fb367e03SJohn Snow s = create_common(&job); 289fb367e03SJohn Snow 2900cc4643bSJohn Snow job_start(job); 2910cc4643bSJohn Snow assert(job->status == JOB_STATUS_RUNNING); 292fb367e03SJohn Snow 293fb367e03SJohn Snow s->should_converge = true; 2940cc4643bSJohn Snow job_enter(job); 2950cc4643bSJohn Snow assert(job->status == JOB_STATUS_READY); 296fb367e03SJohn Snow 297fb367e03SJohn Snow cancel_common(s); 298fb367e03SJohn Snow } 299fb367e03SJohn Snow 300fb367e03SJohn Snow static void test_cancel_standby(void) 301fb367e03SJohn Snow { 3020cc4643bSJohn Snow Job *job; 303fb367e03SJohn Snow CancelJob *s; 304fb367e03SJohn Snow 305fb367e03SJohn Snow s = create_common(&job); 306fb367e03SJohn Snow 3070cc4643bSJohn Snow job_start(job); 3080cc4643bSJohn Snow assert(job->status == JOB_STATUS_RUNNING); 309fb367e03SJohn Snow 310fb367e03SJohn Snow s->should_converge = true; 3110cc4643bSJohn Snow job_enter(job); 3120cc4643bSJohn Snow assert(job->status == JOB_STATUS_READY); 313fb367e03SJohn Snow 3140cc4643bSJohn Snow job_user_pause(job, &error_abort); 3150cc4643bSJohn Snow job_enter(job); 3160cc4643bSJohn Snow assert(job->status == JOB_STATUS_STANDBY); 317fb367e03SJohn Snow 318fb367e03SJohn Snow cancel_common(s); 319fb367e03SJohn Snow } 320fb367e03SJohn Snow 321fb367e03SJohn Snow static void test_cancel_pending(void) 322fb367e03SJohn Snow { 3230cc4643bSJohn Snow Job *job; 324fb367e03SJohn Snow CancelJob *s; 325fb367e03SJohn Snow 326fb367e03SJohn Snow s = create_common(&job); 327fb367e03SJohn Snow 3280cc4643bSJohn Snow job_start(job); 3290cc4643bSJohn Snow assert(job->status == JOB_STATUS_RUNNING); 330fb367e03SJohn Snow 331fb367e03SJohn Snow s->should_converge = true; 3320cc4643bSJohn Snow job_enter(job); 3330cc4643bSJohn Snow assert(job->status == JOB_STATUS_READY); 334fb367e03SJohn Snow 3350cc4643bSJohn Snow job_complete(job, &error_abort); 3360cc4643bSJohn Snow job_enter(job); 337977d26fdSJohn Snow while (!job->deferred_to_main_loop) { 338fb367e03SJohn Snow aio_poll(qemu_get_aio_context(), true); 339fb367e03SJohn Snow } 340977d26fdSJohn Snow assert(job->status == JOB_STATUS_READY); 341977d26fdSJohn Snow aio_poll(qemu_get_aio_context(), true); 3420cc4643bSJohn Snow assert(job->status == JOB_STATUS_PENDING); 343fb367e03SJohn Snow 344fb367e03SJohn Snow cancel_common(s); 345fb367e03SJohn Snow } 346fb367e03SJohn Snow 347fb367e03SJohn Snow static void test_cancel_concluded(void) 348fb367e03SJohn Snow { 3490cc4643bSJohn Snow Job *job; 350fb367e03SJohn Snow CancelJob *s; 351fb367e03SJohn Snow 352fb367e03SJohn Snow s = create_common(&job); 353fb367e03SJohn Snow 3540cc4643bSJohn Snow job_start(job); 3550cc4643bSJohn Snow assert(job->status == JOB_STATUS_RUNNING); 356fb367e03SJohn Snow 357fb367e03SJohn Snow s->should_converge = true; 3580cc4643bSJohn Snow job_enter(job); 3590cc4643bSJohn Snow assert(job->status == JOB_STATUS_READY); 360fb367e03SJohn Snow 3610cc4643bSJohn Snow job_complete(job, &error_abort); 3620cc4643bSJohn Snow job_enter(job); 363977d26fdSJohn Snow while (!job->deferred_to_main_loop) { 364fb367e03SJohn Snow aio_poll(qemu_get_aio_context(), true); 365fb367e03SJohn Snow } 366977d26fdSJohn Snow assert(job->status == JOB_STATUS_READY); 367977d26fdSJohn Snow aio_poll(qemu_get_aio_context(), true); 3680cc4643bSJohn Snow assert(job->status == JOB_STATUS_PENDING); 369fb367e03SJohn Snow 3700cc4643bSJohn Snow job_finalize(job, &error_abort); 3710cc4643bSJohn Snow assert(job->status == JOB_STATUS_CONCLUDED); 372fb367e03SJohn Snow 373fb367e03SJohn Snow cancel_common(s); 374fb367e03SJohn Snow } 375fb367e03SJohn Snow 3769ef8112aSAlberto Garcia int main(int argc, char **argv) 3779ef8112aSAlberto Garcia { 3789ef8112aSAlberto Garcia qemu_init_main_loop(&error_abort); 379d185cf0eSKevin Wolf bdrv_init(); 3809ef8112aSAlberto Garcia 3819ef8112aSAlberto Garcia g_test_init(&argc, &argv, NULL); 3829ef8112aSAlberto Garcia g_test_add_func("/blockjob/ids", test_job_ids); 383fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/created", test_cancel_created); 384fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/running", test_cancel_running); 385fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/paused", test_cancel_paused); 386fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/ready", test_cancel_ready); 387fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/standby", test_cancel_standby); 388fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/pending", test_cancel_pending); 389fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded); 3909ef8112aSAlberto Garcia return g_test_run(); 3919ef8112aSAlberto Garcia } 392