31
31
/* Default guest test virtual memory offset */
32
32
#define DEFAULT_GUEST_TEST_MEM 0xc0000000
33
33
34
- /* How many pages to dirty for each guest loop */
35
- #define TEST_PAGES_PER_LOOP 1024
36
-
37
34
/* How many host loops to run (one KVM_GET_DIRTY_LOG for each loop) */
38
35
#define TEST_HOST_LOOP_N 32UL
39
36
@@ -75,6 +72,7 @@ static uint64_t host_page_size;
75
72
static uint64_t guest_page_size ;
76
73
static uint64_t guest_num_pages ;
77
74
static uint64_t iteration ;
75
+ static bool vcpu_stop ;
78
76
79
77
/*
80
78
* Guest physical memory offset of the testing memory slot.
@@ -96,9 +94,10 @@ static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM;
96
94
static void guest_code (void )
97
95
{
98
96
uint64_t addr ;
99
- int i ;
100
97
101
98
#ifdef __s390x__
99
+ uint64_t i ;
100
+
102
101
/*
103
102
* On s390x, all pages of a 1M segment are initially marked as dirty
104
103
* when a page of the segment is written to for the very first time.
@@ -112,7 +111,7 @@ static void guest_code(void)
112
111
#endif
113
112
114
113
while (true) {
115
- for ( i = 0 ; i < TEST_PAGES_PER_LOOP ; i ++ ) {
114
+ while (! READ_ONCE ( vcpu_stop ) ) {
116
115
addr = guest_test_virt_mem ;
117
116
addr += (guest_random_u64 (& guest_rng ) % guest_num_pages )
118
117
* guest_page_size ;
@@ -140,14 +139,7 @@ static uint64_t host_track_next_count;
140
139
/* Whether dirty ring reset is requested, or finished */
141
140
static sem_t sem_vcpu_stop ;
142
141
static sem_t sem_vcpu_cont ;
143
- /*
144
- * This is only set by main thread, and only cleared by vcpu thread. It is
145
- * used to request vcpu thread to stop at the next GUEST_SYNC, since GUEST_SYNC
146
- * is the only place that we'll guarantee both "dirty bit" and "dirty data"
147
- * will match. E.g., SIG_IPI won't guarantee that if the vcpu is interrupted
148
- * after setting dirty bit but before the data is written.
149
- */
150
- static atomic_t vcpu_sync_stop_requested ;
142
+
151
143
/*
152
144
* This is updated by the vcpu thread to tell the host whether it's a
153
145
* ring-full event. It should only be read until a sem_wait() of
@@ -272,9 +264,7 @@ static void clear_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot,
272
264
/* Should only be called after a GUEST_SYNC */
273
265
static void vcpu_handle_sync_stop (void )
274
266
{
275
- if (atomic_read (& vcpu_sync_stop_requested )) {
276
- /* It means main thread is sleeping waiting */
277
- atomic_set (& vcpu_sync_stop_requested , false);
267
+ if (READ_ONCE (vcpu_stop )) {
278
268
sem_post (& sem_vcpu_stop );
279
269
sem_wait (& sem_vcpu_cont );
280
270
}
@@ -801,20 +791,31 @@ static void run_test(enum vm_guest_mode mode, void *arg)
801
791
}
802
792
803
793
/*
804
- * See vcpu_sync_stop_requested definition for details on why
805
- * we need to stop vcpu when verify data.
794
+ * Stop the vCPU prior to collecting and verifying the dirty
795
+ * log. If the vCPU is allowed to run during collection, then
796
+ * pages that are written during this iteration may be missed,
797
+ * i.e. collected in the next iteration. And if the vCPU is
798
+ * writing memory during verification, pages that this thread
799
+ * sees as clean may be written with this iteration's value.
806
800
*/
807
- atomic_set (& vcpu_sync_stop_requested , true);
801
+ WRITE_ONCE (vcpu_stop , true);
802
+ sync_global_to_guest (vm , vcpu_stop );
808
803
sem_wait (& sem_vcpu_stop );
804
+
805
+ /*
806
+ * Clear vcpu_stop after the vCPU thread has acknowledge the
807
+ * stop request and is waiting, i.e. is definitely not running!
808
+ */
809
+ WRITE_ONCE (vcpu_stop , false);
810
+ sync_global_to_guest (vm , vcpu_stop );
811
+
809
812
/*
810
813
* NOTE: for dirty ring, it's possible that we didn't stop at
811
814
* GUEST_SYNC but instead we stopped because ring is full;
812
815
* that's okay too because ring full means we're only missing
813
816
* the flush of the last page, and since we handle the last
814
817
* page specially verification will succeed anyway.
815
818
*/
816
- assert (host_log_mode == LOG_MODE_DIRTY_RING ||
817
- atomic_read (& vcpu_sync_stop_requested ) == false);
818
819
vm_dirty_log_verify (mode , bmap );
819
820
820
821
/*
0 commit comments