Hi:
[XEN] gnttab: Add new op unmap_and_replace
The operation unmap_and_replace is an extension of unmap_grant_ref.
A new argument in the form of a virtual address (for PV) is given.
Instead of modifying the PTE for the mapped grant table entry to
null, we change it to the PTE for the new address. In turn we
point the new address to null.
As it stands grant table entries once mapped cannot be
remapped by the guest OS (it can however perform a new
mapping on the same entry but that is within our control).
Therefore it's safe to manipulate the mapped PTE entry to
redirect it to a normal page where we've copied the contents.
It's intended to be used as follows:
1) map_grant_ref to v1
2) ...
3) alloc page at v2
4) copy the page at v1 to v2
5) unmap_and_replace v1 with v2
Signed-off-by: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@xxxxxxxxxxxxxxxxxxx>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff -r 3ac19fda0bc2 linux-2.6-xen-sparse/include/xen/gnttab.h
--- a/linux-2.6-xen-sparse/include/xen/gnttab.h Fri Mar 02 12:11:52 2007 +0000
+++ b/linux-2.6-xen-sparse/include/xen/gnttab.h Tue Mar 20 14:08:40 2007 +1100
@@ -135,4 +135,19 @@ gnttab_set_unmap_op(struct gnttab_unmap_
unmap->dev_bus_addr = 0;
}
+static inline void
+gnttab_set_replace_op(struct gnttab_unmap_and_replace *unmap, maddr_t addr,
+ maddr_t new_addr, grant_handle_t handle)
+{
+ if (xen_feature(XENFEAT_auto_translated_physmap)) {
+ unmap->host_addr = __pa(addr);
+ unmap->new_addr = __pa(new_addr);
+ } else {
+ unmap->host_addr = addr;
+ unmap->new_addr = new_addr;
+ }
+
+ unmap->handle = handle;
+}
+
#endif /* __ASM_GNTTAB_H__ */
diff -r 3ac19fda0bc2 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Fri Mar 02 12:11:52 2007 +0000
+++ b/xen/arch/x86/mm.c Tue Mar 20 14:08:40 2007 +1100
@@ -2594,8 +2594,8 @@ static int create_grant_va_mapping(
return GNTST_okay;
}
-static int destroy_grant_va_mapping(
- unsigned long addr, unsigned long frame, struct vcpu *v)
+static int replace_grant_va_mapping(
+ unsigned long addr, unsigned long frame, l1_pgentry_t nl1e, struct vcpu *v)
{
l1_pgentry_t *pl1e, ol1e;
unsigned long gl1mfn;
@@ -2619,7 +2619,7 @@ static int destroy_grant_va_mapping(
}
/* Delete pagetable entry. */
- if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(), gl1mfn, v)) )
+ if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v)) )
{
MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
rc = GNTST_general_error;
@@ -2629,6 +2629,12 @@ static int destroy_grant_va_mapping(
out:
guest_unmap_l1e(v, pl1e);
return rc;
+}
+
+static int destroy_grant_va_mapping(
+ unsigned long addr, unsigned long frame, struct vcpu *v)
+{
+ return replace_grant_va_mapping(addr, frame, l1e_empty(), v);
}
int create_grant_host_mapping(
@@ -2652,6 +2658,44 @@ int destroy_grant_host_mapping(
if ( flags & GNTMAP_contains_pte )
return destroy_grant_pte_mapping(addr, frame, current->domain);
return destroy_grant_va_mapping(addr, frame, current);
+}
+
+int replace_grant_host_mapping(
+ uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags)
+{
+ l1_pgentry_t *pl1e, ol1e;
+ unsigned long gl1mfn;
+ int rc;
+
+ if ( flags & GNTMAP_contains_pte )
+ {
+ MEM_LOG("Unsupported grant table operation");
+ return GNTST_general_error;
+ }
+
+ pl1e = guest_map_l1e(current, new_addr, &gl1mfn);
+ if ( !pl1e )
+ {
+ MEM_LOG("Could not find L1 PTE for address %lx",
+ (unsigned long)new_addr);
+ return GNTST_general_error;
+ }
+ ol1e = *pl1e;
+
+ if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(), gl1mfn, current))
)
+ {
+ MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
+ guest_unmap_l1e(current, pl1e);
+ return GNTST_general_error;
+ }
+
+ guest_unmap_l1e(current, pl1e);
+
+ rc = replace_grant_va_mapping(addr, frame, ol1e, current);
+ if ( rc && !paging_mode_refcounts(current->domain) )
+ put_page_from_l1e(ol1e, current->domain);
+
+ return rc;
}
int steal_page(
diff -r 3ac19fda0bc2 xen/common/grant_table.c
--- a/xen/common/grant_table.c Fri Mar 02 12:11:52 2007 +0000
+++ b/xen/common/grant_table.c Tue Mar 20 14:08:40 2007 +1100
@@ -540,6 +540,126 @@ fault:
return -EFAULT;
}
+static void
+__gnttab_unmap_and_replace(
+ struct gnttab_unmap_and_replace *op)
+{
+ domid_t dom;
+ grant_ref_t ref;
+ struct domain *ld, *rd;
+ struct active_grant_entry *act;
+ grant_entry_t *sha;
+ struct grant_mapping *map;
+ u16 flags;
+ s16 rc = 0;
+ unsigned long frame;
+
+ ld = current->domain;
+
+ if ( unlikely(op->handle >= ld->grant_table->maptrack_limit) )
+ {
+ gdprintk(XENLOG_INFO, "Bad handle (%d).\n", op->handle);
+ op->status = GNTST_bad_handle;
+ return;
+ }
+
+ map = &maptrack_entry(ld->grant_table, op->handle);
+
+ if ( unlikely(!map->flags) )
+ {
+ gdprintk(XENLOG_INFO, "Zero flags for handle (%d).\n", op->handle);
+ op->status = GNTST_bad_handle;
+ return;
+ }
+
+ dom = map->domid;
+ ref = map->ref;
+ flags = map->flags;
+
+ if ( unlikely((rd = rcu_lock_domain_by_id(dom)) == NULL) )
+ {
+ /* This can happen when a grant is implicitly unmapped. */
+ gdprintk(XENLOG_INFO, "Could not find domain %d\n", dom);
+ domain_crash(ld); /* naughty... */
+ return;
+ }
+
+ TRACE_1D(TRC_MEM_PAGE_GRANT_UNMAP, dom);
+
+ spin_lock(&rd->grant_table->lock);
+
+ act = &active_entry(rd->grant_table, ref);
+ sha = &shared_entry(rd->grant_table, ref);
+
+ frame = act->frame;
+
+ if ( flags & GNTMAP_host_map )
+ {
+ if ( (rc = replace_grant_host_mapping(op->host_addr,
+ frame, op->new_addr, flags)) < 0
)
+ goto unmap_out;
+
+ ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask));
+ map->flags &= ~GNTMAP_host_map;
+ if ( flags & GNTMAP_readonly )
+ {
+ act->pin -= GNTPIN_hstr_inc;
+ put_page(mfn_to_page(frame));
+ }
+ else
+ {
+ act->pin -= GNTPIN_hstw_inc;
+ put_page_and_type(mfn_to_page(frame));
+ }
+ }
+
+ if ( (map->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0 )
+ {
+ map->flags = 0;
+ put_maptrack_handle(ld->grant_table, op->handle);
+ }
+
+ /* If just unmapped a writable mapping, mark as dirtied */
+ if ( !(flags & GNTMAP_readonly) )
+ gnttab_mark_dirty(rd, frame);
+
+ if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
+ !(flags & GNTMAP_readonly) )
+ gnttab_clear_flag(_GTF_writing, &sha->flags);
+
+ if ( act->pin == 0 )
+ gnttab_clear_flag(_GTF_reading, &sha->flags);
+
+ unmap_out:
+ op->status = rc;
+ spin_unlock(&rd->grant_table->lock);
+ rcu_unlock_domain(rd);
+}
+
+static long
+gnttab_unmap_and_replace(
+ XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t) uop, unsigned int count)
+{
+ int i;
+ struct gnttab_unmap_and_replace op;
+
+ for ( i = 0; i < count; i++ )
+ {
+ if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
+ goto fault;
+ __gnttab_unmap_and_replace(&op);
+ if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
+ goto fault;
+ }
+
+ flush_tlb_mask(current->domain->domain_dirty_cpumask);
+ return 0;
+
+fault:
+ flush_tlb_mask(current->domain->domain_dirty_cpumask);
+ return -EFAULT;
+}
+
int
gnttab_grow_table(struct domain *d, unsigned int req_nr_frames)
{
@@ -1201,6 +1321,21 @@ do_grant_table_op(
if ( unlikely(!grant_operation_permitted(d)) )
goto out;
rc = gnttab_unmap_grant_ref(unmap, count);
+ break;
+ }
+ case GNTTABOP_unmap_and_replace:
+ {
+ XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t) unmap =
+ guest_handle_cast(uop, gnttab_unmap_and_replace_t);
+ if ( unlikely(!guest_handle_okay(unmap, count)) )
+ goto out;
+ rc = -EPERM;
+ if ( unlikely(!grant_operation_permitted(d)) )
+ goto out;
+ rc = -ENOSYS;
+ if ( unlikely(!replace_grant_supported()) )
+ goto out;
+ rc = gnttab_unmap_and_replace(unmap, count);
break;
}
case GNTTABOP_setup_table:
diff -r 3ac19fda0bc2 xen/include/asm-ia64/grant_table.h
--- a/xen/include/asm-ia64/grant_table.h Fri Mar 02 12:11:52 2007 +0000
+++ b/xen/include/asm-ia64/grant_table.h Tue Mar 20 14:08:40 2007 +1100
@@ -64,4 +64,14 @@ static inline void gnttab_clear_flag(uns
clear_bit(nr, addr);
}
+static inline int replace_grant_host_mapping(unsigned long gpaddr, unsigned
long mfn, unsigned long new_gpaddr, unsigned int flags)
+{
+ return 0;
+}
+
+static inline int replace_grant_supported(void)
+{
+ return 0;
+}
+
#endif /* __ASM_GRANT_TABLE_H__ */
diff -r 3ac19fda0bc2 xen/include/asm-powerpc/grant_table.h
--- a/xen/include/asm-powerpc/grant_table.h Fri Mar 02 12:11:52 2007 +0000
+++ b/xen/include/asm-powerpc/grant_table.h Tue Mar 20 14:08:40 2007 +1100
@@ -69,4 +69,14 @@ static inline uint cpu_foreign_map_order
/* 16 GiB */
return 34 - PAGE_SHIFT;
}
+
+static inline int replace_grant_host_mapping(unsigned long addr, unsigned long
frame, unsigned long new_addr, unsigned int flags)
+{
+ return 0;
+}
+
+static inline int replace_grant_supported(void)
+{
+ return 0;
+}
#endif /* __ASM_PPC_GRANT_TABLE_H__ */
diff -r 3ac19fda0bc2 xen/include/asm-x86/grant_table.h
--- a/xen/include/asm-x86/grant_table.h Fri Mar 02 12:11:52 2007 +0000
+++ b/xen/include/asm-x86/grant_table.h Tue Mar 20 14:08:40 2007 +1100
@@ -17,6 +17,8 @@ int create_grant_host_mapping(
uint64_t addr, unsigned long frame, unsigned int flags);
int destroy_grant_host_mapping(
uint64_t addr, unsigned long frame, unsigned int flags);
+int replace_grant_host_mapping(
+ uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags);
#define gnttab_create_shared_page(d, t, i) \
do { \
@@ -38,4 +40,9 @@ static inline void gnttab_clear_flag(uns
clear_bit(nr, addr);
}
+static inline int replace_grant_supported(void)
+{
+ return 1;
+}
+
#endif /* __ASM_GRANT_TABLE_H__ */
diff -r 3ac19fda0bc2 xen/include/public/grant_table.h
--- a/xen/include/public/grant_table.h Fri Mar 02 12:11:52 2007 +0000
+++ b/xen/include/public/grant_table.h Tue Mar 20 14:08:40 2007 +1100
@@ -327,6 +327,29 @@ struct gnttab_query_size {
};
typedef struct gnttab_query_size gnttab_query_size_t;
DEFINE_XEN_GUEST_HANDLE(gnttab_query_size_t);
+
+/*
+ * GNTTABOP_unmap_and_replace: Destroy one or more grant-reference mappings
+ * tracked by <handle> but atomically replace the page table entry with one
+ * pointing to the machine address under <new_addr>. <new_addr> will be
+ * redirected to the null entry.
+ * NOTES:
+ * 1. The call may fail in an undefined manner if either mapping is not
+ * tracked by <handle>.
+ * 2. After executing a batch of unmaps, it is guaranteed that no stale
+ * mappings will remain in the device or host TLBs.
+ */
+#define GNTTABOP_unmap_and_replace 7
+struct gnttab_unmap_and_replace {
+ /* IN parameters. */
+ uint64_t host_addr;
+ uint64_t new_addr;
+ grant_handle_t handle;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+};
+typedef struct gnttab_unmap_and_replace gnttab_unmap_and_replace_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t);
/*
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|