@@ -1192,35 +1192,6 @@ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range,
11921192 return flush ;
11931193}
11941194
1195- typedef bool (* tdp_handler_t )(struct kvm * kvm , struct tdp_iter * iter ,
1196- struct kvm_gfn_range * range );
1197-
1198- static __always_inline bool kvm_tdp_mmu_handle_gfn (struct kvm * kvm ,
1199- struct kvm_gfn_range * range ,
1200- tdp_handler_t handler )
1201- {
1202- struct kvm_mmu_page * root ;
1203- struct tdp_iter iter ;
1204- bool ret = false;
1205-
1206- /*
1207- * Don't support rescheduling, none of the MMU notifiers that funnel
1208- * into this helper allow blocking; it'd be dead, wasteful code. Note,
1209- * this helper must NOT be used to unmap GFNs, as it processes only
1210- * valid roots!
1211- */
1212- for_each_valid_tdp_mmu_root (kvm , root , range -> slot -> as_id ) {
1213- rcu_read_lock ();
1214-
1215- tdp_root_for_each_leaf_pte (iter , root , range -> start , range -> end )
1216- ret |= handler (kvm , & iter , range );
1217-
1218- rcu_read_unlock ();
1219- }
1220-
1221- return ret ;
1222- }
1223-
12241195/*
12251196 * Mark the SPTEs range of GFNs [start, end) unaccessed and return non-zero
12261197 * if any of the GFNs in the range have been accessed.
@@ -1229,15 +1200,10 @@ static __always_inline bool kvm_tdp_mmu_handle_gfn(struct kvm *kvm,
12291200 * from the clear_young() or clear_flush_young() notifier, which uses the
12301201 * return value to determine if the page has been accessed.
12311202 */
1232- static bool age_gfn_range (struct kvm * kvm , struct tdp_iter * iter ,
1233- struct kvm_gfn_range * range )
1203+ static void kvm_tdp_mmu_age_spte (struct tdp_iter * iter )
12341204{
12351205 u64 new_spte ;
12361206
1237- /* If we have a non-accessed entry we don't need to change the pte. */
1238- if (!is_accessed_spte (iter -> old_spte ))
1239- return false;
1240-
12411207 if (spte_ad_enabled (iter -> old_spte )) {
12421208 iter -> old_spte = tdp_mmu_clear_spte_bits (iter -> sptep ,
12431209 iter -> old_spte ,
@@ -1253,23 +1219,48 @@ static bool age_gfn_range(struct kvm *kvm, struct tdp_iter *iter,
12531219
12541220 trace_kvm_tdp_mmu_spte_changed (iter -> as_id , iter -> gfn , iter -> level ,
12551221 iter -> old_spte , new_spte );
1256- return true;
12571222}
12581223
1259- bool kvm_tdp_mmu_age_gfn_range (struct kvm * kvm , struct kvm_gfn_range * range )
1224+ static bool __kvm_tdp_mmu_age_gfn_range (struct kvm * kvm ,
1225+ struct kvm_gfn_range * range ,
1226+ bool test_only )
12601227{
1261- return kvm_tdp_mmu_handle_gfn (kvm , range , age_gfn_range );
1228+ struct kvm_mmu_page * root ;
1229+ struct tdp_iter iter ;
1230+ bool ret = false;
1231+
1232+ /*
1233+ * Don't support rescheduling, none of the MMU notifiers that funnel
1234+ * into this helper allow blocking; it'd be dead, wasteful code. Note,
1235+ * this helper must NOT be used to unmap GFNs, as it processes only
1236+ * valid roots!
1237+ */
1238+ for_each_valid_tdp_mmu_root (kvm , root , range -> slot -> as_id ) {
1239+ guard (rcu )();
1240+
1241+ tdp_root_for_each_leaf_pte (iter , root , range -> start , range -> end ) {
1242+ if (!is_accessed_spte (iter .old_spte ))
1243+ continue ;
1244+
1245+ if (test_only )
1246+ return true;
1247+
1248+ ret = true;
1249+ kvm_tdp_mmu_age_spte (& iter );
1250+ }
1251+ }
1252+
1253+ return ret ;
12621254}
12631255
1264- static bool test_age_gfn (struct kvm * kvm , struct tdp_iter * iter ,
1265- struct kvm_gfn_range * range )
1256+ bool kvm_tdp_mmu_age_gfn_range (struct kvm * kvm , struct kvm_gfn_range * range )
12661257{
1267- return is_accessed_spte ( iter -> old_spte );
1258+ return __kvm_tdp_mmu_age_gfn_range ( kvm , range , false );
12681259}
12691260
12701261bool kvm_tdp_mmu_test_age_gfn (struct kvm * kvm , struct kvm_gfn_range * range )
12711262{
1272- return kvm_tdp_mmu_handle_gfn (kvm , range , test_age_gfn );
1263+ return __kvm_tdp_mmu_age_gfn_range (kvm , range , true );
12731264}
12741265
12751266/*
0 commit comments