@@ -2,6 +2,7 @@
#include <xen/domain_page.h>
#include <xen/iocap.h>
#include <xen/ioreq.h>
+#include <xen/grant_table.h>
#include <xen/lib.h>
#include <xen/sched.h>
#include <xen/softirq.h>
@@ -718,8 +719,10 @@ static int p2m_mem_access_radix_set(struct p2m_domain *p2m, gfn_t gfn,
* TODO: Handle superpages, for now we only take special references for leaf
* pages (specifically foreign ones, which can't be super mapped today).
*/
-static void p2m_put_l3_page(const lpae_t pte)
+static void p2m_put_l3_page(struct p2m_domain *p2m, const lpae_t pte)
{
+ mfn_t mfn = lpae_get_mfn(pte);
+
ASSERT(p2m_is_valid(pte));
/*
@@ -731,11 +734,20 @@ static void p2m_put_l3_page(const lpae_t pte)
*/
if ( p2m_is_foreign(pte.p2m.type) )
{
- mfn_t mfn = lpae_get_mfn(pte);
-
ASSERT(mfn_valid(mfn));
put_page(mfn_to_page(mfn));
}
+
+#ifdef CONFIG_GRANT_TABLE
+ /*
+ * Check whether we deal with grant-table page which GFN is stored
+ * in the gnttab database, so also needs to be marked as invalid.
+ * As the grant-table page is xen_heap page and its entry has known
+ * p2m type, detect it and let the gnttab code do the job.
+ */
+ if ( p2m_is_ram(pte.p2m.type) && is_xen_heap_mfn(mfn) )
+ gnttab_clean_frame_gfn(p2m->domain, mfn);
+#endif
}
/* Free lpae sub-tree behind an entry */
@@ -768,7 +780,7 @@ static void p2m_free_entry(struct p2m_domain *p2m,
p2m->stats.mappings[level]--;
/* Nothing to do if the entry is a super-page. */
if ( level == 3 )
- p2m_put_l3_page(entry);
+ p2m_put_l3_page(p2m, entry);
return;
}
@@ -4104,6 +4104,48 @@ int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn)
return rc;
}
+/*
+ * The only purpose of this function is to locate GFN corresponding to
+ * the passed MFN and remove it from the gnttab database.
+ */
+void gnttab_clean_frame_gfn(struct domain *d, mfn_t mfn)
+{
+ struct grant_table *gt = d->grant_table;
+ unsigned int i;
+ mfn_t tmp;
+
+ grant_write_lock(gt);
+
+ for ( i = 0; i < gt->max_grant_frames; i++ )
+ {
+ if ( gt->shared_raw[i] == NULL )
+ continue;
+
+ tmp = _mfn(virt_to_mfn(gt->shared_raw[i]));
+ if ( mfn_eq(tmp, mfn) )
+ {
+ gnttab_set_frame_gfn(gt, false, i, INVALID_GFN);
+ goto unlock;
+ }
+ }
+
+ for ( i = 0; i < grant_to_status_frames(gt->max_grant_frames); i++ )
+ {
+ if ( gt->status[i] == NULL )
+ continue;
+
+ tmp = _mfn(virt_to_mfn(gt->status[i]));
+ if ( mfn_eq(tmp, mfn) )
+ {
+ gnttab_set_frame_gfn(gt, true, i, INVALID_GFN);
+ goto unlock;
+ }
+ }
+
+unlock:
+ grant_write_unlock(gt);
+}
+
static void gnttab_usage_print(struct domain *rd)
{
int first = 1;
@@ -63,6 +63,8 @@ int gnttab_acquire_resource(
struct domain *d, unsigned int id, unsigned int frame,
unsigned int nr_frames, xen_pfn_t mfn_list[]);
+void gnttab_clean_frame_gfn(struct domain *d, mfn_t mfn);
+
#else
#define opt_max_grant_frames 0
@@ -108,6 +110,8 @@ static inline int gnttab_acquire_resource(
return -EINVAL;
}
+static inline void gnttab_clean_frame_gfn(struct domain *d, mfn_t mfn) {}
+
#endif /* CONFIG_GRANT_TABLE */
#endif /* __XEN_GRANT_TABLE_H__ */