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

replay: add BH oneshot event for block layer

Replay is capable of recording normal BH events, but sometimes
there are single use callbacks scheduled with aio_bh_schedule_oneshot
function. This patch enables recording and replaying such callbacks.
Block layer uses these events for calling the completion function.
Replaying these calls makes the execution deterministic.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
Acked-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>

authored by

Pavel Dovgalyuk and committed by
Kevin Wolf
e4ec5ad4 ae25dccb

+59 -16
+6 -3
block/block-backend.c
··· 18 18 #include "hw/qdev-core.h" 19 19 #include "sysemu/blockdev.h" 20 20 #include "sysemu/runstate.h" 21 + #include "sysemu/sysemu.h" 22 + #include "sysemu/replay.h" 21 23 #include "qapi/error.h" 22 24 #include "qapi/qapi-events-block.h" 23 25 #include "qemu/id.h" ··· 1306 1308 acb->blk = blk; 1307 1309 acb->ret = ret; 1308 1310 1309 - aio_bh_schedule_oneshot(blk_get_aio_context(blk), error_callback_bh, acb); 1311 + replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), 1312 + error_callback_bh, acb); 1310 1313 return &acb->common; 1311 1314 } 1312 1315 ··· 1362 1365 1363 1366 acb->has_returned = true; 1364 1367 if (acb->rwco.ret != NOT_DONE) { 1365 - aio_bh_schedule_oneshot(blk_get_aio_context(blk), 1366 - blk_aio_complete_bh, acb); 1368 + replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), 1369 + blk_aio_complete_bh, acb); 1367 1370 } 1368 1371 1369 1372 return &acb->common;
+2 -2
block/io.c
··· 369 369 if (bs) { 370 370 bdrv_inc_in_flight(bs); 371 371 } 372 - aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), 373 - bdrv_co_drain_bh_cb, &data); 372 + replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs), 373 + bdrv_co_drain_bh_cb, &data); 374 374 375 375 qemu_coroutine_yield(); 376 376 /* If we are resumed from some other event (such as an aio completion or a
+3 -2
block/iscsi.c
··· 40 40 #include "qemu/module.h" 41 41 #include "qemu/option.h" 42 42 #include "qemu/uuid.h" 43 + #include "sysemu/replay.h" 43 44 #include "qapi/error.h" 44 45 #include "qapi/qapi-commands-misc.h" 45 46 #include "qapi/qmp/qdict.h" ··· 280 281 } 281 282 282 283 if (iTask->co) { 283 - aio_bh_schedule_oneshot(iTask->iscsilun->aio_context, 284 - iscsi_co_generic_bh_cb, iTask); 284 + replay_bh_schedule_oneshot_event(iTask->iscsilun->aio_context, 285 + iscsi_co_generic_bh_cb, iTask); 285 286 } else { 286 287 iTask->complete = 1; 287 288 }
+4 -2
block/nfs.c
··· 37 37 #include "qemu/option.h" 38 38 #include "qemu/uri.h" 39 39 #include "qemu/cutils.h" 40 + #include "sysemu/sysemu.h" 41 + #include "sysemu/replay.h" 40 42 #include "qapi/qapi-visit-block-core.h" 41 43 #include "qapi/qmp/qdict.h" 42 44 #include "qapi/qmp/qstring.h" ··· 257 259 if (task->ret < 0) { 258 260 error_report("NFS Error: %s", nfs_get_error(nfs)); 259 261 } 260 - aio_bh_schedule_oneshot(task->client->aio_context, 261 - nfs_co_generic_bh_cb, task); 262 + replay_bh_schedule_oneshot_event(task->client->aio_context, 263 + nfs_co_generic_bh_cb, task); 262 264 } 263 265 264 266 static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
+3 -1
block/null.c
··· 17 17 #include "qemu/module.h" 18 18 #include "qemu/option.h" 19 19 #include "block/block_int.h" 20 + #include "sysemu/replay.h" 20 21 21 22 #define NULL_OPT_LATENCY "latency-ns" 22 23 #define NULL_OPT_ZEROES "read-zeroes" ··· 179 180 timer_mod_ns(&acb->timer, 180 181 qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns); 181 182 } else { 182 - aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb); 183 + replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs), 184 + null_bh_cb, acb); 183 185 } 184 186 return &acb->common; 185 187 }
+4 -2
block/nvme.c
··· 23 23 #include "qemu/option.h" 24 24 #include "qemu/vfio-helpers.h" 25 25 #include "block/block_int.h" 26 + #include "sysemu/replay.h" 26 27 #include "trace.h" 27 28 28 29 #include "block/nvme.h" ··· 351 352 smp_mb_release(); 352 353 *q->cq.doorbell = cpu_to_le32(q->cq.head); 353 354 if (!qemu_co_queue_empty(&q->free_req_queue)) { 354 - aio_bh_schedule_oneshot(s->aio_context, nvme_free_req_queue_cb, q); 355 + replay_bh_schedule_oneshot_event(s->aio_context, 356 + nvme_free_req_queue_cb, q); 355 357 } 356 358 } 357 359 q->busy = false; ··· 935 937 /* The rw coroutine hasn't yielded, don't try to enter. */ 936 938 return; 937 939 } 938 - aio_bh_schedule_oneshot(data->ctx, nvme_rw_cb_bh, data); 940 + replay_bh_schedule_oneshot_event(data->ctx, nvme_rw_cb_bh, data); 939 941 } 940 942 941 943 static coroutine_fn int nvme_co_prw_aligned(BlockDriverState *bs,
+3 -2
block/rbd.c
··· 22 22 #include "block/qdict.h" 23 23 #include "crypto/secret.h" 24 24 #include "qemu/cutils.h" 25 + #include "sysemu/replay.h" 25 26 #include "qapi/qmp/qstring.h" 26 27 #include "qapi/qmp/qdict.h" 27 28 #include "qapi/qmp/qjson.h" ··· 884 885 rcb->ret = rbd_aio_get_return_value(c); 885 886 rbd_aio_release(c); 886 887 887 - aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), 888 - rbd_finish_bh, rcb); 888 + replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs), 889 + rbd_finish_bh, rcb); 889 890 } 890 891 891 892 static int rbd_aio_discard_wrapper(rbd_image_t image,
+3 -2
block/vxhs.c
··· 22 22 #include "qapi/error.h" 23 23 #include "qemu/uuid.h" 24 24 #include "crypto/tlscredsx509.h" 25 + #include "sysemu/replay.h" 25 26 26 27 #define VXHS_OPT_FILENAME "filename" 27 28 #define VXHS_OPT_VDISK_ID "vdisk-id" ··· 105 106 trace_vxhs_iio_callback(error); 106 107 } 107 108 108 - aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), 109 - vxhs_complete_aio_bh, acb); 109 + replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs), 110 + vxhs_complete_aio_bh, acb); 110 111 break; 111 112 112 113 default:
+4
include/sysemu/replay.h
··· 15 15 #include "qapi/qapi-types-misc.h" 16 16 #include "qapi/qapi-types-run-state.h" 17 17 #include "qapi/qapi-types-ui.h" 18 + #include "block/aio.h" 18 19 19 20 /* replay clock kinds */ 20 21 enum ReplayClockKind { ··· 140 141 bool replay_events_enabled(void); 141 142 /*! Adds bottom half event to the queue */ 142 143 void replay_bh_schedule_event(QEMUBH *bh); 144 + /* Adds oneshot bottom half event to the queue */ 145 + void replay_bh_schedule_oneshot_event(AioContext *ctx, 146 + QEMUBHFunc *cb, void *opaque); 143 147 /*! Adds input event to the queue */ 144 148 void replay_input_event(QemuConsole *src, InputEvent *evt); 145 149 /*! Adds input sync event to the queue */
+16
replay/replay-events.c
··· 36 36 case REPLAY_ASYNC_EVENT_BH: 37 37 aio_bh_call(event->opaque); 38 38 break; 39 + case REPLAY_ASYNC_EVENT_BH_ONESHOT: 40 + ((QEMUBHFunc *)event->opaque)(event->opaque2); 41 + break; 39 42 case REPLAY_ASYNC_EVENT_INPUT: 40 43 qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); 41 44 qapi_free_InputEvent((InputEvent *)event->opaque); ··· 131 134 } 132 135 } 133 136 137 + void replay_bh_schedule_oneshot_event(AioContext *ctx, 138 + QEMUBHFunc *cb, void *opaque) 139 + { 140 + if (events_enabled) { 141 + uint64_t id = replay_get_current_icount(); 142 + replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id); 143 + } else { 144 + aio_bh_schedule_oneshot(ctx, cb, opaque); 145 + } 146 + } 147 + 134 148 void replay_add_input_event(struct InputEvent *event) 135 149 { 136 150 replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); ··· 161 175 /* save event-specific data */ 162 176 switch (event->event_kind) { 163 177 case REPLAY_ASYNC_EVENT_BH: 178 + case REPLAY_ASYNC_EVENT_BH_ONESHOT: 164 179 replay_put_qword(event->id); 165 180 break; 166 181 case REPLAY_ASYNC_EVENT_INPUT: ··· 216 231 /* Events that has not to be in the queue */ 217 232 switch (replay_state.read_event_kind) { 218 233 case REPLAY_ASYNC_EVENT_BH: 234 + case REPLAY_ASYNC_EVENT_BH_ONESHOT: 219 235 if (replay_state.read_event_id == -1) { 220 236 replay_state.read_event_id = replay_get_qword(); 221 237 }
+1
replay/replay-internal.h
··· 51 51 52 52 enum ReplayAsyncEventKind { 53 53 REPLAY_ASYNC_EVENT_BH, 54 + REPLAY_ASYNC_EVENT_BH_ONESHOT, 54 55 REPLAY_ASYNC_EVENT_INPUT, 55 56 REPLAY_ASYNC_EVENT_INPUT_SYNC, 56 57 REPLAY_ASYNC_EVENT_CHAR_READ,
+1
stubs/Makefile.objs
··· 20 20 stub-obj-y += notify-event.o 21 21 stub-obj-y += qtest.o 22 22 stub-obj-y += replay.o 23 + stub-obj-y += replay-user.o 23 24 stub-obj-y += runstate-check.o 24 25 stub-obj-y += set-fd-handler.o 25 26 stub-obj-y += sysbus.o
+9
stubs/replay-user.c
··· 1 + #include "qemu/osdep.h" 2 + #include "sysemu/replay.h" 3 + #include "sysemu/sysemu.h" 4 + 5 + void replay_bh_schedule_oneshot_event(AioContext *ctx, 6 + QEMUBHFunc *cb, void *opaque) 7 + { 8 + aio_bh_schedule_oneshot(ctx, cb, opaque); 9 + }