x86 shadow: reset up-pointers on all l3s when l3s stop being pinnable.
authorKeir Fraser <keir@xen.org>
Sat, 2 Oct 2010 14:05:50 +0000 (15:05 +0100)
committerKeir Fraser <keir@xen.org>
Sat, 2 Oct 2010 14:05:50 +0000 (15:05 +0100)
Walking the pinned-shadows list isn't enough: there could be an
unpinned (but still shadowed) l3 somewhere and if we later try to
unshadow it it'll have an up-pointer of PAGE_LIST_NULL:PAGE_LIST_NULL.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
xen/arch/x86/mm/shadow/common.c
xen/arch/x86/mm/shadow/multi.c
xen/arch/x86/mm/shadow/private.h

index b91e6c2a4a98a8bcae1f461eb4ab1775693e4712..d063a4e371e71f2a98fe01aeab71f83dc2368985 100644 (file)
@@ -2774,6 +2774,47 @@ sh_remove_all_shadows_and_parents(struct vcpu *v, mfn_t gmfn)
      * It means extra emulated writes and slows down removal of mappings. */
 }
 
+/**************************************************************************/
+
+/* Reset the up-pointers of every L3 shadow to 0. 
+ * This is called when l3 shadows stop being pinnable, to clear out all
+ * the list-head bits so the up-pointer field is properly inititalised. */
+static int sh_clear_up_pointer(struct vcpu *v, mfn_t smfn, mfn_t unused)
+{
+    mfn_to_page(smfn)->up = 0;
+    return 0;
+}
+
+void sh_reset_l3_up_pointers(struct vcpu *v)
+{
+    static hash_callback_t callbacks[SH_type_unused] = {
+        NULL, /* none    */
+        NULL, /* l1_32   */
+        NULL, /* fl1_32  */
+        NULL, /* l2_32   */
+        NULL, /* l1_pae  */
+        NULL, /* fl1_pae */
+        NULL, /* l2_pae  */
+        NULL, /* l2h_pae */
+        NULL, /* l1_64   */
+        NULL, /* fl1_64  */
+        NULL, /* l2_64   */
+        NULL, /* l2h_64  */
+#if CONFIG_PAGING_LEVELS >= 4
+        sh_clear_up_pointer, /* l3_64   */
+#else
+        NULL, /* l3_64   */
+#endif
+        NULL, /* l4_64   */
+        NULL, /* p2m     */
+        NULL  /* unused  */
+    };
+    static unsigned int callback_mask = 1 << SH_type_l3_64_shadow;    
+
+    hash_foreach(v, callback_mask, callbacks, _mfn(INVALID_MFN));
+}
+
+
 /**************************************************************************/
 
 static void sh_update_paging_modes(struct vcpu *v)
index 06b4c0a09a7ffde6ba150e7577f980aa615637bf..09771bfc030b87c237fdc6c014921ac6b6e75b02 100644 (file)
@@ -1634,12 +1634,10 @@ sh_make_shadow(struct vcpu *v, mfn_t gmfn, u32 shadow_type)
             page_list_for_each_safe(sp, t, &v->domain->arch.paging.shadow.pinned_shadows)
             {
                 if ( sp->u.sh.type == SH_type_l3_64_shadow )
-                {
                     sh_unpin(v, page_to_mfn(sp));
-                    sp->up = 0;
-                }
             }
             v->domain->arch.paging.shadow.opt_flags &= ~SHOPT_LINUX_L3_TOPLEVEL;
+            sh_reset_l3_up_pointers(v);
         }
     }
 #endif
index 44e57e0abc0fbae90292b4a45b3fa9d5787c68a7..85766ce84b8b30a224c3d9a0cd699e781e532656 100644 (file)
@@ -475,6 +475,12 @@ mfn_t oos_snapshot_lookup(struct vcpu *v, mfn_t gmfn);
 
 #endif /* (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC) */
 
+
+/* Reset the up-pointers of every L3 shadow to 0. 
+ * This is called when l3 shadows stop being pinnable, to clear out all
+ * the list-head bits so the up-pointer field is properly inititalised. */
+void sh_reset_l3_up_pointers(struct vcpu *v);
+
 /******************************************************************************
  * Flags used in the return value of the shadow_set_lXe() functions...
  */