SHA256
1
0
forked from pool/xen
xen/53b56de1-properly-reference-count-DOMCTL_-un-pausedomain-hypercalls.patch
Charles Arnold b94eda4466 - Upstream patches from Jan
5347b524-evtchn-eliminate-64k-ports-limitation.patch
  53aac342-x86-HVM-consolidate-and-sanitize-CR4-guest-reserved-bit-determination.patch
  53b16cd4-VT-d-ATS-correct-and-clean-up-dev_invalidate_iotlb.patch
  53b56de1-properly-reference-count-DOMCTL_-un-pausedomain-hypercalls.patch
  53cfdcc7-avoid-crash-when-doing-shutdown-with-active-cpupools.patch
  53cfddaf-x86-mem_event-validate-the-response-vcpu_id-before-acting-on-it.patch
  53cfdde4-x86-mem_event-prevent-underflow-of-vcpu-pause-counts.patch

- bnc#886801 - xl vncviewer: The first domu can be accessed by any id
  53c9151b-Fix-xl-vncviewer-accesses-port-0-by-any-invalid-domid.patch

- Upstream pygrub bug fix
  5370e03b-pygrub-fix-error-handling-if-no-valid-partitions-are-found.patch

- Fix pygrub to handle old 32 bit VMs
  pygrub-boot-legacy-sles.patch (Mike Latimer)

- Remove xen-vmresync utility.  It is an old Platespin Orchestrate
  utility that should have never been included in the Xen package.
  Updated xen.spec

- Rework xen-destroy utility included in xen-utils
  bnc#885292 and bnc#886063
  Updated xen-utils-0.1.tar.bz2

- bnc#886063 - Xen monitor fails (xl list --long output different
  from xm list --long output)
- bnc#885292 - VirtualDomain: pid_status does not know how to check
  status on SLE12

OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=322
2014-07-24 19:43:18 +00:00

219 lines
7.2 KiB
Diff

# Commit 3eb1c708ab0fe1067a436498a684907afa14dacf
# Date 2014-07-03 16:51:13 +0200
# Author Andrew Cooper <andrew.cooper3@citrix.com>
# Committer Jan Beulich <jbeulich@suse.com>
properly reference count DOMCTL_{,un}pausedomain hypercalls
For safety reasons, c/s 6ae2df93c27 "mem_access: Add helper API to setup
ring and enable mem_access" has to pause the domain while it performs a set of
operations.
However without properly reference counted hypercalls, xc_mem_event_enable()
now unconditionally unpauses a previously paused domain.
To prevent toolstack software running wild, there is an arbitrary limit of 255
on the toolstack pause count. This is high enough for several components of
the toolstack to safely use, but prevents over/underflow of d->pause_count.
The previous domain_{,un}pause_by_systemcontroller() functions are updated to
return an error code. domain_pause_by_systemcontroller() is modified to have
a common stub and take a pause_fn pointer, allowing for both sync and nosync
domain pauses. domain_pause_for_debugger() has a hand-rolled nosync pause
replaced with the new domain_pause_by_systemcontroller_nosync(), and has its
variables shuffled slightly to avoid rereading current multiple times.
Suggested-by: Don Slutz <dslutz@verizon.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
With a couple of formatting adjustments:
Reviewed-by: Jan Beulich <jbeulich@suse.com>
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1019,7 +1019,7 @@ long arch_do_domctl(
struct vcpu *v;
ret = -EBUSY;
- if ( !d->is_paused_by_controller )
+ if ( !d->controller_pause_count )
break;
ret = -EINVAL;
if ( domctl->u.gdbsx_pauseunp_vcpu.vcpu >= MAX_VIRT_CPUS ||
@@ -1035,7 +1035,7 @@ long arch_do_domctl(
struct vcpu *v;
ret = -EBUSY;
- if ( !d->is_paused_by_controller )
+ if ( !d->controller_pause_count )
break;
ret = -EINVAL;
if ( domctl->u.gdbsx_pauseunp_vcpu.vcpu >= MAX_VIRT_CPUS ||
@@ -1053,7 +1053,7 @@ long arch_do_domctl(
struct vcpu *v;
domctl->u.gdbsx_domstatus.vcpu_id = -1;
- domctl->u.gdbsx_domstatus.paused = d->is_paused_by_controller;
+ domctl->u.gdbsx_domstatus.paused = d->controller_pause_count > 0;
if ( domctl->u.gdbsx_domstatus.paused )
{
for_each_vcpu ( d, v )
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -264,7 +264,7 @@ struct domain *domain_create(
if ( (err = xsm_domain_create(XSM_HOOK, d, ssidref)) != 0 )
goto fail;
- d->is_paused_by_controller = 1;
+ d->controller_pause_count = 1;
atomic_inc(&d->pause_count);
if ( domid )
@@ -680,18 +680,13 @@ void vcpu_end_shutdown_deferral(struct v
#ifdef HAS_GDBSX
void domain_pause_for_debugger(void)
{
- struct domain *d = current->domain;
- struct vcpu *v;
-
- atomic_inc(&d->pause_count);
- if ( test_and_set_bool(d->is_paused_by_controller) )
- domain_unpause(d); /* race-free atomic_dec(&d->pause_count) */
+ struct vcpu *curr = current;
+ struct domain *d = curr->domain;
- for_each_vcpu ( d, v )
- vcpu_sleep_nosync(v);
+ domain_pause_by_systemcontroller_nosync(d);
/* if gdbsx active, we just need to pause the domain */
- if (current->arch.gdbsx_vcpu_event == 0)
+ if ( curr->arch.gdbsx_vcpu_event == 0 )
send_global_virq(VIRQ_DEBUGGER);
}
#endif
@@ -839,17 +834,49 @@ void domain_unpause(struct domain *d)
vcpu_wake(v);
}
-void domain_pause_by_systemcontroller(struct domain *d)
+int __domain_pause_by_systemcontroller(struct domain *d,
+ void (*pause_fn)(struct domain *d))
{
- domain_pause(d);
- if ( test_and_set_bool(d->is_paused_by_controller) )
- domain_unpause(d);
+ int old, new, prev = d->controller_pause_count;
+
+ do
+ {
+ old = prev;
+ new = old + 1;
+
+ /*
+ * Limit the toolstack pause count to an arbitrary 255 to prevent the
+ * toolstack overflowing d->pause_count with many repeated hypercalls.
+ */
+ if ( new > 255 )
+ return -EUSERS;
+
+ prev = cmpxchg(&d->controller_pause_count, old, new);
+ } while ( prev != old );
+
+ pause_fn(d);
+
+ return 0;
}
-void domain_unpause_by_systemcontroller(struct domain *d)
+int domain_unpause_by_systemcontroller(struct domain *d)
{
- if ( test_and_clear_bool(d->is_paused_by_controller) )
- domain_unpause(d);
+ int old, new, prev = d->controller_pause_count;
+
+ do
+ {
+ old = prev;
+ new = old - 1;
+
+ if ( new < 0 )
+ return -EINVAL;
+
+ prev = cmpxchg(&d->controller_pause_count, old, new);
+ } while ( prev != old );
+
+ domain_unpause(d);
+
+ return 0;
}
int vcpu_reset(struct vcpu *v)
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -181,7 +181,7 @@ void getdomaininfo(struct domain *d, str
info->flags = (info->nr_online_vcpus ? flags : 0) |
((d->is_dying == DOMDYING_dead) ? XEN_DOMINF_dying : 0) |
(d->is_shut_down ? XEN_DOMINF_shutdown : 0) |
- (d->is_paused_by_controller ? XEN_DOMINF_paused : 0) |
+ (d->controller_pause_count > 0 ? XEN_DOMINF_paused : 0) |
(d->debugger_attached ? XEN_DOMINF_debugged : 0) |
d->shutdown_code << XEN_DOMINF_shutdownshift;
@@ -384,22 +384,14 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
break;
case XEN_DOMCTL_pausedomain:
- {
ret = -EINVAL;
if ( d != current->domain )
- {
- domain_pause_by_systemcontroller(d);
- ret = 0;
- }
- }
- break;
+ ret = domain_pause_by_systemcontroller(d);
+ break;
case XEN_DOMCTL_unpausedomain:
- {
- domain_unpause_by_systemcontroller(d);
- ret = 0;
- }
- break;
+ ret = domain_unpause_by_systemcontroller(d);
+ break;
case XEN_DOMCTL_resumedomain:
{
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -338,7 +338,7 @@ struct domain
/* Is this guest dying (i.e., a zombie)? */
enum { DOMDYING_alive, DOMDYING_dying, DOMDYING_dead } is_dying;
/* Domain is paused by controller software? */
- bool_t is_paused_by_controller;
+ int controller_pause_count;
/* Domain's VCPUs are pinned 1:1 to physical CPUs? */
bool_t is_pinned;
@@ -742,8 +742,17 @@ void domain_pause(struct domain *d);
void domain_pause_nosync(struct domain *d);
void vcpu_unpause(struct vcpu *v);
void domain_unpause(struct domain *d);
-void domain_pause_by_systemcontroller(struct domain *d);
-void domain_unpause_by_systemcontroller(struct domain *d);
+int domain_unpause_by_systemcontroller(struct domain *d);
+int __domain_pause_by_systemcontroller(struct domain *d,
+ void (*pause_fn)(struct domain *d));
+static inline int domain_pause_by_systemcontroller(struct domain *d)
+{
+ return __domain_pause_by_systemcontroller(d, domain_pause);
+}
+static inline int domain_pause_by_systemcontroller_nosync(struct domain *d)
+{
+ return __domain_pause_by_systemcontroller(d, domain_pause_nosync);
+}
void cpu_init(void);
struct scheduler;