aboutsummaryrefslogtreecommitdiffstats
path: root/xen
diff options
context:
space:
mode:
authorWei Liu <wei.liu2@citrix.com>2012-01-24 14:16:04 +0000
committerWei Liu <wei.liu2@citrix.com>2012-01-24 14:16:04 +0000
commit04b9829949d79e753c8047f4ef620a82b1743349 (patch)
treebbf692fac5b4fdf15a367ba68a9aa7b0f9bac4a6 /xen
parentf67b958f103337ba173feaf015eae7c43e35a7a8 (diff)
downloadxen-04b9829949d79e753c8047f4ef620a82b1743349.tar.gz
xen-04b9829949d79e753c8047f4ef620a82b1743349.tar.bz2
xen-04b9829949d79e753c8047f4ef620a82b1743349.zip
Add a GNTTABOP to swap the content of two grant references under lock
provided that they are not currently active. Signed-off-by: Wei Liu <wei.liu2@citrix.com> Signed-off-by: Paul Durrant <paul.durrant@citrix.com> Committed-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen')
-rw-r--r--xen/arch/x86/hvm/hvm.c1
-rw-r--r--xen/common/compat/grant_table.c8
-rw-r--r--xen/common/grant_table.c89
-rw-r--r--xen/include/public/grant_table.h18
-rw-r--r--xen/include/xlat.lst1
5 files changed, 115 insertions, 2 deletions
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index a0c1a24a4c..b163ed0f01 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -2959,6 +2959,7 @@ static int grant_table_op_is_allowed(unsigned int cmd)
case GNTTABOP_copy:
case GNTTABOP_map_grant_ref:
case GNTTABOP_unmap_grant_ref:
+ case GNTTABOP_swap_grant_ref:
return 1;
default:
/* all other commands need auditing */
diff --git a/xen/common/compat/grant_table.c b/xen/common/compat/grant_table.c
index ca60395f0a..edd20c6bd3 100644
--- a/xen/common/compat/grant_table.c
+++ b/xen/common/compat/grant_table.c
@@ -47,6 +47,10 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_compat_t);
CHECK_gnttab_get_version;
#undef xen_gnttab_get_version
+#define xen_gnttab_swap_grant_ref gnttab_swap_grant_ref
+CHECK_gnttab_swap_grant_ref;
+#undef xen_gnttab_swap_grant_ref
+
int compat_grant_table_op(unsigned int cmd,
XEN_GUEST_HANDLE(void) cmp_uop,
unsigned int count)
@@ -98,6 +102,10 @@ int compat_grant_table_op(unsigned int cmd,
CASE(get_status_frames);
#endif
+#ifndef CHECK_gnttab_swap_grant_ref
+ CASE(swap_grant_ref);
+#endif
+
#undef CASE
default:
return do_grant_table_op(cmd, cmp_uop, count);
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 58d5e1f114..0c55fd154d 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -2283,6 +2283,81 @@ gnttab_get_version(XEN_GUEST_HANDLE(gnttab_get_version_t uop))
return 0;
}
+static s16
+__gnttab_swap_grant_ref(grant_ref_t ref_a, grant_ref_t ref_b)
+{
+ struct domain *d;
+ struct active_grant_entry *act;
+ s16 rc = GNTST_okay;
+
+ d = rcu_lock_current_domain();
+
+ spin_lock(&d->grant_table->lock);
+
+ act = &active_entry(d->grant_table, ref_a);
+ if ( act->pin )
+ PIN_FAIL(out, GNTST_eagain, "ref a %ld busy\n", (long)ref_a);
+
+ act = &active_entry(d->grant_table, ref_b);
+ if ( act->pin )
+ PIN_FAIL(out, GNTST_eagain, "ref b %ld busy\n", (long)ref_b);
+
+ if ( d->grant_table->gt_version == 1 )
+ {
+ grant_entry_v1_t shared;
+
+ shared = shared_entry_v1(d->grant_table, ref_a);
+
+ shared_entry_v1(d->grant_table, ref_a) =
+ shared_entry_v1(d->grant_table, ref_b);
+
+ shared_entry_v1(d->grant_table, ref_b) = shared;
+ }
+ else
+ {
+ grant_entry_v2_t shared;
+ grant_status_t status;
+
+ shared = shared_entry_v2(d->grant_table, ref_a);
+ status = status_entry(d->grant_table, ref_a);
+
+ shared_entry_v2(d->grant_table, ref_a) =
+ shared_entry_v2(d->grant_table, ref_b);
+ status_entry(d->grant_table, ref_a) =
+ status_entry(d->grant_table, ref_b);
+
+ shared_entry_v2(d->grant_table, ref_b) = shared;
+ status_entry(d->grant_table, ref_b) = status;
+ }
+
+out:
+ spin_unlock(&d->grant_table->lock);
+
+ rcu_unlock_domain(d);
+
+ return rc;
+}
+
+static long
+gnttab_swap_grant_ref(XEN_GUEST_HANDLE(gnttab_swap_grant_ref_t uop),
+ unsigned int count)
+{
+ int i;
+ gnttab_swap_grant_ref_t op;
+
+ for ( i = 0; i < count; i++ )
+ {
+ if ( i && hypercall_preempt_check() )
+ return i;
+ if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
+ return -EFAULT;
+ op.status = __gnttab_swap_grant_ref(op.ref_a, op.ref_b);
+ if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
+ return -EFAULT;
+ }
+ return 0;
+}
+
long
do_grant_table_op(
unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
@@ -2401,6 +2476,20 @@ do_grant_table_op(
rc = gnttab_get_version(guest_handle_cast(uop, gnttab_get_version_t));
break;
}
+ case GNTTABOP_swap_grant_ref:
+ {
+ XEN_GUEST_HANDLE(gnttab_swap_grant_ref_t) swap =
+ guest_handle_cast(uop, gnttab_swap_grant_ref_t);
+ if ( unlikely(!guest_handle_okay(swap, count)) )
+ goto out;
+ rc = gnttab_swap_grant_ref(swap, count);
+ if ( rc > 0 )
+ {
+ guest_handle_add_offset(swap, rc);
+ uop = guest_handle_cast(swap, void);
+ }
+ break;
+ }
default:
rc = -ENOSYS;
break;
diff --git a/xen/include/public/grant_table.h b/xen/include/public/grant_table.h
index 0bf20bcc69..54d95511e9 100644
--- a/xen/include/public/grant_table.h
+++ b/xen/include/public/grant_table.h
@@ -511,6 +511,20 @@ struct gnttab_get_version {
typedef struct gnttab_get_version gnttab_get_version_t;
DEFINE_XEN_GUEST_HANDLE(gnttab_get_version_t);
+/*
+ * GNTTABOP_swap_grant_ref: Swap the contents of two grant entries.
+ */
+#define GNTTABOP_swap_grant_ref 11
+struct gnttab_swap_grant_ref {
+ /* IN parameters */
+ grant_ref_t ref_a;
+ grant_ref_t ref_b;
+ /* OUT parameters */
+ int16_t status; /* GNTST_* */
+};
+typedef struct gnttab_swap_grant_ref gnttab_swap_grant_ref_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_swap_grant_ref_t);
+
#endif /* __XEN_INTERFACE_VERSION__ */
/*
@@ -566,7 +580,7 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_get_version_t);
#define GNTST_bad_page (-9) /* Specified page was invalid for op. */
#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary. */
#define GNTST_address_too_big (-11) /* transfer page address too large. */
-#define GNTST_eagain (-12) /* Could not map at the moment. Retry. */
+#define GNTST_eagain (-12) /* Operation not done; try again. */
#define GNTTABOP_error_msgs { \
"okay", \
@@ -581,7 +595,7 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_get_version_t);
"bad page", \
"copy arguments cross page boundary", \
"page address size too large", \
- "could not map at the moment, retry" \
+ "operation not done; try again" \
}
#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst
index 3d92175f41..f6021550df 100644
--- a/xen/include/xlat.lst
+++ b/xen/include/xlat.lst
@@ -50,6 +50,7 @@
? grant_entry_v1 grant_table.h
? grant_entry_header grant_table.h
? grant_entry_v2 grant_table.h
+? gnttab_swap_grant_ref grant_table.h
? kexec_exec kexec.h
! kexec_image kexec.h
! kexec_range kexec.h