Skip to contentSkip to conversation

icount/replay additions

PATCH Superseded Pavel Dovgalyuk 3 participants 9 messages Jun 8, 2016 – Jun 29, 2016

Subsystems (2)

v1 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

cover icount/replay additions

This set of patches includes fixes and additions for icount and record/replay implementation:
- Fixing icount processing on exceptions in PPC
- Enabling VM start/stop in replay mode
- Adding network record/replay

---

Pavel Dovgalyuk (3):
target-ppc: exceptions handling in icount mode
replay: allow replay stopping and restarting record/replay: add network support

 block/blkreplay.c            |   18 +++-
 cpus.c                       |    1 
 docs/replay.txt              |   14 +++
 include/sysemu/replay.h      |   14 +++
 net/Makefile.objs            |    1 
 net/filter-replay.c          |   90 ++++++++++++++++++++
 replay/Makefile.objs         |    1 
 replay/replay-events.c       |   11 ++
 replay/replay-internal.h     |   12 ++-
 replay/replay-net.c          |  110 ++++++++++++++++++++++++
 replay/replay.c              |    2 
 target-ppc/cpu.h             |    3 +
 target-ppc/excp_helper.c     |   38 ++++++--
 target-ppc/fpu_helper.c      |  192 ++++++++++++++++++++++--------------------
 target-ppc/helper.h          |    1 
 target-ppc/mem_helper.c      |    6 +
 target-ppc/misc_helper.c     |    8 +-
 target-ppc/mmu-hash64.c      |   12 +--
 target-ppc/mmu_helper.c      |   18 ++--
 target-ppc/timebase_helper.c |   21 ++---
 target-ppc/translate.c       |   84 +-----------------
 vl.c                         |    4 +
 22 files changed, 438 insertions(+), 223 deletions(-)
 create mode 100644 net/filter-replay.c
 create mode 100644 replay/replay-net.c
Signature · 1 line
Pavel Dovgalyuk
#1 lore raw

PATCH 1/3 target-ppc: exceptions handling in icount mode

From: Pavel Dovgalyuk <[email protected]>

This patch fixes exception handling in PowerPC.
Instructions generate several types of exceptions.
When exception is generated, it breaks the execution of the current translation block. Implementation of the exceptions handling does not correctly restore icount for the instruction which caused the exception. In most cases icount will be decreased by the value equal to the size of TB. This patch passes pointer to the translation block internals to the exception handler. It allows correct restoring of the icount value.

---
 target-ppc/cpu.h             |    3 +
 target-ppc/excp_helper.c     |   38 ++++++--
 target-ppc/fpu_helper.c      |  192 ++++++++++++++++++++++--------------------
 target-ppc/helper.h          |    1 
 target-ppc/mem_helper.c      |    6 +
 target-ppc/misc_helper.c     |    8 +-
 target-ppc/mmu-hash64.c      |   12 +--
 target-ppc/mmu_helper.c      |   18 ++--
 target-ppc/timebase_helper.c |   21 ++---
 target-ppc/translate.c       |   84 +-----------------
 10 files changed, 169 insertions(+), 214 deletions(-)
target-ppc/cpu.h +3 -0
index 98a24a5..4d7319a 100644
@@ -2391,4 +2391,7 @@ int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
 PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
 
 void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
+void raise_exception_err(CPUPPCState *env, uint32_t exception,
+                         uint32_t error_code, uintptr_t pc);
+
 #endif /* !defined (__CPU_PPC_H__) */
target-ppc/excp_helper.c +29 -9
index a37009e..ec006fa 100644
@@ -887,8 +887,8 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
 /*****************************************************************************/
 /* Exceptions processing helpers */
 
-void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
-                                uint32_t error_code)
+void raise_exception_err(CPUPPCState *env, uint32_t exception,
+                         uint32_t error_code, uintptr_t pc)
 {
     CPUState *cs = CPU(ppc_env_get_cpu(env));
 
@@ -897,15 +897,32 @@ void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
 #endif
     cs->exception_index = exception;
     env->error_code = error_code;
-    cpu_loop_exit(cs);
+    cpu_loop_exit_restore(cs, pc);
+}
+
+void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
+                                uint32_t error_code)
+{
+    raise_exception_err(env, exception, error_code, GETPC());
+}
+
+void helper_raise_exception_end(CPUPPCState *env, uint32_t exception,
+                                uint32_t error_code)
+{
+    raise_exception_err(env, exception, error_code, 0);
 }
 
 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
 {
-    helper_raise_exception_err(env, exception, 0);
+    raise_exception_err(env, exception, 0, GETPC());
 }
 
 #if !defined(CONFIG_USER_ONLY)
+static void raise_exception(CPUPPCState *env, uint32_t exception, uintptr_t pc)
+{
+    raise_exception_err(env, exception, 0, pc);
+}
+
 void helper_store_msr(CPUPPCState *env, target_ulong val)
 {
     CPUState *cs;
@@ -914,7 +931,8 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
     if (val != 0) {
         cs = CPU(ppc_env_get_cpu(env));
         cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
-        helper_raise_exception(env, val);
+        /* nip is updated by generated code */
+        raise_exception(env, val, 0);
     }
 }
 
@@ -1015,8 +1033,9 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_TRAP);
+        /* nip is updated in TB */
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_TRAP, 0);
     }
 }
 
@@ -1029,8 +1048,9 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_TRAP);
+        /* nip is updated in TB */
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_TRAP, 0);
     }
 }
 #endif
target-ppc/fpu_helper.c +99 -93

652 lines not on this page · raw message

target-ppc/helper.h +1 -0
index 0526322..3d318fe 100644
@@ -1,4 +1,5 @@
 DEF_HELPER_3(raise_exception_err, void, env, i32, i32)
+DEF_HELPER_3(raise_exception_end, void, env, i32, i32)
 DEF_HELPER_2(raise_exception, void, env, i32)
 DEF_HELPER_4(tw, void, env, tl, tl, i32)
 #if defined(TARGET_PPC64)
target-ppc/mem_helper.c +3 -3
index e4de86b..7ebc412 100644
@@ -107,9 +107,9 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
         if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
                      lsw_reg_in_range(reg, num_used_regs, rb))) {
             env->nip += 4;     /* Compensate the "nip - 4" from gen_lswx() */
-            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                       POWERPC_EXCP_INVAL |
-                                       POWERPC_EXCP_INVAL_LSWX);
+            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                                POWERPC_EXCP_INVAL |
+                                POWERPC_EXCP_INVAL_LSWX, GETPC());
         } else {
             helper_lsw(env, addr, xer_bc, reg);
         }
target-ppc/misc_helper.c +4 -4
index 7d41b01..ded5941 100644
@@ -39,7 +39,7 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
 
 #ifdef TARGET_PPC64
 static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
-                               uint32_t sprn, uint32_t cause)
+                               uint32_t sprn, uint32_t cause, uintptr_t retaddr)
 {
     qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
 
@@ -47,7 +47,7 @@ static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
     cause &= FSCR_IC_MASK;
     env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
 
-    helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
+    raise_exception_err(env, POWERPC_EXCP_FU, 0, retaddr);
 }
 #endif
 
@@ -59,7 +59,7 @@ void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
         /* Facility is enabled, continue */
         return;
     }
-    raise_fu_exception(env, bit, sprn, cause);
+    raise_fu_exception(env, bit, sprn, cause, GETPC());
 #endif
 }
 
@@ -71,7 +71,7 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
         /* Facility is enabled, continue */
         return;
     }
-    raise_fu_exception(env, bit, sprn, cause);
+    raise_fu_exception(env, bit, sprn, cause, GETPC());
 #endif
 }
 
target-ppc/mmu-hash64.c +6 -6
index ea6e99a..58465d8 100644
@@ -224,8 +224,8 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
     PowerPCCPU *cpu = ppc_env_get_cpu(env);
 
     if (ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL, GETPC());
     }
 }
 
@@ -235,8 +235,8 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
     target_ulong rt = 0;
 
     if (ppc_load_slb_esid(cpu, rb, &rt) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL, GETPC());
     }
     return rt;
 }
@@ -247,8 +247,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
     target_ulong rt = 0;
 
     if (ppc_load_slb_vsid(cpu, rb, &rt) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL, GETPC());
     }
     return rt;
 }
target-ppc/mmu_helper.c +7 -11
index 1499af72..62c82bc 100644
@@ -2608,9 +2608,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
     tlb = booke206_cur_tlb(env);
 
     if (!tlb) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL |
+                            POWERPC_EXCP_INVAL_INVAL, GETPC());
     }
 
     /* check that we support the targeted size */
@@ -2618,9 +2618,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
     size_ps = booke206_tlbnps(env, tlbn);
     if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
         !(size_ps & (1 << size_tlb))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL |
+                            POWERPC_EXCP_INVAL_INVAL, GETPC());
     }
 
     if (msr_gs) {
@@ -2902,10 +2902,6 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
         ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
     }
     if (unlikely(ret != 0)) {
-        if (likely(retaddr)) {
-            /* now we have a real cpu fault */
-            cpu_restore_state(cs, retaddr);
-        }
-        helper_raise_exception_err(env, cs->exception_index, env->error_code);
+        raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
     }
 }
target-ppc/timebase_helper.c +11 -10
index 66de313..77b91f3 100644
@@ -19,6 +19,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
+#include "exec/exec-all.h"
 #include "qemu/log.h"
 
 /*****************************************************************************/
@@ -133,15 +134,15 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
 
     if (unlikely(env->dcr_env == NULL)) {
         qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL |
+                            POWERPC_EXCP_INVAL_INVAL, GETPC());
     } else if (unlikely(ppc_dcr_read(env->dcr_env,
                                      (uint32_t)dcrn, &val) != 0)) {
         qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n",
                       (uint32_t)dcrn, (uint32_t)dcrn);
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
     }
     return val;
 }
@@ -150,14 +151,14 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val)
 {
     if (unlikely(env->dcr_env == NULL)) {
         qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL |
+                            POWERPC_EXCP_INVAL_INVAL, GETPC());
     } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
                                       (uint32_t)val) != 0)) {
         qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d %03x\n",
                       (uint32_t)dcrn, (uint32_t)dcrn);
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
     }
 }
target-ppc/translate.c +6 -78

312 lines not on this page · raw message

#2 lore raw

PATCH 2/3 replay: allow replay stopping and restarting

In reply to Pavel Dovgalyuk

This patch fixes bug with stopping and restarting replay through monitor.

---
 block/blkreplay.c        |   18 +++++++++++++-----
 cpus.c                   |    1 +
 include/sysemu/replay.h  |    2 ++
 replay/replay-internal.h |    2 --
 vl.c                     |    1 +
 5 files changed, 17 insertions(+), 7 deletions(-)
block/blkreplay.c +13 -5
index 42f1813..438170c 100644
@@ -70,6 +70,14 @@ static void blkreplay_bh_cb(void *opaque)
     g_free(req);
 }
 
+static uint64_t blkreplay_next_id(void)
+{
+    if (replay_events_enabled()) {
+        return request_id++;
+    }
+    return 0;
+}
+
 static void block_request_create(uint64_t reqid, BlockDriverState *bs,
                                  Coroutine *co)
 {
@@ -84,7 +92,7 @@ static void block_request_create(uint64_t reqid, BlockDriverState *bs,
 static int coroutine_fn blkreplay_co_readv(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
 {
-    uint64_t reqid = request_id++;
+    uint64_t reqid = blkreplay_next_id();
     int ret = bdrv_co_readv(bs->file->bs, sector_num, nb_sectors, qiov);
     block_request_create(reqid, bs, qemu_coroutine_self());
     qemu_coroutine_yield();
@@ -95,7 +103,7 @@ static int coroutine_fn blkreplay_co_readv(BlockDriverState *bs,
 static int coroutine_fn blkreplay_co_writev(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
 {
-    uint64_t reqid = request_id++;
+    uint64_t reqid = blkreplay_next_id();
     int ret = bdrv_co_writev(bs->file->bs, sector_num, nb_sectors, qiov);
     block_request_create(reqid, bs, qemu_coroutine_self());
     qemu_coroutine_yield();
@@ -106,7 +114,7 @@ static int coroutine_fn blkreplay_co_writev(BlockDriverState *bs,
 static int coroutine_fn blkreplay_co_write_zeroes(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
 {
-    uint64_t reqid = request_id++;
+    uint64_t reqid = blkreplay_next_id();
     int ret = bdrv_co_write_zeroes(bs->file->bs, sector_num, nb_sectors, flags);
     block_request_create(reqid, bs, qemu_coroutine_self());
     qemu_coroutine_yield();
@@ -117,7 +125,7 @@ static int coroutine_fn blkreplay_co_write_zeroes(BlockDriverState *bs,
 static int coroutine_fn blkreplay_co_discard(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors)
 {
-    uint64_t reqid = request_id++;
+    uint64_t reqid = blkreplay_next_id();
     int ret = bdrv_co_discard(bs->file->bs, sector_num, nb_sectors);
     block_request_create(reqid, bs, qemu_coroutine_self());
     qemu_coroutine_yield();
@@ -127,7 +135,7 @@ static int coroutine_fn blkreplay_co_discard(BlockDriverState *bs,
 
 static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
 {
-    uint64_t reqid = request_id++;
+    uint64_t reqid = blkreplay_next_id();
     int ret = bdrv_co_flush(bs->file->bs);
     block_request_create(reqid, bs, qemu_coroutine_self());
     qemu_coroutine_yield();
cpus.c +1 -0
index 326742f..34f951f 100644
@@ -742,6 +742,7 @@ static int do_vm_stop(RunState state)
         runstate_set(state);
         vm_state_notify(0, state);
         qapi_event_send_stop(&error_abort);
+        replay_disable_events();
     }
 
     bdrv_drain_all();
include/sysemu/replay.h +2 -0
index 0a88393..52430d3 100644
@@ -105,6 +105,8 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint);
 
 /*! Disables storing events in the queue */
 void replay_disable_events(void);
+/*! Enables storing events in the queue */
+void replay_enable_events(void);
 /*! Returns true when saving events is enabled */
 bool replay_events_enabled(void);
 /*! Adds bottom half event to the queue */
replay/replay-internal.h +0 -2
index efbf14c..310c4b7 100644
@@ -119,8 +119,6 @@ void replay_read_next_clock(unsigned int kind);
 void replay_init_events(void);
 /*! Clears internal data structures for events handling */
 void replay_finish_events(void);
-/*! Enables storing events in the queue */
-void replay_enable_events(void);
 /*! Flushes events queue */
 void replay_flush_events(void);
 /*! Clears events list before loading new VM state */
vl.c +1 -0
index 2f74fe8..b361ca8 100644
@@ -765,6 +765,7 @@ void vm_start(void)
     if (runstate_is_running()) {
         qapi_event_send_stop(&error_abort);
     } else {
+        replay_enable_events();
         cpu_enable_ticks();
         runstate_set(RUN_STATE_RUNNING);
         vm_state_notify(1, RUN_STATE_RUNNING);
#3 lore raw

Re: [Qemu-devel] [PATCH 2/3] replay: allow replay stopping and restarting

----- Original Message -----

Quoted 23 lines

From: "Pavel Dovgalyuk" <[email protected]>
To: [email protected]
Cc: [email protected], [email protected], [email protected], [email protected]
Sent: Wednesday, June 8, 2016 7:14:04 AM
Subject: [PATCH 2/3] replay: allow replay stopping and restarting

This patch fixes bug with stopping and restarting replay through monitor.

---
 block/blkreplay.c        |   18 +++++++++++++-----
 cpus.c                   |    1 +
 include/sysemu/replay.h  |    2 ++
 replay/replay-internal.h |    2 --
 vl.c                     |    1 +
 5 files changed, 17 insertions(+), 7 deletions(-)
block/blkreplay.c +0 -0
index 42f1813..438170c 100644

block/blkreplay.c static void blkreplay_bh_cb(void *opaque) · line 79

Quoted 10 lines
block/blkreplay.c +7 -0
@@ -70,6 +70,14 @@ static void blkreplay_bh_cb(void *opaque)
     g_free(req);
 }
 
+static uint64_t blkreplay_next_id(void)
+{
+    if (replay_events_enabled()) {
+        return request_id++;
+    }
+    return 0;
+}

What happens if 0 is returned? I think that you want to call replay_disable_events...

block/blkreplay.c static void blkreplay_bh_cb(void *opaque) · line 80

Quoted 1 line
block/blkreplay.c +0 -0
     bdrv_drain_all();

... after this bdrv_drain_all.

I was going to suggest using qemu_add_vm_change_state_handler in replay_start (which could have replaced the existing call to replay_enable_events), but that's not possible if you have to do your calls after bdrv_drain_all.

Thanks,

Paolo

#4 lore raw

Re: [Qemu-devel] [PATCH 2/3] replay: allow replay stopping and restarting

Quoted 22 lines

From: Paolo Bonzini [mailto:[email protected]]

Quoted 21 lines

From: "Pavel Dovgalyuk" <[email protected]> This patch fixes bug with stopping and restarting replay through monitor.

---
 block/blkreplay.c        |   18 +++++++++++++-----
 cpus.c                   |    1 +
 include/sysemu/replay.h  |    2 ++
 replay/replay-internal.h |    2 --
 vl.c                     |    1 +
 5 files changed, 17 insertions(+), 7 deletions(-)
block/blkreplay.c +0 -0
index 42f1813..438170c 100644
@@ -70,6 +70,14 @@ static void blkreplay_bh_cb(void *opaque)
     g_free(req);
 }
 
Quoted 9 lines

block/blkreplay.c static void blkreplay_bh_cb(void *opaque) · line 79

Quoted 7 lines
block/blkreplay.c +7 -0
+static uint64_t blkreplay_next_id(void)
+{
+    if (replay_events_enabled()) {
+        return request_id++;
+    }
+    return 0;
+}

What happens if 0 is returned?

It could be any value. When replay events are disables, it means that either replay is disabled or execution is stopped. In first case we won't pass this requests through the replay queue and therefore id is useless.
In stopped mode we have to keep request_id unchanged to make record/replay deterministic.

Quoted 6 lines

I think that you want to call
replay_disable_events...

block/blkreplay.c static void blkreplay_bh_cb(void *opaque) · line 80

Quoted 1 line
block/blkreplay.c +0 -0
     bdrv_drain_all();

... after this bdrv_drain_all.

Why? We disable replay events to avoid adding new block requests to the queue. How this is related to drain all?

Quoted 5 lines

I was going to suggest using qemu_add_vm_change_state_handler in replay_start (which could have replaced the existing call to replay_enable_events), but that's not possible if you have to do your calls after bdrv_drain_all.

Pavel Dovgalyuk

#5 lore raw

Re: [Qemu-devel] [PATCH 2/3] replay: allow replay stopping and restarting

Ping?

Pavel Dovgalyuk

Quoted 63 lines

-----Original Message-----
From: Pavel Dovgalyuk [mailto:[email protected]]
Sent: Monday, June 20, 2016 9:27 AM
To: 'Paolo Bonzini'; 'Pavel Dovgalyuk'
Cc: [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH 2/3] replay: allow replay stopping and restarting

Quoted 22 lines

From: Paolo Bonzini [mailto:[email protected]]

Quoted 21 lines

From: "Pavel Dovgalyuk" <[email protected]> This patch fixes bug with stopping and restarting replay through monitor.

---
 block/blkreplay.c        |   18 +++++++++++++-----
 cpus.c                   |    1 +
 include/sysemu/replay.h  |    2 ++
 replay/replay-internal.h |    2 --
 vl.c                     |    1 +
 5 files changed, 17 insertions(+), 7 deletions(-)
block/blkreplay.c +0 -0
index 42f1813..438170c 100644
@@ -70,6 +70,14 @@ static void blkreplay_bh_cb(void *opaque)
     g_free(req);
 }
 
Quoted 9 lines

block/blkreplay.c static void blkreplay_bh_cb(void *opaque) · line 79

Quoted 7 lines
block/blkreplay.c +7 -0
+static uint64_t blkreplay_next_id(void)
+{
+    if (replay_events_enabled()) {
+        return request_id++;
+    }
+    return 0;
+}

What happens if 0 is returned?

It could be any value. When replay events are disables, it means that either replay is disabled or execution is stopped. In first case we won't pass this requests through the replay queue and therefore id is useless.
In stopped mode we have to keep request_id unchanged to make record/replay deterministic.

Quoted 6 lines

I think that you want to call
replay_disable_events...

block/blkreplay.c static void blkreplay_bh_cb(void *opaque) · line 80

Quoted 1 line
block/blkreplay.c +0 -0
     bdrv_drain_all();

... after this bdrv_drain_all.

Why? We disable replay events to avoid adding new block requests to the queue. How this is related to drain all?

Quoted 5 lines

I was going to suggest using qemu_add_vm_change_state_handler in replay_start (which could have replaced the existing call to replay_enable_events), but that's not possible if you have to do your calls after bdrv_drain_all.

Pavel Dovgalyuk

#6 lore raw

Re: [Qemu-devel] [PATCH 2/3] replay: allow replay stopping and restarting

In reply to Pavel Dovgalyuk
Quoted 42 lines · Pavel Dovgalyuk
Quoted 22 lines

From: Paolo Bonzini [mailto:[email protected]]

Quoted 21 lines

From: "Pavel Dovgalyuk" <[email protected]> This patch fixes bug with stopping and restarting replay through monitor.

---
 block/blkreplay.c        |   18 +++++++++++++-----
 cpus.c                   |    1 +
 include/sysemu/replay.h  |    2 ++
 replay/replay-internal.h |    2 --
 vl.c                     |    1 +
 5 files changed, 17 insertions(+), 7 deletions(-)
block/blkreplay.c +0 -0
index 42f1813..438170c 100644
@@ -70,6 +70,14 @@ static void blkreplay_bh_cb(void *opaque)
     g_free(req);
 }
 
Quoted 9 lines

block/blkreplay.c static void blkreplay_bh_cb(void *opaque) · line 79

Quoted 7 lines
block/blkreplay.c +7 -0
+static uint64_t blkreplay_next_id(void)
+{
+    if (replay_events_enabled()) {
+        return request_id++;
+    }
+    return 0;
+}

What happens if 0 is returned?

It could be any value. When replay events are disables, it means that either replay is disabled or execution is stopped. In first case we won't pass this requests through the replay queue and therefore id is useless.
In stopped mode we have to keep request_id unchanged to make record/replay deterministic.

Quoted 3 lines

I think that you want to call
replay_disable_events...

Quoted 6 lines
Quoted 3 lines

block/blkreplay.c static void blkreplay_bh_cb(void *opaque) · line 80

Quoted 1 line
block/blkreplay.c +0 -0
     bdrv_drain_all();

... after this bdrv_drain_all.

Why? We disable replay events to avoid adding new block requests to the queue. How this is related to drain all?

drain all completes the guest's pending requests. If you disable events before drain all, doesn't that cause a mismatch between record and replay?

Quoted 10 lines
Quoted 5 lines

I was going to suggest using qemu_add_vm_change_state_handler in replay_start (which could have replaced the existing call to replay_enable_events), but that's not possible if you have to do your calls after bdrv_drain_all.

Pavel Dovgalyuk

#7 lore raw

Re: [Qemu-devel] [PATCH 2/3] replay: allow replay stopping and restarting

Quoted 15 lines

From: Paolo Bonzini [mailto:[email protected]] On Behalf Of Paolo Bonzini

Quoted 13 lines · Pavel Dovgalyuk
Quoted 13 lines

From: Paolo Bonzini [mailto:[email protected]]

Quoted 6 lines

From: "Pavel Dovgalyuk" <[email protected]> This patch fixes bug with stopping and restarting replay through monitor.

---

I think that you want to call
replay_disable_events...

Quoted 1 line
     bdrv_drain_all();
Quoted 7 lines
Quoted 4 lines
Quoted 1 line

... after this bdrv_drain_all.

Why? We disable replay events to avoid adding new block requests to the queue. How this is related to drain all?

drain all completes the guest's pending requests. If you disable events before drain all, doesn't that cause a mismatch between record and replay?

Looks reasonable, thanks. I'll update the patch.
What about replay patch for networking?

Pavel Dovgalyuk

#8 lore raw

PATCH 3/3 record/replay: add network support

In reply to Pavel Dovgalyuk

This patch adds support of recording and replaying network packets in irount rr mode.

Record and replay for network interactions is performed with the network filter. Each backend must have its own instance of the replay filter as follows:
-netdev user,id=net1 -device rtl8139,netdev=net1
-object filter-replay,id=replay,netdev=net1

Replay network filter is used to record and replay network packets. While recording the virtual machine this filter puts all packets coming from the outer world into the log. In replay mode packets from the log are injected into the network device. All interactions with network backend in replay mode are disabled.

---
 docs/replay.txt          |   14 ++++++
 include/sysemu/replay.h  |   12 +++++
 net/Makefile.objs        |    1 
 net/filter-replay.c      |   90 ++++++++++++++++++++++++++++++++++++++
 replay/Makefile.objs     |    1 
 replay/replay-events.c   |   11 +++++
 replay/replay-internal.h |   10 ++++
 replay/replay-net.c      |  110 ++++++++++++++++++++++++++++++++++++++++++++++
 replay/replay.c          |    2 -
 vl.c                     |    3 +
 10 files changed, 252 insertions(+), 2 deletions(-)
 create mode 100644 net/filter-replay.c
 create mode 100644 replay/replay-net.c
docs/replay.txt +14 -0
index 779c6c0..347b2ff 100644
@@ -195,3 +195,17 @@ Queue is flushed at checkpoints and information about processed requests
 is recorded to the log. In replay phase the queue is matched with
 events read from the log. Therefore block devices requests are processed
 deterministically.
+
+Network devices
+---------------
+
+Record and replay for network interactions is performed with the network filter.
+Each backend must have its own instance of the replay filter as follows:
+ -netdev user,id=net1 -device rtl8139,netdev=net1
+ -object filter-replay,id=replay,netdev=net1
+
+Replay network filter is used to record and replay network packets. While
+recording the virtual machine this filter puts all packets coming from
+the outer world into the log. In replay mode packets from the log are
+injected into the network device. All interactions with network backend
+in replay mode are disabled.
include/sysemu/replay.h +12 -0
index 52430d3..fa61aae 100644
@@ -39,6 +39,8 @@ enum ReplayCheckpoint {
 };
 typedef enum ReplayCheckpoint ReplayCheckpoint;
 
+typedef struct ReplayNetState ReplayNetState;
+
 extern ReplayMode replay_mode;
 
 /* Replay process control functions */
@@ -135,4 +137,14 @@ void replay_char_read_all_save_error(int res);
 /*! Writes character read_all execution result into the replay log. */
 void replay_char_read_all_save_buf(uint8_t *buf, int offset);
 
+/* Network */
+
+/*! Registers replay network filter attached to some backend. */
+ReplayNetState *replay_register_net(NetFilterState *nfs);
+/*! Unregisters replay network filter. */
+void replay_unregister_net(ReplayNetState *rns);
+/*! Called to write network packet to the replay log. */
+void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
+                             const struct iovec *iov, int iovcnt);
+
 #endif
net/Makefile.objs +1 -0
index b7c22fd..f787ba4 100644
@@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o
 common-obj-y += filter.o
 common-obj-y += filter-buffer.o
 common-obj-y += filter-mirror.o
+common-obj-y += filter-replay.o
net/filter-replay.c new file +90 -0

90 lines not on this page · raw message

replay/Makefile.objs +1 -0
index fcb3f74..f55a6b5 100644
@@ -4,3 +4,4 @@ common-obj-y += replay-events.o
 common-obj-y += replay-time.o
 common-obj-y += replay-input.o
 common-obj-y += replay-char.o
+common-obj-y += replay-net.o
replay/replay-events.c +11 -0
index 3807245..9ce9e51 100644
@@ -54,6 +54,9 @@ static void replay_run_event(Event *event)
     case REPLAY_ASYNC_EVENT_BLOCK:
         aio_bh_call(event->opaque);
         break;
+    case REPLAY_ASYNC_EVENT_NET:
+        replay_event_net_run(event->opaque);
+        break;
     default:
         error_report("Replay: invalid async event ID (%d) in the queue",
                     event->event_kind);
@@ -189,6 +192,9 @@ static void replay_save_event(Event *event, int checkpoint)
         case REPLAY_ASYNC_EVENT_BLOCK:
             replay_put_qword(event->id);
             break;
+        case REPLAY_ASYNC_EVENT_NET:
+            replay_event_net_save(event->opaque);
+            break;
         default:
             error_report("Unknown ID %" PRId64 " of replay event", event->id);
             exit(1);
@@ -252,6 +258,11 @@ static Event *replay_read_event(int checkpoint)
             read_id = replay_get_qword();
         }
         break;
+    case REPLAY_ASYNC_EVENT_NET:
+        event = g_malloc0(sizeof(Event));
+        event->event_kind = read_event_kind;
+        event->opaque = replay_event_net_load();
+        return event;
     default:
         error_report("Unknown ID %d of replay event", read_event_kind);
         exit(1);
replay/replay-internal.h +10 -0
index 310c4b7..f41ffc7 100644
@@ -50,6 +50,7 @@ enum ReplayAsyncEventKind {
     REPLAY_ASYNC_EVENT_INPUT_SYNC,
     REPLAY_ASYNC_EVENT_CHAR_READ,
     REPLAY_ASYNC_EVENT_BLOCK,
+    REPLAY_ASYNC_EVENT_NET,
     REPLAY_ASYNC_COUNT
 };
 
@@ -153,4 +154,13 @@ void replay_event_char_read_save(void *opaque);
 /*! Reads char event read from the file. */
 void *replay_event_char_read_load(void);
 
+/* Network devices */
+
+/*! Called to run network event. */
+void replay_event_net_run(void *opaque);
+/*! Writes network event to the file. */
+void replay_event_net_save(void *opaque);
+/*! Reads network from the file. */
+void *replay_event_net_load(void);
+
 #endif
replay/replay-net.c new file +110 -0

110 lines not on this page · raw message

replay/replay.c +1 -1
index 167fd29..e040f6f 100644
@@ -21,7 +21,7 @@
 
 /* Current version of the replay mechanism.
    Increase it when file format changes. */
-#define REPLAY_VERSION              0xe02004
+#define REPLAY_VERSION              0xe02005
 /* Size of replay log header */
 #define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
 
vl.c +2 -1
index b361ca8..d1457e9 100644
@@ -2830,7 +2830,8 @@ static bool object_create_initial(const char *type)
     if (g_str_equal(type, "filter-buffer") ||
         g_str_equal(type, "filter-dump") ||
         g_str_equal(type, "filter-mirror") ||
-        g_str_equal(type, "filter-redirector")) {
+        g_str_equal(type, "filter-redirector") ||
+        g_str_equal(type, "filter-replay")) {
         return false;
     }