qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

tests/test-blockjob: test cancellations

Whatever the state a blockjob is in, it should be able to be canceled
by the block layer.

Signed-off-by: John Snow <jsnow@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>

authored by

John Snow and committed by
Kevin Wolf
fb367e03 6d8be967

+229 -4
+229 -4
tests/test-blockjob.c
··· 24 24 { 25 25 } 26 26 27 - static BlockJob *do_test_id(BlockBackend *blk, const char *id, 28 - bool should_succeed) 27 + static BlockJob *mk_job(BlockBackend *blk, const char *id, 28 + const BlockJobDriver *drv, bool should_succeed, 29 + int flags) 29 30 { 30 31 BlockJob *job; 31 32 Error *errp = NULL; 32 33 33 - job = block_job_create(id, &test_block_job_driver, NULL, blk_bs(blk), 34 - 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, block_job_cb, 34 + job = block_job_create(id, drv, NULL, blk_bs(blk), 35 + 0, BLK_PERM_ALL, 0, flags, block_job_cb, 35 36 NULL, &errp); 36 37 if (should_succeed) { 37 38 g_assert_null(errp); ··· 48 49 } 49 50 50 51 return job; 52 + } 53 + 54 + static BlockJob *do_test_id(BlockBackend *blk, const char *id, 55 + bool should_succeed) 56 + { 57 + return mk_job(blk, id, &test_block_job_driver, 58 + should_succeed, BLOCK_JOB_DEFAULT); 51 59 } 52 60 53 61 /* This creates a BlockBackend (optionally with a name) with a ··· 142 150 destroy_blk(blk[2]); 143 151 } 144 152 153 + typedef struct CancelJob { 154 + BlockJob common; 155 + BlockBackend *blk; 156 + bool should_converge; 157 + bool should_complete; 158 + bool completed; 159 + } CancelJob; 160 + 161 + static void cancel_job_completed(BlockJob *job, void *opaque) 162 + { 163 + CancelJob *s = opaque; 164 + s->completed = true; 165 + block_job_completed(job, 0); 166 + } 167 + 168 + static void cancel_job_complete(BlockJob *job, Error **errp) 169 + { 170 + CancelJob *s = container_of(job, CancelJob, common); 171 + s->should_complete = true; 172 + } 173 + 174 + static void coroutine_fn cancel_job_start(void *opaque) 175 + { 176 + CancelJob *s = opaque; 177 + 178 + while (!s->should_complete) { 179 + if (block_job_is_cancelled(&s->common)) { 180 + goto defer; 181 + } 182 + 183 + if (!s->common.ready && s->should_converge) { 184 + block_job_event_ready(&s->common); 185 + } 186 + 187 + block_job_sleep_ns(&s->common, 100000); 188 + } 189 + 190 + defer: 191 + block_job_defer_to_main_loop(&s->common, cancel_job_completed, s); 192 + } 193 + 194 + static const BlockJobDriver test_cancel_driver = { 195 + .instance_size = sizeof(CancelJob), 196 + .start = cancel_job_start, 197 + .complete = cancel_job_complete, 198 + }; 199 + 200 + static CancelJob *create_common(BlockJob **pjob) 201 + { 202 + BlockBackend *blk; 203 + BlockJob *job; 204 + CancelJob *s; 205 + 206 + blk = create_blk(NULL); 207 + job = mk_job(blk, "Steve", &test_cancel_driver, true, 208 + BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); 209 + block_job_ref(job); 210 + assert(job->status == BLOCK_JOB_STATUS_CREATED); 211 + s = container_of(job, CancelJob, common); 212 + s->blk = blk; 213 + 214 + *pjob = job; 215 + return s; 216 + } 217 + 218 + static void cancel_common(CancelJob *s) 219 + { 220 + BlockJob *job = &s->common; 221 + BlockBackend *blk = s->blk; 222 + BlockJobStatus sts = job->status; 223 + 224 + block_job_cancel_sync(job); 225 + if ((sts != BLOCK_JOB_STATUS_CREATED) && 226 + (sts != BLOCK_JOB_STATUS_CONCLUDED)) { 227 + BlockJob *dummy = job; 228 + block_job_dismiss(&dummy, &error_abort); 229 + } 230 + assert(job->status == BLOCK_JOB_STATUS_NULL); 231 + block_job_unref(job); 232 + destroy_blk(blk); 233 + } 234 + 235 + static void test_cancel_created(void) 236 + { 237 + BlockJob *job; 238 + CancelJob *s; 239 + 240 + s = create_common(&job); 241 + cancel_common(s); 242 + } 243 + 244 + static void test_cancel_running(void) 245 + { 246 + BlockJob *job; 247 + CancelJob *s; 248 + 249 + s = create_common(&job); 250 + 251 + block_job_start(job); 252 + assert(job->status == BLOCK_JOB_STATUS_RUNNING); 253 + 254 + cancel_common(s); 255 + } 256 + 257 + static void test_cancel_paused(void) 258 + { 259 + BlockJob *job; 260 + CancelJob *s; 261 + 262 + s = create_common(&job); 263 + 264 + block_job_start(job); 265 + assert(job->status == BLOCK_JOB_STATUS_RUNNING); 266 + 267 + block_job_user_pause(job, &error_abort); 268 + block_job_enter(job); 269 + assert(job->status == BLOCK_JOB_STATUS_PAUSED); 270 + 271 + cancel_common(s); 272 + } 273 + 274 + static void test_cancel_ready(void) 275 + { 276 + BlockJob *job; 277 + CancelJob *s; 278 + 279 + s = create_common(&job); 280 + 281 + block_job_start(job); 282 + assert(job->status == BLOCK_JOB_STATUS_RUNNING); 283 + 284 + s->should_converge = true; 285 + block_job_enter(job); 286 + assert(job->status == BLOCK_JOB_STATUS_READY); 287 + 288 + cancel_common(s); 289 + } 290 + 291 + static void test_cancel_standby(void) 292 + { 293 + BlockJob *job; 294 + CancelJob *s; 295 + 296 + s = create_common(&job); 297 + 298 + block_job_start(job); 299 + assert(job->status == BLOCK_JOB_STATUS_RUNNING); 300 + 301 + s->should_converge = true; 302 + block_job_enter(job); 303 + assert(job->status == BLOCK_JOB_STATUS_READY); 304 + 305 + block_job_user_pause(job, &error_abort); 306 + block_job_enter(job); 307 + assert(job->status == BLOCK_JOB_STATUS_STANDBY); 308 + 309 + cancel_common(s); 310 + } 311 + 312 + static void test_cancel_pending(void) 313 + { 314 + BlockJob *job; 315 + CancelJob *s; 316 + 317 + s = create_common(&job); 318 + 319 + block_job_start(job); 320 + assert(job->status == BLOCK_JOB_STATUS_RUNNING); 321 + 322 + s->should_converge = true; 323 + block_job_enter(job); 324 + assert(job->status == BLOCK_JOB_STATUS_READY); 325 + 326 + block_job_complete(job, &error_abort); 327 + block_job_enter(job); 328 + while (!s->completed) { 329 + aio_poll(qemu_get_aio_context(), true); 330 + } 331 + assert(job->status == BLOCK_JOB_STATUS_PENDING); 332 + 333 + cancel_common(s); 334 + } 335 + 336 + static void test_cancel_concluded(void) 337 + { 338 + BlockJob *job; 339 + CancelJob *s; 340 + 341 + s = create_common(&job); 342 + 343 + block_job_start(job); 344 + assert(job->status == BLOCK_JOB_STATUS_RUNNING); 345 + 346 + s->should_converge = true; 347 + block_job_enter(job); 348 + assert(job->status == BLOCK_JOB_STATUS_READY); 349 + 350 + block_job_complete(job, &error_abort); 351 + block_job_enter(job); 352 + while (!s->completed) { 353 + aio_poll(qemu_get_aio_context(), true); 354 + } 355 + assert(job->status == BLOCK_JOB_STATUS_PENDING); 356 + 357 + block_job_finalize(job, &error_abort); 358 + assert(job->status == BLOCK_JOB_STATUS_CONCLUDED); 359 + 360 + cancel_common(s); 361 + } 362 + 145 363 int main(int argc, char **argv) 146 364 { 147 365 qemu_init_main_loop(&error_abort); ··· 149 367 150 368 g_test_init(&argc, &argv, NULL); 151 369 g_test_add_func("/blockjob/ids", test_job_ids); 370 + g_test_add_func("/blockjob/cancel/created", test_cancel_created); 371 + g_test_add_func("/blockjob/cancel/running", test_cancel_running); 372 + g_test_add_func("/blockjob/cancel/paused", test_cancel_paused); 373 + g_test_add_func("/blockjob/cancel/ready", test_cancel_ready); 374 + g_test_add_func("/blockjob/cancel/standby", test_cancel_standby); 375 + g_test_add_func("/blockjob/cancel/pending", test_cancel_pending); 376 + g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded); 152 377 return g_test_run(); 153 378 }