]> xenbits.xensource.com Git - xen.git/commitdiff
This fixes a bug in changeset 22526:7a5ee3800417, where the wrong
authorTim Deegan <Tim.Deegan@citrix.com>
Wed, 16 Mar 2011 09:35:32 +0000 (09:35 +0000)
committerTim Deegan <Tim.Deegan@citrix.com>
Wed, 16 Mar 2011 09:35:32 +0000 (09:35 +0000)
value is read when deciding whether to flush the VTd tables.  The
effect is minor: in situations where the p2m entry is changed but the
mfn is the same, the VTd tables will be unnecessarily flushed.

old_entry is left untouched in the second case, since having a present
old_entry will cause the an unnecessary check to be taken at the end
of the function.

Spotted-by: Zhang, Peng Fei <zpfalpc23@gmail.com>
Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com>
Acked-by: Tim Deegan <Tim.Deegan@citrix.com>
xen/arch/x86/mm/hap/p2m-ept.c

index 49f379a2efc4858e7b0e5a041f356b51b2fbadf2..f1c2b0ee4dd9b681c04753d1564f4d11c6eb883a 100644 (file)
@@ -374,7 +374,9 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
             needs_sync = 0;
 
         /* If we're replacing a non-leaf entry with a leaf entry (1GiB or 2MiB),
-         * the intermediate tables will be freed below after the ept flush */
+         * the intermediate tables will be freed below after the ept flush
+         *
+         * Read-then-write is OK because we hold the p2m lock. */
         old_entry = *ept_entry;
 
         if ( mfn_valid(mfn_x(mfn)) || direct_mmio || p2m_is_paged(p2mt) ||
@@ -390,10 +392,10 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
             new_entry.access = p2ma;
             new_entry.rsvd2_snp = (iommu_enabled && iommu_snoop);
 
-            if ( new_entry.mfn == mfn_x(mfn) )
+            new_entry.mfn = mfn_x(mfn);
+
+            if ( old_entry.mfn == new_entry.mfn )
                 need_modify_vtd_table = 0;
-            else
-                new_entry.mfn = mfn_x(mfn);
 
             ept_p2m_type_to_flags(&new_entry, p2mt, p2ma);
         }
@@ -438,10 +440,12 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
         new_entry.access = p2ma;
         new_entry.rsvd2_snp = (iommu_enabled && iommu_snoop);
 
-        if ( new_entry.mfn == mfn_x(mfn) )
+        /* the caller should take care of the previous page */
+        new_entry.mfn = mfn_x(mfn);
+
+        /* Safe to read-then-write because we hold the p2m lock */
+        if ( ept_entry->mfn == new_entry.mfn )
              need_modify_vtd_table = 0;
-        else /* the caller should take care of the previous page */
-            new_entry.mfn = mfn_x(mfn);
 
         ept_p2m_type_to_flags(&new_entry, p2mt, p2ma);