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

replay: synchronize on every virtual timer callback

Sometimes virtual timer callbacks depend on order
of virtual timer processing and warping of virtual clock.
Therefore every callback should be logged to make replay deterministic.
This patch creates a checkpoint before every virtual timer callback.
With these checkpoints virtual timers processing and clock warping
events order is completely deterministic.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
Acked-by: Alex Bennée <alex.bennee@linaro.org>

--

v2:
- remove mutex lock/unlock for virtual clock checkpoint since it is
not process any asynchronous events (commit ca9759c2a92f528f256fef0e3922416f7bb47bf9)
- bump record/replay log file version
Message-Id: <159012932716.27256.8854065545365559921.stgit@pasha-ThinkPad-X280>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Pavel Dovgalyuk and committed by
Paolo Bonzini
677a3bab 255ae6e2

+10 -24
+1 -1
replay/replay.c
··· 22 22 23 23 /* Current version of the replay mechanism. 24 24 Increase it when file format changes. */ 25 - #define REPLAY_VERSION 0xe02009 25 + #define REPLAY_VERSION 0xe0200a 26 26 /* Size of replay log header */ 27 27 #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) 28 28
+9 -23
util/qemu-timer.c
··· 501 501 bool progress = false; 502 502 QEMUTimerCB *cb; 503 503 void *opaque; 504 - bool need_replay_checkpoint = false; 505 504 506 505 if (!atomic_read(&timer_list->active_timers)) { 507 506 return false; ··· 517 516 break; 518 517 default: 519 518 case QEMU_CLOCK_VIRTUAL: 520 - if (replay_mode != REPLAY_MODE_NONE) { 521 - /* Checkpoint for virtual clock is redundant in cases where 522 - * it's being triggered with only non-EXTERNAL timers, because 523 - * these timers don't change guest state directly. 524 - * Since it has conditional dependence on specific timers, it is 525 - * subject to race conditions and requires special handling. 526 - * See below. 527 - */ 528 - need_replay_checkpoint = true; 529 - } 530 519 break; 531 520 case QEMU_CLOCK_HOST: 532 521 if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) { ··· 559 548 */ 560 549 break; 561 550 } 562 - if (need_replay_checkpoint 563 - && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)) { 564 - /* once we got here, checkpoint clock only once */ 565 - need_replay_checkpoint = false; 551 + /* Checkpoint for virtual clock is redundant in cases where 552 + * it's being triggered with only non-EXTERNAL timers, because 553 + * these timers don't change guest state directly. 554 + */ 555 + if (replay_mode != REPLAY_MODE_NONE 556 + && timer_list->clock->type == QEMU_CLOCK_VIRTUAL 557 + && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL) 558 + && !replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { 566 559 qemu_mutex_unlock(&timer_list->active_timers_lock); 567 - if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { 568 - goto out; 569 - } 570 - qemu_mutex_lock(&timer_list->active_timers_lock); 571 - /* The lock was released; start over again in case the list was 572 - * modified. 573 - */ 574 - continue; 560 + goto out; 575 561 } 576 562 577 563 /* remove timer from the list before calling the callback */