[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen stable-4.14] evtchn: arrange for preemption in evtchn_reset()
commit 03019c20b516be53ba0cd393f5291974a9a6c9a8 Author: Jan Beulich <jbeulich@xxxxxxxx> AuthorDate: Tue Sep 22 16:16:52 2020 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Tue Sep 22 16:16:52 2020 +0200 evtchn: arrange for preemption in evtchn_reset() Like for evtchn_destroy() looping over all possible event channels to close them can take a significant amount of time. Unlike done there, we can't alter domain properties (i.e. d->valid_evtchns) here. Borrow, in a lightweight form, the paging domctl continuation concept, redirecting the continuations to different sub-ops. Just like there this is to be able to allow for predictable overall results of the involved sub-ops: Racing requests should either complete or be refused. Note that a domain can't interfere with an already started (by a remote domain) reset, due to being paused. It can prevent a remote reset from happening by leaving a reset unfinished, but that's only going to affect itself. This is part of XSA-344. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> Acked-by: Julien Grall <jgrall@xxxxxxxxxx> Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx> --- xen/common/domain.c | 4 ++-- xen/common/domctl.c | 12 ++++++++++- xen/common/event_channel.c | 42 ++++++++++++++++++++++++++++++++++---- xen/include/public/domctl.h | 5 ++++- xen/include/public/event_channel.h | 3 +++ xen/include/xen/event.h | 2 +- xen/include/xen/sched.h | 4 +++- 7 files changed, 62 insertions(+), 10 deletions(-) diff --git a/xen/common/domain.c b/xen/common/domain.c index 364fcbabb2..a275a35c4f 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -1145,7 +1145,7 @@ void domain_unpause_except_self(struct domain *d) domain_unpause(d); } -int domain_soft_reset(struct domain *d) +int domain_soft_reset(struct domain *d, bool resuming) { struct vcpu *v; int rc; @@ -1159,7 +1159,7 @@ int domain_soft_reset(struct domain *d) } spin_unlock(&d->shutdown_lock); - rc = evtchn_reset(d); + rc = evtchn_reset(d, resuming); if ( rc ) return rc; diff --git a/xen/common/domctl.c b/xen/common/domctl.c index a69b3b59a8..2b25653b49 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -562,12 +562,22 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) } case XEN_DOMCTL_soft_reset: + case XEN_DOMCTL_soft_reset_cont: if ( d == current->domain ) /* no domain_pause() */ { ret = -EINVAL; break; } - ret = domain_soft_reset(d); + ret = domain_soft_reset(d, op->cmd == XEN_DOMCTL_soft_reset_cont); + if ( ret == -ERESTART ) + { + op->cmd = XEN_DOMCTL_soft_reset_cont; + if ( !__copy_field_to_guest(u_domctl, op, cmd) ) + ret = hypercall_create_continuation(__HYPERVISOR_domctl, + "h", u_domctl); + else + ret = -EFAULT; + } break; case XEN_DOMCTL_destroydomain: diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 3b1fe423df..d2ee83bbbf 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -1057,7 +1057,7 @@ int evtchn_unmask(unsigned int port) return 0; } -int evtchn_reset(struct domain *d) +int evtchn_reset(struct domain *d, bool resuming) { unsigned int i; int rc = 0; @@ -1065,11 +1065,40 @@ int evtchn_reset(struct domain *d) if ( d != current->domain && !d->controller_pause_count ) return -EINVAL; - for ( i = 0; port_is_valid(d, i); i++ ) + spin_lock(&d->event_lock); + + /* + * If we are resuming, then start where we stopped. Otherwise, check + * that a reset operation is not already in progress, and if none is, + * record that this is now the case. + */ + i = resuming ? d->next_evtchn : !d->next_evtchn; + if ( i > d->next_evtchn ) + d->next_evtchn = i; + + spin_unlock(&d->event_lock); + + if ( !i ) + return -EBUSY; + + for ( ; port_is_valid(d, i); i++ ) + { evtchn_close(d, i, 1); + /* NB: Choice of frequency is arbitrary. */ + if ( !(i & 0x3f) && hypercall_preempt_check() ) + { + spin_lock(&d->event_lock); + d->next_evtchn = i; + spin_unlock(&d->event_lock); + return -ERESTART; + } + } + spin_lock(&d->event_lock); + d->next_evtchn = 0; + if ( d->active_evtchns > d->xen_evtchns ) rc = -EAGAIN; else if ( d->evtchn_fifo ) @@ -1204,7 +1233,8 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) break; } - case EVTCHNOP_reset: { + case EVTCHNOP_reset: + case EVTCHNOP_reset_cont: { struct evtchn_reset reset; struct domain *d; @@ -1217,9 +1247,13 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) rc = xsm_evtchn_reset(XSM_TARGET, current->domain, d); if ( !rc ) - rc = evtchn_reset(d); + rc = evtchn_reset(d, cmd == EVTCHNOP_reset_cont); rcu_unlock_domain(d); + + if ( rc == -ERESTART ) + rc = hypercall_create_continuation(__HYPERVISOR_event_channel_op, + "ih", EVTCHNOP_reset_cont, arg); break; } diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 59bdc28c89..f416722491 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -1159,7 +1159,10 @@ struct xen_domctl { #define XEN_DOMCTL_iomem_permission 20 #define XEN_DOMCTL_ioport_permission 21 #define XEN_DOMCTL_hypercall_init 22 -#define XEN_DOMCTL_arch_setup 23 /* Obsolete IA64 only */ +#ifdef __XEN__ +/* #define XEN_DOMCTL_arch_setup 23 Obsolete IA64 only */ +#define XEN_DOMCTL_soft_reset_cont 23 +#endif #define XEN_DOMCTL_settimeoffset 24 #define XEN_DOMCTL_getvcpuaffinity 25 #define XEN_DOMCTL_real_mode_area 26 /* Obsolete PPC only */ diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h index cfb7929fef..b896d8da2a 100644 --- a/xen/include/public/event_channel.h +++ b/xen/include/public/event_channel.h @@ -74,6 +74,9 @@ #define EVTCHNOP_init_control 11 #define EVTCHNOP_expand_array 12 #define EVTCHNOP_set_priority 13 +#ifdef __XEN__ +#define EVTCHNOP_reset_cont 14 +#endif /* ` } */ typedef uint32_t evtchn_port_t; diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index bc9aa68650..fa93a3684a 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -179,7 +179,7 @@ void evtchn_check_pollers(struct domain *d, unsigned int port); void evtchn_2l_init(struct domain *d); /* Close all event channels and reset to 2-level ABI. */ -int evtchn_reset(struct domain *d); +int evtchn_reset(struct domain *d, bool resuming); /* * Low-level event channel port ops. diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 57d34b2205..a0d87ef9d0 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -371,6 +371,8 @@ struct domain * EVTCHNOP_reset). Read/write access like for active_evtchns. */ unsigned int xen_evtchns; + /* Port to resume from in evtchn_reset(), when in a continuation. */ + unsigned int next_evtchn; spinlock_t event_lock; const struct evtchn_port_ops *evtchn_port_ops; struct evtchn_fifo_domain *evtchn_fifo; @@ -663,7 +665,7 @@ int domain_kill(struct domain *d); int domain_shutdown(struct domain *d, u8 reason); void domain_resume(struct domain *d); -int domain_soft_reset(struct domain *d); +int domain_soft_reset(struct domain *d, bool resuming); int vcpu_start_shutdown_deferral(struct vcpu *v); void vcpu_end_shutdown_deferral(struct vcpu *v); -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.14
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |