|
@@ -244,6 +244,14 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
|
|
|
BUG_ON(pgnr >= map->count);
|
|
|
pte_maddr = arbitrary_virt_to_machine(pte).maddr;
|
|
|
|
|
|
+ /*
|
|
|
+ * Set the PTE as special to force get_user_pages_fast() fall
|
|
|
+ * back to the slow path. If this is not supported as part of
|
|
|
+ * the grant map, it will be done afterwards.
|
|
|
+ */
|
|
|
+ if (xen_feature(XENFEAT_gnttab_map_avail_bits))
|
|
|
+ flags |= (1 << _GNTMAP_guest_avail0);
|
|
|
+
|
|
|
gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, flags,
|
|
|
map->grants[pgnr].ref,
|
|
|
map->grants[pgnr].domid);
|
|
@@ -252,6 +260,15 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_X86
|
|
|
+static int set_grant_ptes_as_special(pte_t *pte, pgtable_t token,
|
|
|
+ unsigned long addr, void *data)
|
|
|
+{
|
|
|
+ set_pte_at(current->mm, addr, pte, pte_mkspecial(*pte));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static int map_grant_pages(struct grant_map *map)
|
|
|
{
|
|
|
int i, err = 0;
|
|
@@ -840,6 +857,23 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
|
|
|
if (err)
|
|
|
goto out_put_map;
|
|
|
}
|
|
|
+ } else {
|
|
|
+#ifdef CONFIG_X86
|
|
|
+ /*
|
|
|
+ * If the PTEs were not made special by the grant map
|
|
|
+ * hypercall, do so here.
|
|
|
+ *
|
|
|
+ * This is racy since the mapping is already visible
|
|
|
+ * to userspace but userspace should be well-behaved
|
|
|
+ * enough to not touch it until the mmap() call
|
|
|
+ * returns.
|
|
|
+ */
|
|
|
+ if (!xen_feature(XENFEAT_gnttab_map_avail_bits)) {
|
|
|
+ apply_to_page_range(vma->vm_mm, vma->vm_start,
|
|
|
+ vma->vm_end - vma->vm_start,
|
|
|
+ set_grant_ptes_as_special, NULL);
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
return 0;
|