[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen staging] x86/p2m: clarify foreign map handling in p2m_entry_modify()



commit ac607edc2e261e1bd5b2907a62c55f8e5ba8bc9d
Author:     Roger Pau Monne <roger.pau@xxxxxxxxxx>
AuthorDate: Thu Feb 19 18:26:19 2026 +0100
Commit:     Roger Pau Monne <roger.pau@xxxxxxxxxx>
CommitDate: Tue Feb 24 09:34:29 2026 +0100

    x86/p2m: clarify foreign map handling in p2m_entry_modify()
    
    Introduce an extra check and comment to ensure the outer caller has
    possibly taken an extra reference on the foreign page that's about to be
    removed from the p2m.  Otherwise the put_page() in p2m_entry_modify() won't
    be safe to do ahead of the entry being removed form the p2m and any cached
    states purged.
    
    While there also replace the error codes for unreachable paths to use
    EILSEQ.
    
    No functional change intended.
    
    Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
---
 xen/arch/x86/include/asm/p2m.h | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/include/asm/p2m.h b/xen/arch/x86/include/asm/p2m.h
index ef6b02ff0b..1ceb248b9d 100644
--- a/xen/arch/x86/include/asm/p2m.h
+++ b/xen/arch/x86/include/asm/p2m.h
@@ -1066,7 +1066,7 @@ static inline int p2m_entry_modify(struct p2m_domain 
*p2m, p2m_type_t nt,
         if ( !mfn_valid(nfn) || p2m != p2m_get_hostp2m(p2m->domain) )
         {
             ASSERT_UNREACHABLE();
-            return -EINVAL;
+            return -EILSEQ;
         }
 
         if ( !page_get_owner_and_reference(mfn_to_page(nfn)) )
@@ -1088,14 +1088,26 @@ static inline int p2m_entry_modify(struct p2m_domain 
*p2m, p2m_type_t nt,
         break;
 
     case p2m_map_foreign:
-        if ( !mfn_valid(ofn) || p2m != p2m_get_hostp2m(p2m->domain) )
+    {
+        struct page_info *pg = mfn_valid(ofn) ? mfn_to_page(ofn) : NULL;
+        unsigned long ci = pg ? ACCESS_ONCE(pg->count_info) : 0;
+
+        if ( !pg || p2m != p2m_get_hostp2m(p2m->domain) ||
+             /*
+              * Rely on the caller also holding a reference to the page, so
+              * that the put_page() below doesn't cause the page to be
+              * freed, as it still has to be removed from the p2m.
+              */
+             (ci & PGC_count_mask) <= (ci & PGC_allocated ? 2 : 1) ||
+             !p2m->nr_foreign )
         {
             ASSERT_UNREACHABLE();
-            return -EINVAL;
+            return -EILSEQ;
         }
-        put_page(mfn_to_page(ofn));
+        put_page(pg);
         p2m->nr_foreign--;
         break;
+    }
 
     default:
         break;
--
generated by git-patchbot for /home/xen/git/xen.git#staging



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.