Browse Source

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>
Pavel Dovgalyuk 6 years ago
parent
commit
e4ec5ad464
13 changed files with 59 additions and 16 deletions
  1. 6 3
      block/block-backend.c
  2. 2 2
      block/io.c
  3. 3 2
      block/iscsi.c
  4. 4 2
      block/nfs.c
  5. 3 1
      block/null.c
  6. 4 2
      block/nvme.c
  7. 3 2
      block/rbd.c
  8. 3 2
      block/vxhs.c
  9. 4 0
      include/sysemu/replay.h
  10. 16 0
      replay/replay-events.c
  11. 1 0
      replay/replay-internal.h
  12. 1 0
      stubs/Makefile.objs
  13. 9 0
      stubs/replay-user.c

+ 6 - 3
block/block-backend.c

@@ -18,6 +18,8 @@
 #include "hw/qdev-core.h"
 #include "hw/qdev-core.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/runstate.h"
 #include "sysemu/runstate.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/replay.h"
 #include "qapi/error.h"
 #include "qapi/error.h"
 #include "qapi/qapi-events-block.h"
 #include "qapi/qapi-events-block.h"
 #include "qemu/id.h"
 #include "qemu/id.h"
@@ -1306,7 +1308,8 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
     acb->blk = blk;
     acb->blk = blk;
     acb->ret = ret;
     acb->ret = ret;
 
 
-    aio_bh_schedule_oneshot(blk_get_aio_context(blk), error_callback_bh, acb);
+    replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
+                                     error_callback_bh, acb);
     return &acb->common;
     return &acb->common;
 }
 }
 
 
@@ -1362,8 +1365,8 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
 
 
     acb->has_returned = true;
     acb->has_returned = true;
     if (acb->rwco.ret != NOT_DONE) {
     if (acb->rwco.ret != NOT_DONE) {
-        aio_bh_schedule_oneshot(blk_get_aio_context(blk),
-                                blk_aio_complete_bh, acb);
+        replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
+                                         blk_aio_complete_bh, acb);
     }
     }
 
 
     return &acb->common;
     return &acb->common;

+ 2 - 2
block/io.c

@@ -369,8 +369,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
     if (bs) {
     if (bs) {
         bdrv_inc_in_flight(bs);
         bdrv_inc_in_flight(bs);
     }
     }
-    aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
-                            bdrv_co_drain_bh_cb, &data);
+    replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
+                                     bdrv_co_drain_bh_cb, &data);
 
 
     qemu_coroutine_yield();
     qemu_coroutine_yield();
     /* If we are resumed from some other event (such as an aio completion or a
     /* If we are resumed from some other event (such as an aio completion or a

+ 3 - 2
block/iscsi.c

@@ -40,6 +40,7 @@
 #include "qemu/module.h"
 #include "qemu/module.h"
 #include "qemu/option.h"
 #include "qemu/option.h"
 #include "qemu/uuid.h"
 #include "qemu/uuid.h"
+#include "sysemu/replay.h"
 #include "qapi/error.h"
 #include "qapi/error.h"
 #include "qapi/qapi-commands-misc.h"
 #include "qapi/qapi-commands-misc.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qdict.h"
@@ -280,8 +281,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
     }
     }
 
 
     if (iTask->co) {
     if (iTask->co) {
-        aio_bh_schedule_oneshot(iTask->iscsilun->aio_context,
-                                 iscsi_co_generic_bh_cb, iTask);
+        replay_bh_schedule_oneshot_event(iTask->iscsilun->aio_context,
+                                         iscsi_co_generic_bh_cb, iTask);
     } else {
     } else {
         iTask->complete = 1;
         iTask->complete = 1;
     }
     }

+ 4 - 2
block/nfs.c

@@ -37,6 +37,8 @@
 #include "qemu/option.h"
 #include "qemu/option.h"
 #include "qemu/uri.h"
 #include "qemu/uri.h"
 #include "qemu/cutils.h"
 #include "qemu/cutils.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/replay.h"
 #include "qapi/qapi-visit-block-core.h"
 #include "qapi/qapi-visit-block-core.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qstring.h"
 #include "qapi/qmp/qstring.h"
@@ -257,8 +259,8 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
     if (task->ret < 0) {
     if (task->ret < 0) {
         error_report("NFS Error: %s", nfs_get_error(nfs));
         error_report("NFS Error: %s", nfs_get_error(nfs));
     }
     }
-    aio_bh_schedule_oneshot(task->client->aio_context,
-                            nfs_co_generic_bh_cb, task);
+    replay_bh_schedule_oneshot_event(task->client->aio_context,
+                                     nfs_co_generic_bh_cb, task);
 }
 }
 
 
 static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
 static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,

+ 3 - 1
block/null.c

@@ -17,6 +17,7 @@
 #include "qemu/module.h"
 #include "qemu/module.h"
 #include "qemu/option.h"
 #include "qemu/option.h"
 #include "block/block_int.h"
 #include "block/block_int.h"
+#include "sysemu/replay.h"
 
 
 #define NULL_OPT_LATENCY "latency-ns"
 #define NULL_OPT_LATENCY "latency-ns"
 #define NULL_OPT_ZEROES  "read-zeroes"
 #define NULL_OPT_ZEROES  "read-zeroes"
@@ -179,7 +180,8 @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
         timer_mod_ns(&acb->timer,
         timer_mod_ns(&acb->timer,
                      qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
                      qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
     } else {
     } else {
-        aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb);
+        replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
+                                         null_bh_cb, acb);
     }
     }
     return &acb->common;
     return &acb->common;
 }
 }

+ 4 - 2
block/nvme.c

@@ -23,6 +23,7 @@
 #include "qemu/option.h"
 #include "qemu/option.h"
 #include "qemu/vfio-helpers.h"
 #include "qemu/vfio-helpers.h"
 #include "block/block_int.h"
 #include "block/block_int.h"
+#include "sysemu/replay.h"
 #include "trace.h"
 #include "trace.h"
 
 
 #include "block/nvme.h"
 #include "block/nvme.h"
@@ -351,7 +352,8 @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q)
         smp_mb_release();
         smp_mb_release();
         *q->cq.doorbell = cpu_to_le32(q->cq.head);
         *q->cq.doorbell = cpu_to_le32(q->cq.head);
         if (!qemu_co_queue_empty(&q->free_req_queue)) {
         if (!qemu_co_queue_empty(&q->free_req_queue)) {
-            aio_bh_schedule_oneshot(s->aio_context, nvme_free_req_queue_cb, q);
+            replay_bh_schedule_oneshot_event(s->aio_context,
+                                             nvme_free_req_queue_cb, q);
         }
         }
     }
     }
     q->busy = false;
     q->busy = false;
@@ -935,7 +937,7 @@ static void nvme_rw_cb(void *opaque, int ret)
         /* The rw coroutine hasn't yielded, don't try to enter. */
         /* The rw coroutine hasn't yielded, don't try to enter. */
         return;
         return;
     }
     }
-    aio_bh_schedule_oneshot(data->ctx, nvme_rw_cb_bh, data);
+    replay_bh_schedule_oneshot_event(data->ctx, nvme_rw_cb_bh, data);
 }
 }
 
 
 static coroutine_fn int nvme_co_prw_aligned(BlockDriverState *bs,
 static coroutine_fn int nvme_co_prw_aligned(BlockDriverState *bs,

+ 3 - 2
block/rbd.c

@@ -22,6 +22,7 @@
 #include "block/qdict.h"
 #include "block/qdict.h"
 #include "crypto/secret.h"
 #include "crypto/secret.h"
 #include "qemu/cutils.h"
 #include "qemu/cutils.h"
+#include "sysemu/replay.h"
 #include "qapi/qmp/qstring.h"
 #include "qapi/qmp/qstring.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
 #include "qapi/qmp/qjson.h"
@@ -884,8 +885,8 @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
     rcb->ret = rbd_aio_get_return_value(c);
     rcb->ret = rbd_aio_get_return_value(c);
     rbd_aio_release(c);
     rbd_aio_release(c);
 
 
-    aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
-                            rbd_finish_bh, rcb);
+    replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs),
+                                     rbd_finish_bh, rcb);
 }
 }
 
 
 static int rbd_aio_discard_wrapper(rbd_image_t image,
 static int rbd_aio_discard_wrapper(rbd_image_t image,

+ 3 - 2
block/vxhs.c

@@ -22,6 +22,7 @@
 #include "qapi/error.h"
 #include "qapi/error.h"
 #include "qemu/uuid.h"
 #include "qemu/uuid.h"
 #include "crypto/tlscredsx509.h"
 #include "crypto/tlscredsx509.h"
+#include "sysemu/replay.h"
 
 
 #define VXHS_OPT_FILENAME           "filename"
 #define VXHS_OPT_FILENAME           "filename"
 #define VXHS_OPT_VDISK_ID           "vdisk-id"
 #define VXHS_OPT_VDISK_ID           "vdisk-id"
@@ -105,8 +106,8 @@ static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error)
             trace_vxhs_iio_callback(error);
             trace_vxhs_iio_callback(error);
         }
         }
 
 
-        aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
-                                vxhs_complete_aio_bh, acb);
+        replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs),
+                                         vxhs_complete_aio_bh, acb);
         break;
         break;
 
 
     default:
     default:

+ 4 - 0
include/sysemu/replay.h

@@ -15,6 +15,7 @@
 #include "qapi/qapi-types-misc.h"
 #include "qapi/qapi-types-misc.h"
 #include "qapi/qapi-types-run-state.h"
 #include "qapi/qapi-types-run-state.h"
 #include "qapi/qapi-types-ui.h"
 #include "qapi/qapi-types-ui.h"
+#include "block/aio.h"
 
 
 /* replay clock kinds */
 /* replay clock kinds */
 enum ReplayClockKind {
 enum ReplayClockKind {
@@ -140,6 +141,9 @@ void replay_enable_events(void);
 bool replay_events_enabled(void);
 bool replay_events_enabled(void);
 /*! Adds bottom half event to the queue */
 /*! Adds bottom half event to the queue */
 void replay_bh_schedule_event(QEMUBH *bh);
 void replay_bh_schedule_event(QEMUBH *bh);
+/* Adds oneshot bottom half event to the queue */
+void replay_bh_schedule_oneshot_event(AioContext *ctx,
+    QEMUBHFunc *cb, void *opaque);
 /*! Adds input event to the queue */
 /*! Adds input event to the queue */
 void replay_input_event(QemuConsole *src, InputEvent *evt);
 void replay_input_event(QemuConsole *src, InputEvent *evt);
 /*! Adds input sync event to the queue */
 /*! Adds input sync event to the queue */

+ 16 - 0
replay/replay-events.c

@@ -36,6 +36,9 @@ static void replay_run_event(Event *event)
     case REPLAY_ASYNC_EVENT_BH:
     case REPLAY_ASYNC_EVENT_BH:
         aio_bh_call(event->opaque);
         aio_bh_call(event->opaque);
         break;
         break;
+    case REPLAY_ASYNC_EVENT_BH_ONESHOT:
+        ((QEMUBHFunc *)event->opaque)(event->opaque2);
+        break;
     case REPLAY_ASYNC_EVENT_INPUT:
     case REPLAY_ASYNC_EVENT_INPUT:
         qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
         qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
         qapi_free_InputEvent((InputEvent *)event->opaque);
         qapi_free_InputEvent((InputEvent *)event->opaque);
@@ -131,6 +134,17 @@ void replay_bh_schedule_event(QEMUBH *bh)
     }
     }
 }
 }
 
 
+void replay_bh_schedule_oneshot_event(AioContext *ctx,
+    QEMUBHFunc *cb, void *opaque)
+{
+    if (events_enabled) {
+        uint64_t id = replay_get_current_icount();
+        replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id);
+    } else {
+        aio_bh_schedule_oneshot(ctx, cb, opaque);
+    }
+}
+
 void replay_add_input_event(struct InputEvent *event)
 void replay_add_input_event(struct InputEvent *event)
 {
 {
     replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
     replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
@@ -161,6 +175,7 @@ static void replay_save_event(Event *event, int checkpoint)
         /* save event-specific data */
         /* save event-specific data */
         switch (event->event_kind) {
         switch (event->event_kind) {
         case REPLAY_ASYNC_EVENT_BH:
         case REPLAY_ASYNC_EVENT_BH:
+        case REPLAY_ASYNC_EVENT_BH_ONESHOT:
             replay_put_qword(event->id);
             replay_put_qword(event->id);
             break;
             break;
         case REPLAY_ASYNC_EVENT_INPUT:
         case REPLAY_ASYNC_EVENT_INPUT:
@@ -216,6 +231,7 @@ static Event *replay_read_event(int checkpoint)
     /* Events that has not to be in the queue */
     /* Events that has not to be in the queue */
     switch (replay_state.read_event_kind) {
     switch (replay_state.read_event_kind) {
     case REPLAY_ASYNC_EVENT_BH:
     case REPLAY_ASYNC_EVENT_BH:
+    case REPLAY_ASYNC_EVENT_BH_ONESHOT:
         if (replay_state.read_event_id == -1) {
         if (replay_state.read_event_id == -1) {
             replay_state.read_event_id = replay_get_qword();
             replay_state.read_event_id = replay_get_qword();
         }
         }

+ 1 - 0
replay/replay-internal.h

@@ -51,6 +51,7 @@ enum ReplayEvents {
 
 
 enum ReplayAsyncEventKind {
 enum ReplayAsyncEventKind {
     REPLAY_ASYNC_EVENT_BH,
     REPLAY_ASYNC_EVENT_BH,
+    REPLAY_ASYNC_EVENT_BH_ONESHOT,
     REPLAY_ASYNC_EVENT_INPUT,
     REPLAY_ASYNC_EVENT_INPUT,
     REPLAY_ASYNC_EVENT_INPUT_SYNC,
     REPLAY_ASYNC_EVENT_INPUT_SYNC,
     REPLAY_ASYNC_EVENT_CHAR_READ,
     REPLAY_ASYNC_EVENT_CHAR_READ,

+ 1 - 0
stubs/Makefile.objs

@@ -20,6 +20,7 @@ stub-obj-y += monitor.o
 stub-obj-y += notify-event.o
 stub-obj-y += notify-event.o
 stub-obj-y += qtest.o
 stub-obj-y += qtest.o
 stub-obj-y += replay.o
 stub-obj-y += replay.o
+stub-obj-y += replay-user.o
 stub-obj-y += runstate-check.o
 stub-obj-y += runstate-check.o
 stub-obj-y += set-fd-handler.o
 stub-obj-y += set-fd-handler.o
 stub-obj-y += sysbus.o
 stub-obj-y += sysbus.o

+ 9 - 0
stubs/replay-user.c

@@ -0,0 +1,9 @@
+#include "qemu/osdep.h"
+#include "sysemu/replay.h"
+#include "sysemu/sysemu.h"
+
+void replay_bh_schedule_oneshot_event(AioContext *ctx,
+    QEMUBHFunc *cb, void *opaque)
+{
+    aio_bh_schedule_oneshot(ctx, cb, opaque);
+}