@@ -164,14 +164,28 @@ static void kvm_apic_map_free(struct rcu_head *rcu)
164
164
kvfree (map );
165
165
}
166
166
167
- static void recalculate_apic_map (struct kvm * kvm )
167
+ void kvm_recalculate_apic_map (struct kvm * kvm )
168
168
{
169
169
struct kvm_apic_map * new , * old = NULL ;
170
170
struct kvm_vcpu * vcpu ;
171
171
int i ;
172
172
u32 max_id = 255 ; /* enough space for any xAPIC ID */
173
173
174
+ if (!kvm -> arch .apic_map_dirty ) {
175
+ /*
176
+ * Read kvm->arch.apic_map_dirty before
177
+ * kvm->arch.apic_map
178
+ */
179
+ smp_rmb ();
180
+ return ;
181
+ }
182
+
174
183
mutex_lock (& kvm -> arch .apic_map_lock );
184
+ if (!kvm -> arch .apic_map_dirty ) {
185
+ /* Someone else has updated the map. */
186
+ mutex_unlock (& kvm -> arch .apic_map_lock );
187
+ return ;
188
+ }
175
189
176
190
kvm_for_each_vcpu (i , vcpu , kvm )
177
191
if (kvm_apic_present (vcpu ))
@@ -236,6 +250,12 @@ static void recalculate_apic_map(struct kvm *kvm)
236
250
old = rcu_dereference_protected (kvm -> arch .apic_map ,
237
251
lockdep_is_held (& kvm -> arch .apic_map_lock ));
238
252
rcu_assign_pointer (kvm -> arch .apic_map , new );
253
+ /*
254
+ * Write kvm->arch.apic_map before
255
+ * clearing apic->apic_map_dirty
256
+ */
257
+ smp_wmb ();
258
+ kvm -> arch .apic_map_dirty = false;
239
259
mutex_unlock (& kvm -> arch .apic_map_lock );
240
260
241
261
if (old )
@@ -257,20 +277,20 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
257
277
else
258
278
static_key_slow_inc (& apic_sw_disabled .key );
259
279
260
- recalculate_apic_map ( apic -> vcpu -> kvm ) ;
280
+ apic -> vcpu -> kvm -> arch . apic_map_dirty = true ;
261
281
}
262
282
}
263
283
264
284
static inline void kvm_apic_set_xapic_id (struct kvm_lapic * apic , u8 id )
265
285
{
266
286
kvm_lapic_set_reg (apic , APIC_ID , id << 24 );
267
- recalculate_apic_map ( apic -> vcpu -> kvm ) ;
287
+ apic -> vcpu -> kvm -> arch . apic_map_dirty = true ;
268
288
}
269
289
270
290
static inline void kvm_apic_set_ldr (struct kvm_lapic * apic , u32 id )
271
291
{
272
292
kvm_lapic_set_reg (apic , APIC_LDR , id );
273
- recalculate_apic_map ( apic -> vcpu -> kvm ) ;
293
+ apic -> vcpu -> kvm -> arch . apic_map_dirty = true ;
274
294
}
275
295
276
296
static inline u32 kvm_apic_calc_x2apic_ldr (u32 id )
@@ -286,7 +306,7 @@ static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u32 id)
286
306
287
307
kvm_lapic_set_reg (apic , APIC_ID , id );
288
308
kvm_lapic_set_reg (apic , APIC_LDR , ldr );
289
- recalculate_apic_map ( apic -> vcpu -> kvm ) ;
309
+ apic -> vcpu -> kvm -> arch . apic_map_dirty = true ;
290
310
}
291
311
292
312
static inline int apic_lvt_enabled (struct kvm_lapic * apic , int lvt_type )
@@ -1906,7 +1926,7 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
1906
1926
case APIC_DFR :
1907
1927
if (!apic_x2apic_mode (apic )) {
1908
1928
kvm_lapic_set_reg (apic , APIC_DFR , val | 0x0FFFFFFF );
1909
- recalculate_apic_map ( apic -> vcpu -> kvm ) ;
1929
+ apic -> vcpu -> kvm -> arch . apic_map_dirty = true ;
1910
1930
} else
1911
1931
ret = 1 ;
1912
1932
break ;
@@ -2012,6 +2032,8 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
2012
2032
break ;
2013
2033
}
2014
2034
2035
+ kvm_recalculate_apic_map (apic -> vcpu -> kvm );
2036
+
2015
2037
return ret ;
2016
2038
}
2017
2039
EXPORT_SYMBOL_GPL (kvm_lapic_reg_write );
@@ -2160,7 +2182,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
2160
2182
static_key_slow_dec_deferred (& apic_hw_disabled );
2161
2183
} else {
2162
2184
static_key_slow_inc (& apic_hw_disabled .key );
2163
- recalculate_apic_map ( vcpu -> kvm ) ;
2185
+ vcpu -> kvm -> arch . apic_map_dirty = true ;
2164
2186
}
2165
2187
}
2166
2188
@@ -2201,6 +2223,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
2201
2223
if (!apic )
2202
2224
return ;
2203
2225
2226
+ vcpu -> kvm -> arch .apic_map_dirty = false;
2204
2227
/* Stop the timer in case it's a reset to an active apic */
2205
2228
hrtimer_cancel (& apic -> lapic_timer .timer );
2206
2229
@@ -2252,6 +2275,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
2252
2275
2253
2276
vcpu -> arch .apic_arb_prio = 0 ;
2254
2277
vcpu -> arch .apic_attention = 0 ;
2278
+
2279
+ kvm_recalculate_apic_map (vcpu -> kvm );
2255
2280
}
2256
2281
2257
2282
/*
@@ -2473,17 +2498,18 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
2473
2498
struct kvm_lapic * apic = vcpu -> arch .apic ;
2474
2499
int r ;
2475
2500
2476
-
2477
2501
kvm_lapic_set_base (vcpu , vcpu -> arch .apic_base );
2478
2502
/* set SPIV separately to get count of SW disabled APICs right */
2479
2503
apic_set_spiv (apic , * ((u32 * )(s -> regs + APIC_SPIV )));
2480
2504
2481
2505
r = kvm_apic_state_fixup (vcpu , s , true);
2482
- if (r )
2506
+ if (r ) {
2507
+ kvm_recalculate_apic_map (vcpu -> kvm );
2483
2508
return r ;
2509
+ }
2484
2510
memcpy (vcpu -> arch .apic -> regs , s -> regs , sizeof (* s ));
2485
2511
2486
- recalculate_apic_map (vcpu -> kvm );
2512
+ kvm_recalculate_apic_map (vcpu -> kvm );
2487
2513
kvm_apic_set_version (vcpu );
2488
2514
2489
2515
apic_update_ppr (apic );
0 commit comments