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
219 lines
7.2 KiB
Diff
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;
|