@@ -313,13 +313,16 @@ static long gmap_clear_young_crste(union crste *crstep, gfn_t gfn, gfn_t end, st
313313 struct clear_young_pte_priv * priv = walk -> priv ;
314314 union crste crste , new ;
315315
316- crste = READ_ONCE (* crstep );
316+ do {
317+ crste = READ_ONCE (* crstep );
318+
319+ if (!crste .h .fc )
320+ return 0 ;
321+ if (!crste .s .fc1 .y && crste .h .i )
322+ return 0 ;
323+ if (crste_prefix (crste ) && !gmap_mkold_prefix (priv -> gmap , gfn , end ))
324+ break ;
317325
318- if (!crste .h .fc )
319- return 0 ;
320- if (!crste .s .fc1 .y && crste .h .i )
321- return 0 ;
322- if (!crste_prefix (crste ) || gmap_mkold_prefix (priv -> gmap , gfn , end )) {
323326 new = crste ;
324327 new .h .i = 1 ;
325328 new .s .fc1 .y = 0 ;
@@ -328,8 +331,8 @@ static long gmap_clear_young_crste(union crste *crstep, gfn_t gfn, gfn_t end, st
328331 folio_set_dirty (phys_to_folio (crste_origin_large (crste )));
329332 new .s .fc1 .d = 0 ;
330333 new .h .p = 1 ;
331- dat_crstep_xchg ( crstep , new , gfn , walk -> asce );
332- }
334+ } while (! dat_crstep_xchg_atomic ( crstep , crste , new , gfn , walk -> asce ) );
335+
333336 priv -> young = 1 ;
334337 return 0 ;
335338}
@@ -391,14 +394,18 @@ static long _gmap_unmap_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct
391394{
392395 struct gmap_unmap_priv * priv = walk -> priv ;
393396 struct folio * folio = NULL ;
397+ union crste old = * crstep ;
394398
395- if (crstep -> h .fc ) {
396- if (crstep -> s .fc1 .pr && test_bit (GMAP_FLAG_EXPORT_ON_UNMAP , & priv -> gmap -> flags ))
397- folio = phys_to_folio (crste_origin_large (* crstep ));
398- gmap_crstep_xchg (priv -> gmap , crstep , _CRSTE_EMPTY (crstep -> h .tt ), gfn );
399- if (folio )
400- uv_convert_from_secure_folio (folio );
401- }
399+ if (!old .h .fc )
400+ return 0 ;
401+
402+ if (old .s .fc1 .pr && test_bit (GMAP_FLAG_EXPORT_ON_UNMAP , & priv -> gmap -> flags ))
403+ folio = phys_to_folio (crste_origin_large (old ));
404+ /* No races should happen because kvm->mmu_lock is held in write mode */
405+ KVM_BUG_ON (!gmap_crstep_xchg_atomic (priv -> gmap , crstep , old , _CRSTE_EMPTY (old .h .tt ), gfn ),
406+ priv -> gmap -> kvm );
407+ if (folio )
408+ uv_convert_from_secure_folio (folio );
402409
403410 return 0 ;
404411}
@@ -474,23 +481,24 @@ static long _crste_test_and_clear_softdirty(union crste *table, gfn_t gfn, gfn_t
474481
475482 if (fatal_signal_pending (current ))
476483 return 1 ;
477- crste = READ_ONCE (* table );
478- if (!crste .h .fc )
479- return 0 ;
480- if (crste .h .p && !crste .s .fc1 .sd )
481- return 0 ;
484+ do {
485+ crste = READ_ONCE (* table );
486+ if (!crste .h .fc )
487+ return 0 ;
488+ if (crste .h .p && !crste .s .fc1 .sd )
489+ return 0 ;
482490
483- /*
484- * If this large page contains one or more prefixes of vCPUs that are
485- * currently running, do not reset the protection, leave it marked as
486- * dirty.
487- */
488- if (!crste .s .fc1 .prefix_notif || gmap_mkold_prefix (gmap , gfn , end )) {
491+ /*
492+ * If this large page contains one or more prefixes of vCPUs that are
493+ * currently running, do not reset the protection, leave it marked as
494+ * dirty.
495+ */
496+ if (crste .s .fc1 .prefix_notif && !gmap_mkold_prefix (gmap , gfn , end ))
497+ break ;
489498 new = crste ;
490499 new .h .p = 1 ;
491500 new .s .fc1 .sd = 0 ;
492- gmap_crstep_xchg (gmap , table , new , gfn );
493- }
501+ } while (!gmap_crstep_xchg_atomic (gmap , table , crste , new , gfn ));
494502
495503 for ( ; gfn < end ; gfn ++ )
496504 mark_page_dirty (gmap -> kvm , gfn );
@@ -646,8 +654,8 @@ int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fau
646654static int gmap_ucas_map_one (struct kvm_s390_mmu_cache * mc , struct gmap * gmap ,
647655 gfn_t p_gfn , gfn_t c_gfn , bool force_alloc )
648656{
657+ union crste newcrste , oldcrste ;
649658 struct page_table * pt ;
650- union crste newcrste ;
651659 union crste * crstep ;
652660 union pte * ptep ;
653661 int rc ;
@@ -673,7 +681,11 @@ static int gmap_ucas_map_one(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
673681 & crstep , & ptep );
674682 if (rc )
675683 return rc ;
676- dat_crstep_xchg (crstep , newcrste , c_gfn , gmap -> asce );
684+ do {
685+ oldcrste = READ_ONCE (* crstep );
686+ if (oldcrste .val == newcrste .val )
687+ break ;
688+ } while (!dat_crstep_xchg_atomic (crstep , oldcrste , newcrste , c_gfn , gmap -> asce ));
677689 return 0 ;
678690}
679691
@@ -777,8 +789,10 @@ static void gmap_ucas_unmap_one(struct gmap *gmap, gfn_t c_gfn)
777789 int rc ;
778790
779791 rc = dat_entry_walk (NULL , c_gfn , gmap -> asce , 0 , TABLE_TYPE_SEGMENT , & crstep , & ptep );
780- if (!rc )
781- dat_crstep_xchg (crstep , _PMD_EMPTY , c_gfn , gmap -> asce );
792+ if (rc )
793+ return ;
794+ while (!dat_crstep_xchg_atomic (crstep , READ_ONCE (* crstep ), _PMD_EMPTY , c_gfn , gmap -> asce ))
795+ ;
782796}
783797
784798void gmap_ucas_unmap (struct gmap * gmap , gfn_t c_gfn , unsigned long count )
@@ -1017,8 +1031,8 @@ static void gmap_unshadow_level(struct gmap *sg, gfn_t r_gfn, int level)
10171031 dat_ptep_xchg (ptep , _PTE_EMPTY , r_gfn , sg -> asce , uses_skeys (sg ));
10181032 return ;
10191033 }
1020- crste = READ_ONCE ( * crstep );
1021- dat_crstep_clear (crstep , r_gfn , sg -> asce );
1034+
1035+ crste = dat_crstep_clear_atomic (crstep , r_gfn , sg -> asce );
10221036 if (crste_leaf (crste ) || crste .h .i )
10231037 return ;
10241038 if (is_pmd (crste ))
0 commit comments