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 = { 209ef8112aSAlberto Garcia .instance_size = sizeof(BlockJob), 219ef8112aSAlberto Garcia }; 229ef8112aSAlberto Garcia 239ef8112aSAlberto Garcia static void block_job_cb(void *opaque, int ret) 249ef8112aSAlberto Garcia { 259ef8112aSAlberto Garcia } 269ef8112aSAlberto Garcia 27*fb367e03SJohn Snow static BlockJob *mk_job(BlockBackend *blk, const char *id, 28*fb367e03SJohn Snow const BlockJobDriver *drv, bool should_succeed, 29*fb367e03SJohn Snow int flags) 309ef8112aSAlberto Garcia { 319ef8112aSAlberto Garcia BlockJob *job; 329ef8112aSAlberto Garcia Error *errp = NULL; 339ef8112aSAlberto Garcia 34*fb367e03SJohn Snow job = block_job_create(id, drv, NULL, blk_bs(blk), 35*fb367e03SJohn Snow 0, BLK_PERM_ALL, 0, flags, block_job_cb, 36c6cc12bfSKevin Wolf NULL, &errp); 379ef8112aSAlberto Garcia if (should_succeed) { 389ef8112aSAlberto Garcia g_assert_null(errp); 399ef8112aSAlberto Garcia g_assert_nonnull(job); 409ef8112aSAlberto Garcia if (id) { 419ef8112aSAlberto Garcia g_assert_cmpstr(job->id, ==, id); 429ef8112aSAlberto Garcia } else { 439ef8112aSAlberto Garcia g_assert_cmpstr(job->id, ==, blk_name(blk)); 449ef8112aSAlberto Garcia } 459ef8112aSAlberto Garcia } else { 469ef8112aSAlberto Garcia g_assert_nonnull(errp); 479ef8112aSAlberto Garcia g_assert_null(job); 489ef8112aSAlberto Garcia error_free(errp); 499ef8112aSAlberto Garcia } 509ef8112aSAlberto Garcia 519ef8112aSAlberto Garcia return job; 529ef8112aSAlberto Garcia } 539ef8112aSAlberto Garcia 54*fb367e03SJohn Snow static BlockJob *do_test_id(BlockBackend *blk, const char *id, 55*fb367e03SJohn Snow bool should_succeed) 56*fb367e03SJohn Snow { 57*fb367e03SJohn Snow return mk_job(blk, id, &test_block_job_driver, 58*fb367e03SJohn Snow should_succeed, BLOCK_JOB_DEFAULT); 59*fb367e03SJohn Snow } 60*fb367e03SJohn Snow 619ef8112aSAlberto Garcia /* This creates a BlockBackend (optionally with a name) with a 629ef8112aSAlberto Garcia * BlockDriverState inserted. */ 639ef8112aSAlberto Garcia static BlockBackend *create_blk(const char *name) 649ef8112aSAlberto Garcia { 652807c0cdSKevin Wolf /* No I/O is performed on this device */ 666d0eb64dSKevin Wolf BlockBackend *blk = blk_new(0, BLK_PERM_ALL); 67d185cf0eSKevin Wolf BlockDriverState *bs; 68d185cf0eSKevin Wolf 69d185cf0eSKevin Wolf bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort); 70d185cf0eSKevin Wolf g_assert_nonnull(bs); 719ef8112aSAlberto Garcia 72d7086422SKevin Wolf blk_insert_bs(blk, bs, &error_abort); 739ef8112aSAlberto Garcia bdrv_unref(bs); 749ef8112aSAlberto Garcia 759ef8112aSAlberto Garcia if (name) { 769ef8112aSAlberto Garcia Error *errp = NULL; 779ef8112aSAlberto Garcia monitor_add_blk(blk, name, &errp); 789ef8112aSAlberto Garcia g_assert_null(errp); 799ef8112aSAlberto Garcia } 809ef8112aSAlberto Garcia 819ef8112aSAlberto Garcia return blk; 829ef8112aSAlberto Garcia } 839ef8112aSAlberto Garcia 849ef8112aSAlberto Garcia /* This destroys the backend */ 859ef8112aSAlberto Garcia static void destroy_blk(BlockBackend *blk) 869ef8112aSAlberto Garcia { 879ef8112aSAlberto Garcia if (blk_name(blk)[0] != '\0') { 889ef8112aSAlberto Garcia monitor_remove_blk(blk); 899ef8112aSAlberto Garcia } 909ef8112aSAlberto Garcia 919ef8112aSAlberto Garcia blk_remove_bs(blk); 929ef8112aSAlberto Garcia blk_unref(blk); 939ef8112aSAlberto Garcia } 949ef8112aSAlberto Garcia 959ef8112aSAlberto Garcia static void test_job_ids(void) 969ef8112aSAlberto Garcia { 979ef8112aSAlberto Garcia BlockBackend *blk[3]; 989ef8112aSAlberto Garcia BlockJob *job[3]; 999ef8112aSAlberto Garcia 1009ef8112aSAlberto Garcia blk[0] = create_blk(NULL); 1019ef8112aSAlberto Garcia blk[1] = create_blk("drive1"); 1029ef8112aSAlberto Garcia blk[2] = create_blk("drive2"); 1039ef8112aSAlberto Garcia 1049ef8112aSAlberto Garcia /* No job ID provided and the block backend has no name */ 1059ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], NULL, false); 1069ef8112aSAlberto Garcia 1079ef8112aSAlberto Garcia /* These are all invalid job IDs */ 1089ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "0id", false); 1099ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "", false); 1109ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], " ", false); 1119ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "123", false); 1129ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "_id", false); 1139ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "-id", false); 1149ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], ".id", false); 1159ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "#id", false); 1169ef8112aSAlberto Garcia 1179ef8112aSAlberto Garcia /* This one is valid */ 1189ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "id0", true); 1199ef8112aSAlberto Garcia 1209ef8112aSAlberto Garcia /* We cannot have two jobs in the same BDS */ 1219ef8112aSAlberto Garcia do_test_id(blk[0], "id1", false); 1229ef8112aSAlberto Garcia 1239ef8112aSAlberto Garcia /* Duplicate job IDs are not allowed */ 1249ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], "id0", false); 1259ef8112aSAlberto Garcia 1269ef8112aSAlberto Garcia /* But once job[0] finishes we can reuse its ID */ 12705b0d8e3SPaolo Bonzini block_job_early_fail(job[0]); 1289ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], "id0", true); 1299ef8112aSAlberto Garcia 1309ef8112aSAlberto Garcia /* No job ID specified, defaults to the backend name ('drive1') */ 13105b0d8e3SPaolo Bonzini block_job_early_fail(job[1]); 1329ef8112aSAlberto Garcia job[1] = do_test_id(blk[1], NULL, true); 1339ef8112aSAlberto Garcia 1349ef8112aSAlberto Garcia /* Duplicate job ID */ 1359ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], "drive1", false); 1369ef8112aSAlberto Garcia 1379ef8112aSAlberto Garcia /* The ID of job[2] would default to 'drive2' but it is already in use */ 1389ef8112aSAlberto Garcia job[0] = do_test_id(blk[0], "drive2", true); 1399ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], NULL, false); 1409ef8112aSAlberto Garcia 1419ef8112aSAlberto Garcia /* This one is valid */ 1429ef8112aSAlberto Garcia job[2] = do_test_id(blk[2], "id_2", true); 1439ef8112aSAlberto Garcia 14405b0d8e3SPaolo Bonzini block_job_early_fail(job[0]); 14505b0d8e3SPaolo Bonzini block_job_early_fail(job[1]); 14605b0d8e3SPaolo Bonzini block_job_early_fail(job[2]); 1479ef8112aSAlberto Garcia 1489ef8112aSAlberto Garcia destroy_blk(blk[0]); 1499ef8112aSAlberto Garcia destroy_blk(blk[1]); 1509ef8112aSAlberto Garcia destroy_blk(blk[2]); 1519ef8112aSAlberto Garcia } 1529ef8112aSAlberto Garcia 153*fb367e03SJohn Snow typedef struct CancelJob { 154*fb367e03SJohn Snow BlockJob common; 155*fb367e03SJohn Snow BlockBackend *blk; 156*fb367e03SJohn Snow bool should_converge; 157*fb367e03SJohn Snow bool should_complete; 158*fb367e03SJohn Snow bool completed; 159*fb367e03SJohn Snow } CancelJob; 160*fb367e03SJohn Snow 161*fb367e03SJohn Snow static void cancel_job_completed(BlockJob *job, void *opaque) 162*fb367e03SJohn Snow { 163*fb367e03SJohn Snow CancelJob *s = opaque; 164*fb367e03SJohn Snow s->completed = true; 165*fb367e03SJohn Snow block_job_completed(job, 0); 166*fb367e03SJohn Snow } 167*fb367e03SJohn Snow 168*fb367e03SJohn Snow static void cancel_job_complete(BlockJob *job, Error **errp) 169*fb367e03SJohn Snow { 170*fb367e03SJohn Snow CancelJob *s = container_of(job, CancelJob, common); 171*fb367e03SJohn Snow s->should_complete = true; 172*fb367e03SJohn Snow } 173*fb367e03SJohn Snow 174*fb367e03SJohn Snow static void coroutine_fn cancel_job_start(void *opaque) 175*fb367e03SJohn Snow { 176*fb367e03SJohn Snow CancelJob *s = opaque; 177*fb367e03SJohn Snow 178*fb367e03SJohn Snow while (!s->should_complete) { 179*fb367e03SJohn Snow if (block_job_is_cancelled(&s->common)) { 180*fb367e03SJohn Snow goto defer; 181*fb367e03SJohn Snow } 182*fb367e03SJohn Snow 183*fb367e03SJohn Snow if (!s->common.ready && s->should_converge) { 184*fb367e03SJohn Snow block_job_event_ready(&s->common); 185*fb367e03SJohn Snow } 186*fb367e03SJohn Snow 187*fb367e03SJohn Snow block_job_sleep_ns(&s->common, 100000); 188*fb367e03SJohn Snow } 189*fb367e03SJohn Snow 190*fb367e03SJohn Snow defer: 191*fb367e03SJohn Snow block_job_defer_to_main_loop(&s->common, cancel_job_completed, s); 192*fb367e03SJohn Snow } 193*fb367e03SJohn Snow 194*fb367e03SJohn Snow static const BlockJobDriver test_cancel_driver = { 195*fb367e03SJohn Snow .instance_size = sizeof(CancelJob), 196*fb367e03SJohn Snow .start = cancel_job_start, 197*fb367e03SJohn Snow .complete = cancel_job_complete, 198*fb367e03SJohn Snow }; 199*fb367e03SJohn Snow 200*fb367e03SJohn Snow static CancelJob *create_common(BlockJob **pjob) 201*fb367e03SJohn Snow { 202*fb367e03SJohn Snow BlockBackend *blk; 203*fb367e03SJohn Snow BlockJob *job; 204*fb367e03SJohn Snow CancelJob *s; 205*fb367e03SJohn Snow 206*fb367e03SJohn Snow blk = create_blk(NULL); 207*fb367e03SJohn Snow job = mk_job(blk, "Steve", &test_cancel_driver, true, 208*fb367e03SJohn Snow BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); 209*fb367e03SJohn Snow block_job_ref(job); 210*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_CREATED); 211*fb367e03SJohn Snow s = container_of(job, CancelJob, common); 212*fb367e03SJohn Snow s->blk = blk; 213*fb367e03SJohn Snow 214*fb367e03SJohn Snow *pjob = job; 215*fb367e03SJohn Snow return s; 216*fb367e03SJohn Snow } 217*fb367e03SJohn Snow 218*fb367e03SJohn Snow static void cancel_common(CancelJob *s) 219*fb367e03SJohn Snow { 220*fb367e03SJohn Snow BlockJob *job = &s->common; 221*fb367e03SJohn Snow BlockBackend *blk = s->blk; 222*fb367e03SJohn Snow BlockJobStatus sts = job->status; 223*fb367e03SJohn Snow 224*fb367e03SJohn Snow block_job_cancel_sync(job); 225*fb367e03SJohn Snow if ((sts != BLOCK_JOB_STATUS_CREATED) && 226*fb367e03SJohn Snow (sts != BLOCK_JOB_STATUS_CONCLUDED)) { 227*fb367e03SJohn Snow BlockJob *dummy = job; 228*fb367e03SJohn Snow block_job_dismiss(&dummy, &error_abort); 229*fb367e03SJohn Snow } 230*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_NULL); 231*fb367e03SJohn Snow block_job_unref(job); 232*fb367e03SJohn Snow destroy_blk(blk); 233*fb367e03SJohn Snow } 234*fb367e03SJohn Snow 235*fb367e03SJohn Snow static void test_cancel_created(void) 236*fb367e03SJohn Snow { 237*fb367e03SJohn Snow BlockJob *job; 238*fb367e03SJohn Snow CancelJob *s; 239*fb367e03SJohn Snow 240*fb367e03SJohn Snow s = create_common(&job); 241*fb367e03SJohn Snow cancel_common(s); 242*fb367e03SJohn Snow } 243*fb367e03SJohn Snow 244*fb367e03SJohn Snow static void test_cancel_running(void) 245*fb367e03SJohn Snow { 246*fb367e03SJohn Snow BlockJob *job; 247*fb367e03SJohn Snow CancelJob *s; 248*fb367e03SJohn Snow 249*fb367e03SJohn Snow s = create_common(&job); 250*fb367e03SJohn Snow 251*fb367e03SJohn Snow block_job_start(job); 252*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_RUNNING); 253*fb367e03SJohn Snow 254*fb367e03SJohn Snow cancel_common(s); 255*fb367e03SJohn Snow } 256*fb367e03SJohn Snow 257*fb367e03SJohn Snow static void test_cancel_paused(void) 258*fb367e03SJohn Snow { 259*fb367e03SJohn Snow BlockJob *job; 260*fb367e03SJohn Snow CancelJob *s; 261*fb367e03SJohn Snow 262*fb367e03SJohn Snow s = create_common(&job); 263*fb367e03SJohn Snow 264*fb367e03SJohn Snow block_job_start(job); 265*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_RUNNING); 266*fb367e03SJohn Snow 267*fb367e03SJohn Snow block_job_user_pause(job, &error_abort); 268*fb367e03SJohn Snow block_job_enter(job); 269*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_PAUSED); 270*fb367e03SJohn Snow 271*fb367e03SJohn Snow cancel_common(s); 272*fb367e03SJohn Snow } 273*fb367e03SJohn Snow 274*fb367e03SJohn Snow static void test_cancel_ready(void) 275*fb367e03SJohn Snow { 276*fb367e03SJohn Snow BlockJob *job; 277*fb367e03SJohn Snow CancelJob *s; 278*fb367e03SJohn Snow 279*fb367e03SJohn Snow s = create_common(&job); 280*fb367e03SJohn Snow 281*fb367e03SJohn Snow block_job_start(job); 282*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_RUNNING); 283*fb367e03SJohn Snow 284*fb367e03SJohn Snow s->should_converge = true; 285*fb367e03SJohn Snow block_job_enter(job); 286*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_READY); 287*fb367e03SJohn Snow 288*fb367e03SJohn Snow cancel_common(s); 289*fb367e03SJohn Snow } 290*fb367e03SJohn Snow 291*fb367e03SJohn Snow static void test_cancel_standby(void) 292*fb367e03SJohn Snow { 293*fb367e03SJohn Snow BlockJob *job; 294*fb367e03SJohn Snow CancelJob *s; 295*fb367e03SJohn Snow 296*fb367e03SJohn Snow s = create_common(&job); 297*fb367e03SJohn Snow 298*fb367e03SJohn Snow block_job_start(job); 299*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_RUNNING); 300*fb367e03SJohn Snow 301*fb367e03SJohn Snow s->should_converge = true; 302*fb367e03SJohn Snow block_job_enter(job); 303*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_READY); 304*fb367e03SJohn Snow 305*fb367e03SJohn Snow block_job_user_pause(job, &error_abort); 306*fb367e03SJohn Snow block_job_enter(job); 307*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_STANDBY); 308*fb367e03SJohn Snow 309*fb367e03SJohn Snow cancel_common(s); 310*fb367e03SJohn Snow } 311*fb367e03SJohn Snow 312*fb367e03SJohn Snow static void test_cancel_pending(void) 313*fb367e03SJohn Snow { 314*fb367e03SJohn Snow BlockJob *job; 315*fb367e03SJohn Snow CancelJob *s; 316*fb367e03SJohn Snow 317*fb367e03SJohn Snow s = create_common(&job); 318*fb367e03SJohn Snow 319*fb367e03SJohn Snow block_job_start(job); 320*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_RUNNING); 321*fb367e03SJohn Snow 322*fb367e03SJohn Snow s->should_converge = true; 323*fb367e03SJohn Snow block_job_enter(job); 324*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_READY); 325*fb367e03SJohn Snow 326*fb367e03SJohn Snow block_job_complete(job, &error_abort); 327*fb367e03SJohn Snow block_job_enter(job); 328*fb367e03SJohn Snow while (!s->completed) { 329*fb367e03SJohn Snow aio_poll(qemu_get_aio_context(), true); 330*fb367e03SJohn Snow } 331*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_PENDING); 332*fb367e03SJohn Snow 333*fb367e03SJohn Snow cancel_common(s); 334*fb367e03SJohn Snow } 335*fb367e03SJohn Snow 336*fb367e03SJohn Snow static void test_cancel_concluded(void) 337*fb367e03SJohn Snow { 338*fb367e03SJohn Snow BlockJob *job; 339*fb367e03SJohn Snow CancelJob *s; 340*fb367e03SJohn Snow 341*fb367e03SJohn Snow s = create_common(&job); 342*fb367e03SJohn Snow 343*fb367e03SJohn Snow block_job_start(job); 344*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_RUNNING); 345*fb367e03SJohn Snow 346*fb367e03SJohn Snow s->should_converge = true; 347*fb367e03SJohn Snow block_job_enter(job); 348*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_READY); 349*fb367e03SJohn Snow 350*fb367e03SJohn Snow block_job_complete(job, &error_abort); 351*fb367e03SJohn Snow block_job_enter(job); 352*fb367e03SJohn Snow while (!s->completed) { 353*fb367e03SJohn Snow aio_poll(qemu_get_aio_context(), true); 354*fb367e03SJohn Snow } 355*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_PENDING); 356*fb367e03SJohn Snow 357*fb367e03SJohn Snow block_job_finalize(job, &error_abort); 358*fb367e03SJohn Snow assert(job->status == BLOCK_JOB_STATUS_CONCLUDED); 359*fb367e03SJohn Snow 360*fb367e03SJohn Snow cancel_common(s); 361*fb367e03SJohn Snow } 362*fb367e03SJohn Snow 3639ef8112aSAlberto Garcia int main(int argc, char **argv) 3649ef8112aSAlberto Garcia { 3659ef8112aSAlberto Garcia qemu_init_main_loop(&error_abort); 366d185cf0eSKevin Wolf bdrv_init(); 3679ef8112aSAlberto Garcia 3689ef8112aSAlberto Garcia g_test_init(&argc, &argv, NULL); 3699ef8112aSAlberto Garcia g_test_add_func("/blockjob/ids", test_job_ids); 370*fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/created", test_cancel_created); 371*fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/running", test_cancel_running); 372*fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/paused", test_cancel_paused); 373*fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/ready", test_cancel_ready); 374*fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/standby", test_cancel_standby); 375*fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/pending", test_cancel_pending); 376*fb367e03SJohn Snow g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded); 3779ef8112aSAlberto Garcia return g_test_run(); 3789ef8112aSAlberto Garcia } 379