icount/replay additions
Subsystems (2)
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
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 2/3 replay: allow replay stopping and restarting
In reply to Pavel DovgalyukThis 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 );
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 restartingThis patch fixes bug with stopping and restarting replay through monitor.
Signed-off-by Pavel Dovgalyuk <[email protected]>--- 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
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
-0bdrv_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
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.
Signed-off-by Pavel Dovgalyuk <[email protected]>--- 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@@ -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
-0bdrv_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_handlerinreplay_start(which could have replaced the existing call toreplay_enable_events), but that's not possible if you have to do your calls afterbdrv_drain_all.
Pavel Dovgalyuk
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 restartingQuoted 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.
Signed-off-by Pavel Dovgalyuk <[email protected]>--- 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@@ -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 keeprequest_idunchanged 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
-0bdrv_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_handlerinreplay_start(which could have replaced the existing call toreplay_enable_events), but that's not possible if you have to do your calls afterbdrv_drain_all.Pavel Dovgalyuk
Re: [Qemu-devel] [PATCH 2/3] replay: allow replay stopping and restarting
In reply to Pavel DovgalyukQuoted 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.
Signed-off-by Pavel Dovgalyuk <[email protected]>--- 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@@ -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 keeprequest_idunchanged 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
-0bdrv_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_handlerinreplay_start(which could have replaced the existing call toreplay_enable_events), but that's not possible if you have to do your calls afterbdrv_drain_all.Pavel Dovgalyuk
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.
Signed-off-by Pavel Dovgalyuk <[email protected]>---
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
PATCH 3/3 record/replay: add network support
In reply to Pavel DovgalyukThis 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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; }