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" 189ef8112aSAlberto Garcia 199ef8112aSAlberto Garcia static const BlockJobDriver test_block_job_driver = { 2033e9e9bdSKevin Wolf .job_driver = { 219ef8112aSAlberto Garcia .instance_size = sizeof(BlockJob), 2280fa2c75SKevin Wolf .free = block_job_free, 2333e9e9bdSKevin Wolf }, 249ef8112aSAlberto Garcia }; 259ef8112aSAlberto Garcia 269ef8112aSAlberto Garcia static void block_job_cb(void *opaque, int ret) 279ef8112aSAlberto Garcia { 289ef8112aSAlberto Garcia } 299ef8112aSAlberto Garcia 30fb367e03SJohn Snow static BlockJob *mk_job(BlockBackend *blk, const char *id, 31fb367e03SJohn Snow const BlockJobDriver *drv, bool should_succeed, 32fb367e03SJohn Snow int flags) 339ef8112aSAlberto Garcia { 349ef8112aSAlberto Garcia BlockJob *job; 359ef8112aSAlberto Garcia Error *errp = NULL; 369ef8112aSAlberto Garcia 37fb367e03SJohn Snow job = block_job_create(id, drv, NULL, blk_bs(blk), 38fb367e03SJohn Snow 0, BLK_PERM_ALL, 0, flags, block_job_cb, 39c6cc12bfSKevin Wolf NULL, &errp); 409ef8112aSAlberto Garcia if (should_succeed) { 419ef8112aSAlberto Garcia g_assert_null(errp); 429ef8112aSAlberto Garcia g_assert_nonnull(job); 439ef8112aSAlberto Garcia if (id) { 4433e9e9bdSKevin Wolf g_assert_cmpstr(job->job.id, ==, id); 459ef8112aSAlberto Garcia } else { 4633e9e9bdSKevin Wolf g_assert_cmpstr(job->job.id, ==, blk_name(blk)); 479ef8112aSAlberto Garcia } 489ef8112aSAlberto Garcia } else { 499ef8112aSAlberto Garcia g_assert_nonnull(errp); 509ef8112aSAlberto Garcia g_assert_null(job); 519ef8112aSAlberto Garcia error_free(errp); 529ef8112aSAlberto Garcia } 539ef8112aSAlberto Garcia 549ef8112aSAlberto Garcia return job; 559ef8112aSAlberto Garcia } 569ef8112aSAlberto Garcia 57fb367e03SJohn Snow static BlockJob *do_test_id(BlockBackend *blk, const char *id, 58fb367e03SJohn Snow bool should_succeed) 59fb367e03SJohn Snow { 60fb367e03SJohn Snow return mk_job(blk, id, &test_block_job_driver, 61fb367e03SJohn Snow should_succeed, BLOCK_JOB_DEFAULT); 62fb367e03SJohn Snow } 63fb367e03SJohn Snow 649ef8112aSAlberto Garcia /* This creates a BlockBackend (optionally with a name) with a 659ef8112aSAlberto Garcia * BlockDriverState inserted. */ 669ef8112aSAlberto Garcia static BlockBackend *create_blk(const char *name) 679ef8112aSAlberto Garcia { 682807c0cdSKevin Wolf /* No I/O is performed on this device */ 696d0eb64dSKevin Wolf BlockBackend *blk = blk_new(0, BLK_PERM_ALL); 70d185cf0eSKevin Wolf BlockDriverState *bs; 71d185cf0eSKevin Wolf 72d185cf0eSKevin Wolf bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort); 73d185cf0eSKevin Wolf g_assert_nonnull(bs); 749ef8112aSAlberto Garcia 75d7086422SKevin Wolf blk_insert_bs(blk, bs, &error_abort); 769ef8112aSAlberto Garcia bdrv_unref(bs); 779ef8112aSAlberto Garcia 789ef8112aSAlberto Garcia if (name) { 799ef8112aSAlberto Garcia Error *errp = NULL; 809ef8112aSAlberto Garcia monitor_add_blk(blk, name, &errp); 819ef8112aSAlberto Garcia g_assert_null(errp); 829ef8112aSAlberto Garcia } 839ef8112aSAlberto Garcia 849ef8112aSAlberto Garcia return blk; 859ef8112aSAlberto Garcia } 869ef8112aSAlberto Garcia 879ef8112aSAlberto Garcia /* This destroys the backend */ 889ef8112aSAlberto Garcia static void destroy_blk(BlockBackend *blk) 899ef8112aSAlberto Garcia { 909ef8112aSAlberto Garcia if (blk_name(blk)[0] != '\0') { 919ef8112aSAlberto Garcia monitor_remove_blk(blk); 929ef8112aSAlberto Garcia } 939ef8112aSAlberto Garcia 949ef8112aSAlberto Garcia blk_remove_bs(blk); 959ef8112aSAlberto Garcia blk_unref(blk); 969ef8112aSAlberto Garcia } 979ef8112aSAlberto Garcia 989ef8112aSAlberto Garcia static void test_job_ids(void) 999ef8112aSAlberto Garcia { 1009ef8112aSAlberto Garcia BlockBackend *blk[3]; 1019ef8112aSAlberto Garcia BlockJob *job[3]; 1029ef8112aSAlberto Garcia 1039ef8112aSAlberto Garcia blk[0] = create_blk(NULL); 1049ef8112aSAlberto Garcia blk[1] = create_blk("drive1"); 1059ef8112aSAlberto Garcia blk[2] = create_blk("drive2"); 1069ef8112aSAlberto Garcia 1079ef8112aSAlberto Garcia /* No job ID provided and the block backend has no name */ 1089ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], NULL, false); 1099ef8112aSAlberto Garcia 1109ef8112aSAlberto Garcia /* These are all invalid job IDs */ 1119ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "0id", false); 1129ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "", false); 1139ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], " ", false); 1149ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "123", false); 1159ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "_id", false); 1169ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "-id", false); 1179ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], ".id", false); 1189ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "#id", false); 1199ef8112aSAlberto Garcia 1209ef8112aSAlberto Garcia /* This one is valid */ 1219ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "id0", true); 1229ef8112aSAlberto Garcia 1239ef8112aSAlberto Garcia /* We cannot have two jobs in the same BDS */ 1249ef8112aSAlberto Garcia do_test_id(blk[0], "id1", false); 1259ef8112aSAlberto Garcia 1269ef8112aSAlberto Garcia /* Duplicate job IDs are not allowed */ 1279ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], "id0", false); 1289ef8112aSAlberto Garcia 1299ef8112aSAlberto Garcia /* But once job[0] finishes we can reuse its ID */ 13005b0d8e3SPaolo Bonzini block_job_early_fail(job[0]); 1319ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], "id0", true); 1329ef8112aSAlberto Garcia 1339ef8112aSAlberto Garcia /* No job ID specified, defaults to the backend name ('drive1') */ 13405b0d8e3SPaolo Bonzini block_job_early_fail(job[1]); 1359ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], NULL, true); 1369ef8112aSAlberto Garcia 1379ef8112aSAlberto Garcia /* Duplicate job ID */ 1389ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], "drive1", false); 1399ef8112aSAlberto Garcia 1409ef8112aSAlberto Garcia /* The ID of job[2] would default to 'drive2' but it is already in use */ 1419ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "drive2", true); 1429ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], NULL, false); 1439ef8112aSAlberto Garcia 1449ef8112aSAlberto Garcia /* This one is valid */ 1459ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], "id_2", true); 1469ef8112aSAlberto Garcia 14705b0d8e3SPaolo Bonzini block_job_early_fail(job[0]); 14805b0d8e3SPaolo Bonzini block_job_early_fail(job[1]); 14905b0d8e3SPaolo Bonzini block_job_early_fail(job[2]); 1509ef8112aSAlberto Garcia 1519ef8112aSAlberto Garcia destroy_blk(blk[0]); 1529ef8112aSAlberto Garcia destroy_blk(blk[1]); 1539ef8112aSAlberto Garcia destroy_blk(blk[2]); 1549ef8112aSAlberto Garcia } 1559ef8112aSAlberto Garcia 156fb367e03SJohn Snow typedef struct CancelJob { 157fb367e03SJohn Snow BlockJob common; 158fb367e03SJohn Snow BlockBackend *blk; 159fb367e03SJohn Snow bool should_converge; 160fb367e03SJohn Snow bool should_complete; 161fb367e03SJohn Snow bool completed; 162fb367e03SJohn Snow } CancelJob; 163fb367e03SJohn Snow 1641908a559SKevin Wolf static void cancel_job_completed(Job *job, void *opaque) 165fb367e03SJohn Snow { 1661908a559SKevin Wolf BlockJob *bjob = container_of(job, BlockJob, job); 167fb367e03SJohn Snow CancelJob *s = opaque; 168fb367e03SJohn Snow s->completed = true; 1691908a559SKevin Wolf block_job_completed(bjob, 0); 170fb367e03SJohn Snow } 171fb367e03SJohn Snow 172fb367e03SJohn Snow static void cancel_job_complete(BlockJob *job, Error **errp) 173fb367e03SJohn Snow { 174fb367e03SJohn Snow CancelJob *s = container_of(job, CancelJob, common); 175fb367e03SJohn Snow s->should_complete = true; 176fb367e03SJohn Snow } 177fb367e03SJohn Snow 178fb367e03SJohn Snow static void coroutine_fn cancel_job_start(void *opaque) 179fb367e03SJohn Snow { 180fb367e03SJohn Snow CancelJob *s = opaque; 181fb367e03SJohn Snow 182fb367e03SJohn Snow while (!s->should_complete) { 183daa7f2f9SKevin Wolf if (job_is_cancelled(&s->common.job)) { 184fb367e03SJohn Snow goto defer; 185fb367e03SJohn Snow } 186fb367e03SJohn Snow 187fb367e03SJohn Snow if (!s->common.ready && s->should_converge) { 188fb367e03SJohn Snow block_job_event_ready(&s->common); 189fb367e03SJohn Snow } 190fb367e03SJohn Snow 191fb367e03SJohn Snow block_job_sleep_ns(&s->common, 100000); 192fb367e03SJohn Snow } 193fb367e03SJohn Snow 194fb367e03SJohn Snow defer: 1951908a559SKevin Wolf job_defer_to_main_loop(&s->common.job, cancel_job_completed, s); 196fb367e03SJohn Snow } 197fb367e03SJohn Snow 198fb367e03SJohn Snow static const BlockJobDriver test_cancel_driver = { 19933e9e9bdSKevin Wolf .job_driver = { 200fb367e03SJohn Snow .instance_size = sizeof(CancelJob), 20180fa2c75SKevin Wolf .free = block_job_free, 202fb367e03SJohn Snow .start = cancel_job_start, 203*da01ff7fSKevin Wolf }, 204fb367e03SJohn Snow .complete = cancel_job_complete, 205fb367e03SJohn Snow }; 206fb367e03SJohn Snow 207fb367e03SJohn Snow static CancelJob *create_common(BlockJob **pjob) 208fb367e03SJohn Snow { 209fb367e03SJohn Snow BlockBackend *blk; 210fb367e03SJohn Snow BlockJob *job; 211fb367e03SJohn Snow CancelJob *s; 212fb367e03SJohn Snow 213fb367e03SJohn Snow blk = create_blk(NULL); 214fb367e03SJohn Snow job = mk_job(blk, "Steve", &test_cancel_driver, true, 215fb367e03SJohn Snow BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); 21680fa2c75SKevin Wolf job_ref(&job->job); 217a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_CREATED); 218fb367e03SJohn Snow s = container_of(job, CancelJob, common); 219fb367e03SJohn Snow s->blk = blk; 220fb367e03SJohn Snow 221fb367e03SJohn Snow *pjob = job; 222fb367e03SJohn Snow return s; 223fb367e03SJohn Snow } 224fb367e03SJohn Snow 225fb367e03SJohn Snow static void cancel_common(CancelJob *s) 226fb367e03SJohn Snow { 227fb367e03SJohn Snow BlockJob *job = &s->common; 228fb367e03SJohn Snow BlockBackend *blk = s->blk; 229a50c2ab8SKevin Wolf JobStatus sts = job->job.status; 230fb367e03SJohn Snow 231fb367e03SJohn Snow block_job_cancel_sync(job); 232a50c2ab8SKevin Wolf if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { 233fb367e03SJohn Snow BlockJob *dummy = job; 234fb367e03SJohn Snow block_job_dismiss(&dummy, &error_abort); 235fb367e03SJohn Snow } 236a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_NULL); 23780fa2c75SKevin Wolf job_unref(&job->job); 238fb367e03SJohn Snow destroy_blk(blk); 239fb367e03SJohn Snow } 240fb367e03SJohn Snow 241fb367e03SJohn Snow static void test_cancel_created(void) 242fb367e03SJohn Snow { 243fb367e03SJohn Snow BlockJob *job; 244fb367e03SJohn Snow CancelJob *s; 245fb367e03SJohn Snow 246fb367e03SJohn Snow s = create_common(&job); 247fb367e03SJohn Snow cancel_common(s); 248fb367e03SJohn Snow } 249fb367e03SJohn Snow 250fb367e03SJohn Snow static void test_cancel_running(void) 251fb367e03SJohn Snow { 252fb367e03SJohn Snow BlockJob *job; 253fb367e03SJohn Snow CancelJob *s; 254fb367e03SJohn Snow 255fb367e03SJohn Snow s = create_common(&job); 256fb367e03SJohn Snow 257*da01ff7fSKevin Wolf job_start(&job->job); 258a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_RUNNING); 259fb367e03SJohn Snow 260fb367e03SJohn Snow cancel_common(s); 261fb367e03SJohn Snow } 262fb367e03SJohn Snow 263fb367e03SJohn Snow static void test_cancel_paused(void) 264fb367e03SJohn Snow { 265fb367e03SJohn Snow BlockJob *job; 266fb367e03SJohn Snow CancelJob *s; 267fb367e03SJohn Snow 268fb367e03SJohn Snow s = create_common(&job); 269fb367e03SJohn Snow 270*da01ff7fSKevin Wolf job_start(&job->job); 271a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_RUNNING); 272fb367e03SJohn Snow 273fb367e03SJohn Snow block_job_user_pause(job, &error_abort); 274fb367e03SJohn Snow block_job_enter(job); 275a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_PAUSED); 276fb367e03SJohn Snow 277fb367e03SJohn Snow cancel_common(s); 278fb367e03SJohn Snow } 279fb367e03SJohn Snow 280fb367e03SJohn Snow static void test_cancel_ready(void) 281fb367e03SJohn Snow { 282fb367e03SJohn Snow BlockJob *job; 283fb367e03SJohn Snow CancelJob *s; 284fb367e03SJohn Snow 285fb367e03SJohn Snow s = create_common(&job); 286fb367e03SJohn Snow 287*da01ff7fSKevin Wolf job_start(&job->job); 288a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_RUNNING); 289fb367e03SJohn Snow 290fb367e03SJohn Snow s->should_converge = true; 291fb367e03SJohn Snow block_job_enter(job); 292a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_READY); 293fb367e03SJohn Snow 294fb367e03SJohn Snow cancel_common(s); 295fb367e03SJohn Snow } 296fb367e03SJohn Snow 297fb367e03SJohn Snow static void test_cancel_standby(void) 298fb367e03SJohn Snow { 299fb367e03SJohn Snow BlockJob *job; 300fb367e03SJohn Snow CancelJob *s; 301fb367e03SJohn Snow 302fb367e03SJohn Snow s = create_common(&job); 303fb367e03SJohn Snow 304*da01ff7fSKevin Wolf job_start(&job->job); 305a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_RUNNING); 306fb367e03SJohn Snow 307fb367e03SJohn Snow s->should_converge = true; 308fb367e03SJohn Snow block_job_enter(job); 309a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_READY); 310fb367e03SJohn Snow 311fb367e03SJohn Snow block_job_user_pause(job, &error_abort); 312fb367e03SJohn Snow block_job_enter(job); 313a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_STANDBY); 314fb367e03SJohn Snow 315fb367e03SJohn Snow cancel_common(s); 316fb367e03SJohn Snow } 317fb367e03SJohn Snow 318fb367e03SJohn Snow static void test_cancel_pending(void) 319fb367e03SJohn Snow { 320fb367e03SJohn Snow BlockJob *job; 321fb367e03SJohn Snow CancelJob *s; 322fb367e03SJohn Snow 323fb367e03SJohn Snow s = create_common(&job); 324fb367e03SJohn Snow 325*da01ff7fSKevin Wolf job_start(&job->job); 326a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_RUNNING); 327fb367e03SJohn Snow 328fb367e03SJohn Snow s->should_converge = true; 329fb367e03SJohn Snow block_job_enter(job); 330a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_READY); 331fb367e03SJohn Snow 332fb367e03SJohn Snow block_job_complete(job, &error_abort); 333fb367e03SJohn Snow block_job_enter(job); 334fb367e03SJohn Snow while (!s->completed) { 335fb367e03SJohn Snow aio_poll(qemu_get_aio_context(), true); 336fb367e03SJohn Snow } 337a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_PENDING); 338fb367e03SJohn Snow 339fb367e03SJohn Snow cancel_common(s); 340fb367e03SJohn Snow } 341fb367e03SJohn Snow 342fb367e03SJohn Snow static void test_cancel_concluded(void) 343fb367e03SJohn Snow { 344fb367e03SJohn Snow BlockJob *job; 345fb367e03SJohn Snow CancelJob *s; 346fb367e03SJohn Snow 347fb367e03SJohn Snow s = create_common(&job); 348fb367e03SJohn Snow 349*da01ff7fSKevin Wolf job_start(&job->job); 350a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_RUNNING); 351fb367e03SJohn Snow 352fb367e03SJohn Snow s->should_converge = true; 353fb367e03SJohn Snow block_job_enter(job); 354a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_READY); 355fb367e03SJohn Snow 356fb367e03SJohn Snow block_job_complete(job, &error_abort); 357fb367e03SJohn Snow block_job_enter(job); 358fb367e03SJohn Snow while (!s->completed) { 359fb367e03SJohn Snow aio_poll(qemu_get_aio_context(), true); 360fb367e03SJohn Snow } 361a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_PENDING); 362fb367e03SJohn Snow 363fb367e03SJohn Snow block_job_finalize(job, &error_abort); 364a50c2ab8SKevin Wolf assert(job->job.status == JOB_STATUS_CONCLUDED); 365fb367e03SJohn Snow 366fb367e03SJohn Snow cancel_common(s); 367fb367e03SJohn Snow } 368fb367e03SJohn Snow 3699ef8112aSAlberto Garcia int main(int argc, char **argv) 3709ef8112aSAlberto Garcia { 3719ef8112aSAlberto Garcia qemu_init_main_loop(&error_abort); 372d185cf0eSKevin Wolf bdrv_init(); 3739ef8112aSAlberto Garcia 3749ef8112aSAlberto Garcia g_test_init(&argc, &argv, NULL); 3759ef8112aSAlberto Garcia g_test_add_func("/blockjob/ids", test_job_ids); 376fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/created", test_cancel_created); 377fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/running", test_cancel_running); 378fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/paused", test_cancel_paused); 379fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/ready", test_cancel_ready); 380fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/standby", test_cancel_standby); 381fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/pending", test_cancel_pending); 382fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded); 3839ef8112aSAlberto Garcia return g_test_run(); 3849ef8112aSAlberto Garcia } 385