:p
atchew
Login
Xenstored is using libxenctrl for only one purpose: to get information about state of domains. This RFC patch series is removing that dependency by introducing a new stable interface which can be used by xenstored instead. I have chosen to add a new hypercall with sub-commands. This can be changed, of course, but I thought this would be a good step towards stable control interfaces for the Xen tools. I have done only very little testing (basically normal domain creation and deletion). In case my approach is being accepted I'll do a more thorough test. What is missing right now is some cleanup (e.g. the need to allow the dominfo operation of the domctl hypercall for a stubdom based Xenstore could be removed). For Mini-OS some more work is needed to remove the dependency to libxenctrl for xenstore-stubdom, as Mini-OS can't be configured to use libxenevent and libxengnttab, but not libxenctrl today. Again, I'll do that cleanup in case the series is generally accepted. Juergen Gross (4): xen: add a domain unique id to each domain xen: add bitmap to indicate per-domain state changes xen: add new stable control hypercall tools/xenstore: use new stable interface instead of libxenctrl tools/flask/policy/modules/dom0.te | 2 +- tools/xenstore/Makefile | 3 +- tools/xenstore/xenstored_control.c | 14 +- tools/xenstore/xenstored_domain.c | 219 +++++++++++++++------------- xen/arch/arm/traps.c | 1 + xen/arch/x86/hvm/hypercall.c | 1 + xen/arch/x86/hypercall.c | 1 + xen/arch/x86/pv/hypercall.c | 1 + xen/common/Makefile | 1 + xen/common/control.c | 52 +++++++ xen/common/domain.c | 76 ++++++++++ xen/common/event_channel.c | 11 +- xen/include/Makefile | 1 + xen/include/public/control.h | 80 ++++++++++ xen/include/public/xen.h | 1 + xen/include/xen/event.h | 6 + xen/include/xen/hypercall.h | 5 + xen/include/xen/sched.h | 7 + xen/include/xsm/dummy.h | 14 ++ xen/include/xsm/xsm.h | 6 + xen/xsm/dummy.c | 1 + xen/xsm/flask/hooks.c | 6 + xen/xsm/flask/policy/access_vectors | 2 + 23 files changed, 402 insertions(+), 109 deletions(-) create mode 100644 xen/common/control.c create mode 100644 xen/include/public/control.h -- 2.26.2
Xenstore is referencing domains by their domid, but reuse of a domid can lead to the situation that Xenstore can't tell whether a domain with that domid has been deleted and created again without Xenstore noticing the domain is a new one now. Add a global domain creation unique id which is updated when creating a new domain, and store that value in struct domain of the new domain. The global unique id is initialized with the system time and updates are done via the xorshift algorithm which is used for pseudo random number generation, too (see https://en.wikipedia.org/wiki/Xorshift). Signed-off-by: Juergen Gross <jgross@suse.com> --- xen/common/domain.c | 16 ++++++++++++++++ xen/include/xen/sched.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/xen/common/domain.c b/xen/common/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -XXX,XX +XXX,XX @@ vcpu_info_t dummy_vcpu_info; bool __read_mostly vmtrace_available; +/* Unique domain identifier, protected by domctl lock. */ +static uint64_t unique_id; + static void __domain_finalise_shutdown(struct domain *d) { struct vcpu *v; @@ -XXX,XX +XXX,XX @@ static void _domain_destroy(struct domain *d) free_domain_struct(d); } +static uint64_t get_unique_id(void) +{ + uint64_t x = unique_id ? : NOW(); + + x ^= x << 13; + x ^= x >> 7; + x ^= x << 17; + unique_id = x; + + return x; +} + static int sanitise_domain_config(struct xen_domctl_createdomain *config) { bool hvm = config->flags & XEN_DOMCTL_CDF_hvm; @@ -XXX,XX +XXX,XX @@ struct domain *domain_create(domid_t domid, /* Sort out our idea of is_system_domain(). */ d->domain_id = domid; + d->unique_id = get_unique_id(); /* Debug sanity. */ ASSERT(is_system_domain(d) ? config == NULL : config != NULL); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ struct domain domid_t domain_id; unsigned int max_vcpus; + + uint64_t unique_id; /* Unique domain identifier */ + struct vcpu **vcpu; shared_info_t *shared_info; /* shared data area */ -- 2.26.2
Add a bitmap with one bit per possible domid indicating the respective domain has changed its state (created, deleted, dying, crashed, shutdown). Registering the VIRQ_DOM_EXC event will result in setting the bits for all existing domains and resetting all other bits. Resetting a bit will be done in a future patch. This information is needed for Xenstore to keep track of all domains. Signed-off-by: Juergen Gross <jgross@suse.com> --- xen/common/domain.c | 22 ++++++++++++++++++++++ xen/common/event_channel.c | 2 ++ xen/include/xen/sched.h | 2 ++ 3 files changed, 26 insertions(+) diff --git a/xen/common/domain.c b/xen/common/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -XXX,XX +XXX,XX @@ bool __read_mostly vmtrace_available; /* Unique domain identifier, protected by domctl lock. */ static uint64_t unique_id; +static DECLARE_BITMAP(dom_state_changed, DOMID_MASK + 1); + +void domain_reset_states(void) +{ + struct domain *d; + + bitmap_zero(dom_state_changed, DOMID_MASK + 1); + + rcu_read_lock(&domlist_read_lock); + + for_each_domain ( d ) + set_bit(d->domain_id, dom_state_changed); + + rcu_read_unlock(&domlist_read_lock); +} + static void __domain_finalise_shutdown(struct domain *d) { struct vcpu *v; @@ -XXX,XX +XXX,XX @@ static void __domain_finalise_shutdown(struct domain *d) return; d->is_shut_down = 1; + set_bit(d->domain_id, dom_state_changed); if ( (d->shutdown_code == SHUTDOWN_suspend) && d->suspend_evtchn ) evtchn_send(d, d->suspend_evtchn); else @@ -XXX,XX +XXX,XX @@ struct domain *domain_create(domid_t domid, rcu_assign_pointer(domain_hash[DOMAIN_HASH(domid)], d); spin_unlock(&domlist_update_lock); + set_bit(d->domain_id, dom_state_changed); + memcpy(d->handle, config->handle, sizeof(d->handle)); } @@ -XXX,XX +XXX,XX @@ int domain_kill(struct domain *d) /* Mem event cleanup has to go here because the rings * have to be put before we call put_domain. */ vm_event_cleanup(d); + set_bit(d->domain_id, dom_state_changed); put_domain(d); send_global_virq(VIRQ_DOM_EXC); /* fallthrough */ @@ -XXX,XX +XXX,XX @@ static void complete_domain_destroy(struct rcu_head *head) xfree(d->vcpu); + set_bit(d->domain_id, dom_state_changed); + _domain_destroy(d); send_global_virq(VIRQ_DOM_EXC); diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -XXX,XX +XXX,XX @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) rc = evtchn_bind_virq(&bind_virq, 0); if ( !rc && __copy_to_guest(arg, &bind_virq, 1) ) rc = -EFAULT; /* Cleaning up here would be a mess! */ + if ( !rc && bind_virq.virq == VIRQ_DOM_EXC ) + domain_reset_states(); break; } diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ void domain_resume(struct domain *d); int domain_soft_reset(struct domain *d, bool resuming); +void domain_reset_states(void); + int vcpu_start_shutdown_deferral(struct vcpu *v); void vcpu_end_shutdown_deferral(struct vcpu *v); -- 2.26.2
The sysctl and domctl hypercalls are not stable, so tools using those need to be in sync with the hypervisor. In order to decouple (some) tools from the hypervisor add a new stable hypercall __HYPERVISOR_control_op with (for now) two sub-options: - XEN_CONTROL_OP_get_version for retrieving the max version of the new hypercall supported by the hypervisor - XEN_CONTROL_OP_get_state_changed_domain for retrieving some state data of a domain which changed state (this is needed by Xenstore). The returned state just contains the domid, the domain unique id, and some flags (existing, shutdown, dying). Signed-off-by: Juergen Gross <jgross@suse.com> --- tools/flask/policy/modules/dom0.te | 2 +- xen/arch/arm/traps.c | 1 + xen/arch/x86/hvm/hypercall.c | 1 + xen/arch/x86/hypercall.c | 1 + xen/arch/x86/pv/hypercall.c | 1 + xen/common/Makefile | 1 + xen/common/control.c | 52 +++++++++++++++++++ xen/common/domain.c | 38 ++++++++++++++ xen/common/event_channel.c | 9 +++- xen/include/Makefile | 1 + xen/include/public/control.h | 80 +++++++++++++++++++++++++++++ xen/include/public/xen.h | 1 + xen/include/xen/event.h | 6 +++ xen/include/xen/hypercall.h | 5 ++ xen/include/xen/sched.h | 2 + xen/include/xsm/dummy.h | 14 +++++ xen/include/xsm/xsm.h | 6 +++ xen/xsm/dummy.c | 1 + xen/xsm/flask/hooks.c | 6 +++ xen/xsm/flask/policy/access_vectors | 2 + 20 files changed, 227 insertions(+), 3 deletions(-) create mode 100644 xen/common/control.c create mode 100644 xen/include/public/control.h diff --git a/tools/flask/policy/modules/dom0.te b/tools/flask/policy/modules/dom0.te index XXXXXXX..XXXXXXX 100644 --- a/tools/flask/policy/modules/dom0.te +++ b/tools/flask/policy/modules/dom0.te @@ -XXX,XX +XXX,XX @@ allow dom0_t xen_t:xen { mtrr_del mtrr_read microcode physinfo quirk writeconsole readapic writeapic privprofile nonprivprofile kexec firmware sleep frequency getidle debug getcpuinfo heap pm_op mca_op lockprof cpupool_op - getscheduler setscheduler hypfs_op + getscheduler setscheduler hypfs_op control_op }; allow dom0_t xen_t:xen2 { resource_op psr_cmt_op psr_alloc pmu_ctrl get_symbol diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -XXX,XX +XXX,XX @@ static arm_hypercall_t arm_hypercall_table[] = { #ifdef CONFIG_IOREQ_SERVER HYPERCALL(dm_op, 3), #endif + HYPERCALL(control_op, 2), }; #ifndef NDEBUG diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hypercall.c +++ b/xen/arch/x86/hvm/hypercall.c @@ -XXX,XX +XXX,XX @@ static const struct { #ifdef CONFIG_HYPFS HYPERCALL(hypfs_op), #endif + HYPERCALL(control_op), HYPERCALL(arch_1) }; diff --git a/xen/arch/x86/hypercall.c b/xen/arch/x86/hypercall.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hypercall.c +++ b/xen/arch/x86/hypercall.c @@ -XXX,XX +XXX,XX @@ const hypercall_args_t hypercall_args_table[NR_hypercalls] = ARGS(hvm_op, 2), ARGS(dm_op, 3), ARGS(hypfs_op, 5), + ARGS(control_op, 2), ARGS(mca, 1), ARGS(arch_1, 1), }; diff --git a/xen/arch/x86/pv/hypercall.c b/xen/arch/x86/pv/hypercall.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/pv/hypercall.c +++ b/xen/arch/x86/pv/hypercall.c @@ -XXX,XX +XXX,XX @@ const pv_hypercall_table_t pv_hypercall_table[] = { #ifdef CONFIG_HYPFS HYPERCALL(hypfs_op), #endif + HYPERCALL(control_op), HYPERCALL(mca), #ifndef CONFIG_PV_SHIM_EXCLUSIVE HYPERCALL(arch_1), diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_ARGO) += argo.o obj-y += bitmap.o obj-$(CONFIG_HYPFS_CONFIG) += config_data.o +obj-y += control.o obj-$(CONFIG_CORE_PARKING) += core_parking.o obj-y += cpu.o obj-$(CONFIG_DEBUG_TRACE) += debugtrace.o diff --git a/xen/common/control.c b/xen/common/control.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/control.c @@ -XXX,XX +XXX,XX @@ +/****************************************************************************** + * + * control.c + * + * Entry point of the stable __HYPERVISOR_control_op hypercall. + */ +#include <xen/err.h> +#include <xen/event.h> +#include <xen/guest_access.h> +#include <xen/hypercall.h> +#include <public/control.h> + +long do_control_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) +{ + int ret = 0; + + if ( xsm_control_op(XSM_OTHER, cmd) ) + return -EPERM; + + switch ( cmd ) + { + case XEN_CONTROL_OP_get_version: + if ( !guest_handle_is_null(arg) ) + return -EINVAL; + + ret = XEN_CONTROL_VERSION; + break; + + case XEN_CONTROL_OP_get_state_changed_domain: + { + struct xen_control_changed_domain info = { }; + + if ( get_global_virq_handler(VIRQ_DOM_EXC) != current->domain ) + return -EPERM; + + ret = domain_get_dom_state_changed(&info); + if ( ret ) + break; + + if ( copy_to_guest(arg, &info, 1) ) + ret = -EFAULT; + + break; + } + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} diff --git a/xen/common/domain.c b/xen/common/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -XXX,XX +XXX,XX @@ #include <asm/debugger.h> #include <asm/p2m.h> #include <asm/processor.h> +#include <public/control.h> #include <public/sched.h> #include <public/sysctl.h> #include <public/vcpu.h> @@ -XXX,XX +XXX,XX @@ void domain_reset_states(void) rcu_read_unlock(&domlist_read_lock); } +int domain_get_dom_state_changed(struct xen_control_changed_domain *info) +{ + unsigned int dom; + struct domain *d; + + while ( (dom = find_first_bit(dom_state_changed, DOMID_MASK + 1)) < + DOMID_FIRST_RESERVED ) + { + d = rcu_lock_domain_by_id(dom); + + if ( test_and_clear_bit(dom, dom_state_changed) ) + { + info->domid = dom; + if ( d ) + { + info->state = XEN_CONTROL_CHANGEDDOM_STATE_EXIST; + if ( d->is_shut_down ) + info->state |= XEN_CONTROL_CHANGEDDOM_STATE_SHUTDOWN; + if ( d->is_dying == DOMDYING_dead ) + info->state |= XEN_CONTROL_CHANGEDDOM_STATE_DYING; + info->unique_id = d->unique_id; + + rcu_unlock_domain(d); + } + + return 0; + } + + if ( d ) + { + rcu_unlock_domain(d); + } + } + + return -ENOENT; +} + static void __domain_finalise_shutdown(struct domain *d) { struct vcpu *v; diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -XXX,XX +XXX,XX @@ static struct domain *global_virq_handlers[NR_VIRQS] __read_mostly; static DEFINE_SPINLOCK(global_virq_handlers_lock); -void send_global_virq(uint32_t virq) +struct domain *get_global_virq_handler(uint32_t virq) { ASSERT(virq_is_global(virq)); - send_guest_global_virq(global_virq_handlers[virq] ?: hardware_domain, virq); + return global_virq_handlers[virq] ?: hardware_domain; +} + +void send_global_virq(uint32_t virq) +{ + send_guest_global_virq(get_global_virq_handler(virq), virq); } int set_global_virq_handler(struct domain *d, uint32_t virq) diff --git a/xen/include/Makefile b/xen/include/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/include/Makefile +++ b/xen/include/Makefile @@ -XXX,XX +XXX,XX @@ compat-arch-$(CONFIG_X86) := x86_32 headers-y := \ compat/arch-$(compat-arch-y).h \ + compat/control.h \ compat/elfnote.h \ compat/event_channel.h \ compat/features.h \ diff --git a/xen/include/public/control.h b/xen/include/public/control.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/public/control.h @@ -XXX,XX +XXX,XX @@ +/****************************************************************************** + * Xen Control Hypercall + * + * Copyright (c) 2021, SUSE Software Solutions Germany GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __XEN_PUBLIC_CONTROL_H__ +#define __XEN_PUBLIC_CONTROL_H__ + +#include "xen.h" + +/* + * Definitions for the __HYPERVISOR_control_op hypercall. + */ + +/* Highest version number of the control interface currently defined. */ +#define XEN_CONTROL_VERSION 1 + +/* + * Hypercall operations. + */ + +/* + * XEN_CONTROL_OP_get_version + * + * Read highest interface version supported by the hypervisor. + * + * arg: NULL + * + * Possible return values: + * >0: highest supported interface version + * <0: negative Xen errno value + */ +#define XEN_CONTROL_OP_get_version 0 + +/* + * XEN_CONTROL_OP_get_state_changed_domain + * + * Get information about a domain having changed state and reset the state + * change indicator for that domain. This function is usable only by a domain + * having registered the VIRQ_DOM_EXC event (normally Xenstore). + * + * arg: XEN_GUEST_HANDLE(struct xen_control_changed_domain) + * + * Possible return values: + * 0: success + * <0 : negative Xen errno value + */ +#define XEN_CONTROL_OP_get_state_changed_domain 1 +struct xen_control_changed_domain { + domid_t domid; + uint16_t state; +#define XEN_CONTROL_CHANGEDDOM_STATE_EXIST 0x0001 /* Domain is existing. */ +#define XEN_CONTROL_CHANGEDDOM_STATE_SHUTDOWN 0x0002 /* Shutdown finished. */ +#define XEN_CONTROL_CHANGEDDOM_STATE_DYING 0x0004 /* Domain dying. */ + uint32_t pad1; /* Returned as 0. */ + uint64_t unique_id; /* Unique domain identifier. */ + uint64_t pad2[6]; /* Returned as 0. */ +}; + +#endif /* __XEN_PUBLIC_CONTROL_H__ */ diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -XXX,XX +XXX,XX @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); #define __HYPERVISOR_xenpmu_op 40 #define __HYPERVISOR_dm_op 41 #define __HYPERVISOR_hypfs_op 42 +#define __HYPERVISOR_control_op 43 /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -XXX,XX +XXX,XX @@ void send_guest_global_virq(struct domain *d, uint32_t virq); */ int set_global_virq_handler(struct domain *d, uint32_t virq); +/* + * get_global_virq_handler: Get domain handling a global virq. + * @virq: Virtual IRQ number (VIRQ_*), must be global + */ +struct domain *get_global_virq_handler(uint32_t virq); + /* * send_guest_pirq: * @d: Domain to which physical IRQ should be sent diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/hypercall.h +++ b/xen/include/xen/hypercall.h @@ -XXX,XX +XXX,XX @@ do_hypfs_op( unsigned long arg4); #endif +extern long +do_control_op( + unsigned int cmd, + XEN_GUEST_HANDLE_PARAM(void) arg); + #ifdef CONFIG_COMPAT extern int diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ #include <xen/vpci.h> #include <xen/wait.h> #include <public/xen.h> +#include <public/control.h> #include <public/domctl.h> #include <public/sysctl.h> #include <public/vcpu.h> @@ -XXX,XX +XXX,XX @@ void domain_resume(struct domain *d); int domain_soft_reset(struct domain *d, bool resuming); void domain_reset_states(void); +int domain_get_dom_state_changed(struct xen_control_changed_domain *info); int vcpu_start_shutdown_deferral(struct vcpu *v); void vcpu_end_shutdown_deferral(struct vcpu *v); diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -XXX,XX +XXX,XX @@ #include <xen/sched.h> #include <xsm/xsm.h> +#include <public/control.h> #include <public/hvm/params.h> /* Cannot use BUILD_BUG_ON here because the expressions we check are not @@ -XXX,XX +XXX,XX @@ static XSM_INLINE int xsm_sysctl(XSM_DEFAULT_ARG int cmd) return xsm_default_action(action, current->domain, NULL); } +static XSM_INLINE int xsm_control_op(XSM_DEFAULT_ARG uint32_t cmd) +{ + XSM_ASSERT_ACTION(XSM_OTHER); + switch ( cmd ) + { + case XEN_CONTROL_OP_get_version: + case XEN_CONTROL_OP_get_state_changed_domain: + return xsm_default_action(XSM_XS_PRIV, current->domain, NULL); + default: + return xsm_default_action(XSM_PRIV, current->domain, NULL); + } +} + static XSM_INLINE int xsm_readconsole(XSM_DEFAULT_ARG uint32_t clear) { XSM_ASSERT_ACTION(XSM_HOOK); diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -XXX,XX +XXX,XX @@ struct xsm_operations { int (*page_offline)(uint32_t cmd); int (*hypfs_op)(void); + int (*control_op)(uint32_t cmd); long (*do_xsm_op) (XEN_GUEST_HANDLE_PARAM(void) op); #ifdef CONFIG_COMPAT @@ -XXX,XX +XXX,XX @@ static inline int xsm_hypfs_op(xsm_default_t def) return xsm_ops->hypfs_op(); } +static inline int xsm_control_op(xsm_default_t def, uint32_t cmd) +{ + return xsm_ops->control_op(cmd); +} + static inline long xsm_do_xsm_op (XEN_GUEST_HANDLE_PARAM(void) op) { return xsm_ops->do_xsm_op(op); diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index XXXXXXX..XXXXXXX 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -XXX,XX +XXX,XX @@ void __init xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, page_offline); set_to_dummy_if_null(ops, hypfs_op); + set_to_dummy_if_null(ops, control_op); set_to_dummy_if_null(ops, hvm_param); set_to_dummy_if_null(ops, hvm_control); set_to_dummy_if_null(ops, hvm_param_altp2mhvm); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index XXXXXXX..XXXXXXX 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -XXX,XX +XXX,XX @@ static inline int flask_hypfs_op(void) return domain_has_xen(current->domain, XEN__HYPFS_OP); } +static inline int flask_control_op(void) +{ + return domain_has_xen(current->domain, XEN__CONTROL_OP); +} + static int flask_add_to_physmap(struct domain *d1, struct domain *d2) { return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP); @@ -XXX,XX +XXX,XX @@ static struct xsm_operations flask_ops = { .page_offline = flask_page_offline, .hypfs_op = flask_hypfs_op, + .control_op = flask_control_op, .hvm_param = flask_hvm_param, .hvm_control = flask_hvm_param, .hvm_param_altp2mhvm = flask_hvm_param_altp2mhvm, diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index XXXXXXX..XXXXXXX 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -XXX,XX +XXX,XX @@ class xen cpupool_op # hypfs hypercall hypfs_op +# control hypercall + control_op # XEN_SYSCTL_scheduler_op with XEN_DOMCTL_SCHEDOP_getinfo, XEN_SYSCTL_sched_id, XEN_DOMCTL_SCHEDOP_getvcpuinfo getscheduler # XEN_SYSCTL_scheduler_op with XEN_DOMCTL_SCHEDOP_putinfo, XEN_DOMCTL_SCHEDOP_putvcpuinfo -- 2.26.2
Xenstore is using libxenctrl only for obtaining state information about domains. Use the new stable interface XEN_CONTROL_OP_get_state_changed_domain instead. Signed-off-by: Juergen Gross <jgross@suse.com> --- tools/xenstore/Makefile | 3 +- tools/xenstore/xenstored_control.c | 14 +- tools/xenstore/xenstored_domain.c | 219 ++++++++++++++++------------- 3 files changed, 130 insertions(+), 106 deletions(-) diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -XXX,XX +XXX,XX @@ CFLAGS += -include $(XEN_ROOT)/tools/config.h CFLAGS += -I./include CFLAGS += $(CFLAGS_libxenevtchn) CFLAGS += $(CFLAGS_libxenctrl) +CFLAGS += $(CFLAGS_libxencall) CFLAGS += $(CFLAGS_libxenguest) CFLAGS += $(CFLAGS_libxentoolcore) CFLAGS += -DXEN_LIB_STORED="\"$(XEN_LIB_STORED)\"" @@ -XXX,XX +XXX,XX @@ endif $(XENSTORED_OBJS): CFLAGS += $(CFLAGS_libxengnttab) xenstored: $(XENSTORED_OBJS) - $(CC) $^ $(LDFLAGS) $(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_libxenctrl) $(LDLIBS_xenstored) $(SOCKET_LIBS) -o $@ $(APPEND_LDFLAGS) + $(CC) $^ $(LDFLAGS) $(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_libxencall) $(LDLIBS_xenstored) $(SOCKET_LIBS) -o $@ $(APPEND_LDFLAGS) xenstored.a: $(XENSTORED_OBJS) $(AR) cr $@ $^ diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstore/xenstored_control.c +++ b/tools/xenstore/xenstored_control.c @@ -XXX,XX +XXX,XX @@ void lu_read_state(void) void *ctx = talloc_new(NULL); /* Work context for subfunctions. */ struct xs_state_preamble *pre; + /* + * We may have missed the VIRQ_DOM_EXC notification and a domain may + * have died while we were live-updating. So check all the domains are + * still alive. This will pre-initialize all domain structures. + */ + check_domains(); + syslog(LOG_INFO, "live-update: read state\n"); lu_get_dump_state(&state); if (state.size == 0) @@ -XXX,XX +XXX,XX @@ void lu_read_state(void) lu_close_dump_state(&state); talloc_free(ctx); - - /* - * We may have missed the VIRQ_DOM_EXC notification and a domain may - * have died while we were live-updating. So check all the domains are - * still alive. - */ - check_domains(); } static const char *lu_activate_binary(const void *ctx) diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -XXX,XX +XXX,XX @@ #include "xenstored_transaction.h" #include "xenstored_watch.h" +#include <xencall.h> #include <xenevtchn.h> -#include <xenctrl.h> +#include <xen/control.h> #include <xen/grant_table.h> -static xc_interface **xc_handle; +static xencall_handle **xc_handle; xengnttab_handle **xgt_handle; static evtchn_port_t virq_port; @@ -XXX,XX +XXX,XX @@ struct domain /* The id of this domain */ unsigned int domid; + uint64_t unique_id; /* Event channel port */ evtchn_port_t port; @@ -XXX,XX +XXX,XX @@ static int destroy_domain(void *_domain) return 0; } -static bool get_domain_info(unsigned int domid, xc_dominfo_t *dominfo) +static bool get_domain_info(struct xen_control_changed_domain *dominfo) { - return xc_domain_getinfo(*xc_handle, domid, 1, dominfo) == 1 && - dominfo->domid == domid; + struct xen_control_changed_domain *buf; + int ret; + + buf = xencall_alloc_buffer(*xc_handle, sizeof(*buf)); + if (!buf) + return false; + ret = xencall2(*xc_handle, __HYPERVISOR_control_op, + XEN_CONTROL_OP_get_state_changed_domain, + (unsigned long)buf); + *dominfo = *buf; + xencall_free_buffer(*xc_handle, buf); + + return ret == 0; } -void check_domains(void) +static struct domain *find_domain_struct(unsigned int domid) +{ + struct domain *i; + + list_for_each_entry(i, &domains, list) { + if (i->domid == domid) + return i; + } + return NULL; +} + +static struct domain *alloc_domain(unsigned int domid) { - xc_dominfo_t dominfo; struct domain *domain; + + domain = talloc_zero(talloc_autofree_context(), struct domain); + if (!domain) { + errno = ENOMEM; + return NULL; + } + + domain->domid = domid; + domain->generation = generation; + domain->introduced = false; + + talloc_set_destructor(domain, destroy_domain); + + list_add(&domain->list, &domains); + + return domain; +} + +static void domain_drop(struct domain *domain) +{ struct connection *conn; + + /* domain is a talloc child of domain->conn. */ + conn = domain->conn; + domain->conn = NULL; + talloc_unlink(talloc_autofree_context(), conn); +} + +void check_domains(void) +{ + struct xen_control_changed_domain dominfo; + struct domain *domain; int notify = 0; - bool dom_valid; - again: - list_for_each_entry(domain, &domains, list) { - dom_valid = get_domain_info(domain->domid, &dominfo); - if (!domain->introduced) { - if (!dom_valid) { + while (get_domain_info(&dominfo)) { + domain = find_domain_struct(dominfo.domid); + + if (!dominfo.state) { + if (domain && !domain->introduced) talloc_free(domain); - goto again; - } continue; } - if (dom_valid) { - if ((dominfo.crashed || dominfo.shutdown) - && !domain->shutdown) { - domain->shutdown = true; - notify = 1; - } - /* - * On Restore, we may have been unable to remap the - * interface and the port. As we don't know whether - * this was because of a dying domain, we need to - * check if the interface and port are still valid. - */ - if (!dominfo.dying && domain->port && - domain->interface) + + if (domain && domain->unique_id && + domain->unique_id != dominfo.unique_id) { + if (domain->conn) + domain_drop(domain); + else + talloc_free(domain); + domain = NULL; + } + + if (!domain) { + domain = alloc_domain(dominfo.domid); + if (!domain) continue; + domain->unique_id = dominfo.unique_id; } - if (domain->conn) { - /* domain is a talloc child of domain->conn. */ - conn = domain->conn; - domain->conn = NULL; - talloc_unlink(talloc_autofree_context(), conn); - notify = 0; /* destroy_domain() fires the watch */ - goto again; + + if ((dominfo.state & XEN_CONTROL_CHANGEDDOM_STATE_SHUTDOWN) && + !domain->shutdown) { + domain->shutdown = true; + notify = 1; } + + /* + * On Restore, we may have been unable to remap the + * interface and the port. As we don't know whether + * this was because of a dying domain, we need to + * check if the interface and port are still valid. + */ + if (!(dominfo.state & XEN_CONTROL_CHANGEDDOM_STATE_DYING) && + domain->port && domain->interface) + continue; + + if (domain->conn) + domain_drop(domain); } if (notify) @@ -XXX,XX +XXX,XX @@ static char *talloc_domain_path(void *context, unsigned int domid) return talloc_asprintf(context, "/local/domain/%u", domid); } -static struct domain *find_domain_struct(unsigned int domid) -{ - struct domain *i; - - list_for_each_entry(i, &domains, list) { - if (i->domid == domid) - return i; - } - return NULL; -} - -static struct domain *alloc_domain(const void *context, unsigned int domid) -{ - struct domain *domain; - - domain = talloc(context, struct domain); - if (!domain) { - errno = ENOMEM; - return NULL; - } - - domain->domid = domid; - domain->generation = generation; - domain->introduced = false; - - talloc_set_destructor(domain, destroy_domain); - - list_add(&domain->list, &domains); - - return domain; -} - -static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid) -{ - struct domain *domain; - - domain = find_domain_struct(domid); - return domain ? : alloc_domain(ctx, domid); -} - static int new_domain(struct domain *domain, int port, bool restore) { int rc; @@ -XXX,XX +XXX,XX @@ static struct domain *introduce_domain(const void *ctx, struct xenstore_domain_interface *interface; bool is_master_domain = (domid == xenbus_master_domid()); - domain = find_or_alloc_domain(ctx, domid); - if (!domain) + check_domains(); + + domain = find_domain_struct(domid); + if (!domain) { + errno = ENOENT; return NULL; + } if (!domain->introduced) { interface = is_master_domain ? xenbus_map() @@ -XXX,XX +XXX,XX @@ int do_reset_watches(struct connection *conn, struct buffered_data *in) static int close_xc_handle(void *_handle) { - xc_interface_close(*(xc_interface**)_handle); + xencall_close(*(xencall_handle **)_handle); return 0; } @@ -XXX,XX +XXX,XX @@ void domain_init(int evtfd) { int rc; - xc_handle = talloc(talloc_autofree_context(), xc_interface*); + xc_handle = talloc(talloc_autofree_context(), xencall_handle *); if (!xc_handle) barf_perror("Failed to allocate domain handle"); - *xc_handle = xc_interface_open(0,0,0); + *xc_handle = xencall_open(NULL, 0); if (!*xc_handle) barf_perror("Failed to open connection to hypervisor"); @@ -XXX,XX +XXX,XX @@ void domain_entry_inc(struct connection *conn, struct node *node) * count (used for testing whether a node permission is older than a domain). * * Return values: - * -1: error * 0: domain has higher generation count (it is younger than a node with the * given count), or domain isn't existing any longer * 1: domain is older than the node @@ -XXX,XX +XXX,XX @@ void domain_entry_inc(struct connection *conn, struct node *node) static int chk_domain_generation(unsigned int domid, uint64_t gen) { struct domain *d; - xc_dominfo_t dominfo; if (!xc_handle && domid == 0) return 1; @@ -XXX,XX +XXX,XX @@ static int chk_domain_generation(unsigned int domid, uint64_t gen) if (d) return (d->generation <= gen) ? 1 : 0; - if (!get_domain_info(domid, &dominfo)) - return 0; - - d = alloc_domain(NULL, domid); - return d ? 1 : -1; + check_domains(); + d = find_domain_struct(domid); + return (d && d->generation <= gen) ? 1 : 0; } /* @@ -XXX,XX +XXX,XX @@ int domain_adjust_node_perms(struct node *node) int ret; ret = chk_domain_generation(node->perms.p[0].id, node->generation); - if (ret < 0) - return errno; /* If the owner doesn't exist any longer give it to priv domain. */ if (!ret) @@ -XXX,XX +XXX,XX @@ int domain_adjust_node_perms(struct node *node) continue; ret = chk_domain_generation(node->perms.p[i].id, node->generation); - if (ret < 0) - return errno; if (!ret) node->perms.p[i].perms |= XS_PERM_IGNORE; } @@ -XXX,XX +XXX,XX @@ void read_state_connection(const void *ctx, const void *state) } else { domain = introduce_domain(ctx, sc->spec.ring.domid, sc->spec.ring.evtchn, true); - if (!domain) + if (!domain) { + /* Domain vanished during LM? */ + if (errno = ENOENT) + return; barf("domain allocation error"); + } if (sc->spec.ring.tdomid != DOMID_INVALID) { - tdomain = find_or_alloc_domain(ctx, - sc->spec.ring.tdomid); - if (!tdomain) + tdomain = find_domain_struct(sc->spec.ring.tdomid); + if (!tdomain && errno != ENOENT) barf("target domain allocation error"); - talloc_reference(domain->conn, tdomain->conn); - domain->conn->target = tdomain->conn; + if (tdomain) { + talloc_reference(domain->conn, tdomain->conn); + domain->conn->target = tdomain->conn; + } } conn = domain->conn; } -- 2.26.2
Xenstored is using libxenctrl for only one purpose: to get information about state of domains. This patch series is removing that dependency by introducing a new stable interface which can be used by xenstored instead. There was a RFC series sent out 3 years ago, which I have taken as a base and by addressing all comments from back then. The main differences since that RFC series are: - Instead of introducing an new main hypercall for a stable management interface I have just added a new domctl sub-op, as requested in 2021. - I have added a new library libxenmanage for easy use of the new stable hypervisor interface. Main motivation for adding the library was the recent attempt to decouple oxenstored from the Xen git tree. By using the new library, oxenstored could benefit in the same way as xenstored from the new interface: it would be possible to rely on stable libraries only. - Mini-OS has gained some more config options recently, so it was rather easy to make xenstore[pvh]-stubdom independent from libxenctrl, too. - By moving the CPU barrier definitions out of xenctrl.h into a new dedicated header xenstored code no longer needs to #include xenctrl.h, thus removing any xenctrl reference from xenstored code. Please note that the last patch can be committed only after the related Mini-OS patch "config: add support for libxenmanage" has gone in AND the Mini-OS commit-id has been updated in Config.mk accordingly! Juergen Gross (6): xen: add a domain unique id to each domain xen: add bitmap to indicate per-domain state changes xen: add new domctl get_changed_domain tools/libs: add a new libxenmanage library tools: add a dedicated header file for barrier definitions tools/xenstored: use new stable interface instead of libxenctrl stubdom/Makefile | 8 +- stubdom/mini-os.mk | 1 + tools/9pfsd/io.c | 5 +- tools/flask/policy/modules/dom0.te | 2 +- tools/include/xen-barrier.h | 51 +++++++++ tools/include/xenctrl.h | 28 +---- tools/include/xenmanage.h | 98 ++++++++++++++++ tools/libs/Makefile | 1 + tools/libs/ctrl/Makefile | 2 +- tools/libs/manage/Makefile | 10 ++ tools/libs/manage/Makefile.common | 1 + tools/libs/manage/core.c | 170 ++++++++++++++++++++++++++++ tools/libs/manage/libxenmanage.map | 8 ++ tools/libs/uselibs.mk | 2 + tools/xenstored/Makefile | 2 +- tools/xenstored/Makefile.common | 2 +- tools/xenstored/core.h | 1 - tools/xenstored/domain.c | 52 ++++----- tools/xenstored/lu.c | 1 + tools/xenstored/lu_daemon.c | 1 + xen/common/domain.c | 92 +++++++++++++++ xen/common/domctl.c | 19 +++- xen/common/event_channel.c | 11 +- xen/include/public/domctl.h | 33 ++++++ xen/include/xen/event.h | 6 + xen/include/xen/sched.h | 7 ++ xen/include/xsm/dummy.h | 8 ++ xen/include/xsm/xsm.h | 6 + xen/xsm/dummy.c | 1 + xen/xsm/flask/hooks.c | 7 ++ xen/xsm/flask/policy/access_vectors | 2 + 31 files changed, 566 insertions(+), 72 deletions(-) create mode 100644 tools/include/xen-barrier.h create mode 100644 tools/include/xenmanage.h create mode 100644 tools/libs/manage/Makefile create mode 100644 tools/libs/manage/Makefile.common create mode 100644 tools/libs/manage/core.c create mode 100644 tools/libs/manage/libxenmanage.map -- 2.43.0
Xenstore is referencing domains by their domid, but reuse of a domid can lead to the situation that Xenstore can't tell whether a domain with that domid has been deleted and created again without Xenstore noticing the domain is a new one now. Add a global domain creation unique id which is updated when creating a new domain, and store that value in struct domain of the new domain. The global unique id is initialized with the system time and updates are done via the xorshift algorithm which is used for pseudo random number generation, too (see https://en.wikipedia.org/wiki/Xorshift). Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> --- V1: - make unique_id local to function (Jan Beulich) - add lock (Julien Grall) - add comment (Julien Grall) --- xen/common/domain.c | 20 ++++++++++++++++++++ xen/include/xen/sched.h | 3 +++ 2 files changed, 23 insertions(+) diff --git a/xen/common/domain.c b/xen/common/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -XXX,XX +XXX,XX @@ static void _domain_destroy(struct domain *d) free_domain_struct(d); } +static uint64_t get_unique_id(void) +{ + static uint64_t unique_id; + static DEFINE_SPINLOCK(lock); + uint64_t x = unique_id ? : NOW(); + + spin_lock(&lock); + + /* Pseudo-randomize id in order to avoid consumers relying on sequence. */ + x ^= x << 13; + x ^= x >> 7; + x ^= x << 17; + unique_id = x; + + spin_unlock(&lock); + + return x; +} + static int sanitise_domain_config(struct xen_domctl_createdomain *config) { bool hvm = config->flags & XEN_DOMCTL_CDF_hvm; @@ -XXX,XX +XXX,XX @@ struct domain *domain_create(domid_t domid, /* Sort out our idea of is_system_domain(). */ d->domain_id = domid; + d->unique_id = get_unique_id(); /* Holding CDF_* internal flags. */ d->cdf = flags; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ struct domain domid_t domain_id; unsigned int max_vcpus; + + uint64_t unique_id; /* Unique domain identifier */ + struct vcpu **vcpu; shared_info_t *shared_info; /* shared data area */ -- 2.43.0
Add a bitmap with one bit per possible domid indicating the respective domain has changed its state (created, deleted, dying, crashed, shutdown). Registering the VIRQ_DOM_EXC event will result in setting the bits for all existing domains and resetting all other bits. Resetting a bit will be done in a future patch. This information is needed for Xenstore to keep track of all domains. Signed-off-by: Juergen Gross <jgross@suse.com> --- xen/common/domain.c | 21 +++++++++++++++++++++ xen/common/event_channel.c | 2 ++ xen/include/xen/sched.h | 2 ++ 3 files changed, 25 insertions(+) diff --git a/xen/common/domain.c b/xen/common/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -XXX,XX +XXX,XX @@ bool __read_mostly vmtrace_available; bool __read_mostly vpmu_is_available; +static DECLARE_BITMAP(dom_state_changed, DOMID_MASK + 1); + +void domain_reset_states(void) +{ + struct domain *d; + + bitmap_zero(dom_state_changed, DOMID_MASK + 1); + + rcu_read_lock(&domlist_read_lock); + + for_each_domain ( d ) + set_bit(d->domain_id, dom_state_changed); + + rcu_read_unlock(&domlist_read_lock); +} + static void __domain_finalise_shutdown(struct domain *d) { struct vcpu *v; @@ -XXX,XX +XXX,XX @@ static void __domain_finalise_shutdown(struct domain *d) return; d->is_shut_down = 1; + set_bit(d->domain_id, dom_state_changed); if ( (d->shutdown_code == SHUTDOWN_suspend) && d->suspend_evtchn ) evtchn_send(d, d->suspend_evtchn); else @@ -XXX,XX +XXX,XX @@ struct domain *domain_create(domid_t domid, */ domlist_insert(d); + set_bit(d->domain_id, dom_state_changed); memcpy(d->handle, config->handle, sizeof(d->handle)); return d; @@ -XXX,XX +XXX,XX @@ int domain_kill(struct domain *d) /* Mem event cleanup has to go here because the rings * have to be put before we call put_domain. */ vm_event_cleanup(d); + set_bit(d->domain_id, dom_state_changed); put_domain(d); send_global_virq(VIRQ_DOM_EXC); /* fallthrough */ @@ -XXX,XX +XXX,XX @@ static void cf_check complete_domain_destroy(struct rcu_head *head) xfree(d->vcpu); + set_bit(d->domain_id, dom_state_changed); + _domain_destroy(d); send_global_virq(VIRQ_DOM_EXC); diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -XXX,XX +XXX,XX @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) rc = evtchn_bind_virq(&bind_virq, 0); if ( !rc && __copy_to_guest(arg, &bind_virq, 1) ) rc = -EFAULT; /* Cleaning up here would be a mess! */ + if ( !rc && bind_virq.virq == VIRQ_DOM_EXC ) + domain_reset_states(); break; } diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ void domain_resume(struct domain *d); int domain_soft_reset(struct domain *d, bool resuming); +void domain_reset_states(void); + int vcpu_start_shutdown_deferral(struct vcpu *v); void vcpu_end_shutdown_deferral(struct vcpu *v); -- 2.43.0
Add a new domctl sub-function to get data of a domain having changed state (this is needed by Xenstore). The returned state just contains the domid, the domain unique id, and some flags (existing, shutdown, dying). In order to enable Xenstore stubdom being built for multiple Xen versions, make this domctl stable. For stable domctls the interface_version is specific to the respective domctl op and it is an in/out parameter: On input the caller is specifying the desired version of the op, while on output the hypervisor will return the used version (this will be at max the caller supplied version, but might be lower in case the hypervisor doesn't support this version). Signed-off-by: Juergen Gross <jgross@suse.com> --- V1: - use a domctl subop for the new interface (Jan Beulich) --- tools/flask/policy/modules/dom0.te | 2 +- xen/common/domain.c | 51 +++++++++++++++++++++++++++++ xen/common/domctl.c | 19 ++++++++++- xen/common/event_channel.c | 9 ++++- xen/include/public/domctl.h | 33 +++++++++++++++++++ xen/include/xen/event.h | 6 ++++ xen/include/xen/sched.h | 2 ++ xen/include/xsm/dummy.h | 8 +++++ xen/include/xsm/xsm.h | 6 ++++ xen/xsm/dummy.c | 1 + xen/xsm/flask/hooks.c | 7 ++++ xen/xsm/flask/policy/access_vectors | 2 ++ 12 files changed, 143 insertions(+), 3 deletions(-) diff --git a/tools/flask/policy/modules/dom0.te b/tools/flask/policy/modules/dom0.te index XXXXXXX..XXXXXXX 100644 --- a/tools/flask/policy/modules/dom0.te +++ b/tools/flask/policy/modules/dom0.te @@ -XXX,XX +XXX,XX @@ allow dom0_t dom0_t:domain { }; allow dom0_t dom0_t:domain2 { set_cpu_policy gettsc settsc setscheduler set_vnumainfo - get_vnumainfo psr_cmt_op psr_alloc get_cpu_policy + get_vnumainfo psr_cmt_op psr_alloc get_cpu_policy get_domain_state }; allow dom0_t dom0_t:resource { add remove }; diff --git a/xen/common/domain.c b/xen/common/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -XXX,XX +XXX,XX @@ void domain_reset_states(void) rcu_read_unlock(&domlist_read_lock); } +static void set_domain_state_info(struct xen_domctl_get_domain_state *info, + const struct domain *d) +{ + info->state = XEN_DOMCTL_GETDOMSTATE_STATE_EXIST; + if ( d->is_shut_down ) + info->state |= XEN_DOMCTL_GETDOMSTATE_STATE_SHUTDOWN; + if ( d->is_dying == DOMDYING_dead ) + info->state |= XEN_DOMCTL_GETDOMSTATE_STATE_DYING; + info->unique_id = d->unique_id; +} + +int get_domain_state(struct xen_domctl_get_domain_state *info, struct domain *d) +{ + unsigned int dom; + + memset(info, 0, sizeof(*info)); + + if ( d ) + { + set_domain_state_info(info, d); + + return 0; + } + + while ( (dom = find_first_bit(dom_state_changed, DOMID_MASK + 1)) < + DOMID_FIRST_RESERVED ) + { + d = rcu_lock_domain_by_id(dom); + + if ( test_and_clear_bit(dom, dom_state_changed) ) + { + info->domid = dom; + if ( d ) + { + set_domain_state_info(info, d); + + rcu_unlock_domain(d); + } + + return 0; + } + + if ( d ) + { + rcu_unlock_domain(d); + } + } + + return -ENOENT; +} + static void __domain_finalise_shutdown(struct domain *d) { struct vcpu *v; diff --git a/xen/common/domctl.c b/xen/common/domctl.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -XXX,XX +XXX,XX @@ static struct vnuma_info *vnuma_init(const struct xen_domctl_vnuma *uinfo, return ERR_PTR(ret); } +static bool is_stable_domctl(uint32_t cmd) +{ + return cmd == XEN_DOMCTL_get_domain_state; +} + long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) { long ret = 0; @@ -XXX,XX +XXX,XX @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) if ( copy_from_guest(op, u_domctl, 1) ) return -EFAULT; - if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION ) + if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION && + !is_stable_domctl(op->cmd) ) return -EACCES; switch ( op->cmd ) @@ -XXX,XX +XXX,XX @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) fallthrough; case XEN_DOMCTL_test_assign_device: case XEN_DOMCTL_vm_event_op: + case XEN_DOMCTL_get_domain_state: if ( op->domain == DOMID_INVALID ) { d = NULL; @@ -XXX,XX +XXX,XX @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) __HYPERVISOR_domctl, "h", u_domctl); break; + case XEN_DOMCTL_get_domain_state: + ret = xsm_get_domain_state(XSM_HOOK, d); + if ( ret ) + break; + + copyback = 1; + op->interface_version = XEN_DOMCTL_GETDOMSTATE_VERS_MAX; + ret = get_domain_state(&op->u.get_domain_state, d); + break; + default: ret = arch_do_domctl(op, d, u_domctl); break; diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -XXX,XX +XXX,XX @@ static struct domain *global_virq_handlers[NR_VIRQS] __read_mostly; static DEFINE_SPINLOCK(global_virq_handlers_lock); +struct domain *get_global_virq_handler(uint32_t virq) +{ + ASSERT(virq_is_global(virq)); + + return global_virq_handlers[virq] ?: hardware_domain; +} + void send_global_virq(uint32_t virq) { ASSERT(virq_is_global(virq)); - send_guest_global_virq(global_virq_handlers[virq] ?: hardware_domain, virq); + send_guest_global_virq(get_global_virq_handler(virq), virq); } int set_global_virq_handler(struct domain *d, uint32_t virq) diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -XXX,XX +XXX,XX @@ * Pure additions (e.g. new sub-commands) or compatible interface changes * (e.g. adding semantics to 0-checked input fields or data to zeroed output * fields) don't require a change of the version. + * Stable ops are NOT covered by XEN_DOMCTL_INTERFACE_VERSION! * * Last version bump: Xen 4.19 */ @@ -XXX,XX +XXX,XX @@ struct xen_domctl_dt_overlay { }; #endif +/* + * XEN_DOMCTL_get_domain_state (stable interface) + * + * Get state information of a domain. + * + * In case domain is DOMID_INVALID, return information about a domain having + * changed state and reset the state change indicator for that domain. This + * function is usable only by a domain having registered the VIRQ_DOM_EXC + * event (normally Xenstore). + * + * Supported interface versions: 0x00000000 + */ +#define XEN_DOMCTL_GETDOMSTATE_VERS_MAX 0 +struct xen_domctl_get_domain_state { + domid_t domid; + uint16_t state; +#define XEN_DOMCTL_GETDOMSTATE_STATE_EXIST 0x0001 /* Domain is existing. */ +#define XEN_DOMCTL_GETDOMSTATE_STATE_SHUTDOWN 0x0002 /* Shutdown finished. */ +#define XEN_DOMCTL_GETDOMSTATE_STATE_DYING 0x0004 /* Domain dying. */ + uint32_t pad1; /* Returned as 0. */ + uint64_t unique_id; /* Unique domain identifier. */ + uint64_t pad2[6]; /* Returned as 0. */ +}; + struct xen_domctl { +/* + * Stable domctl ops: + * interface_version is per cmd, hypervisor can support multiple versions + * and will return used version (at max caller supplied value) in + * interface_version on return. + */ uint32_t cmd; #define XEN_DOMCTL_createdomain 1 #define XEN_DOMCTL_destroydomain 2 @@ -XXX,XX +XXX,XX @@ struct xen_domctl { #define XEN_DOMCTL_set_paging_mempool_size 86 #define XEN_DOMCTL_dt_overlay 87 #define XEN_DOMCTL_gsi_permission 88 +#define XEN_DOMCTL_get_domain_state 89 /* stable interface */ #define XEN_DOMCTL_gdbsx_guestmemio 1000 #define XEN_DOMCTL_gdbsx_pausevcpu 1001 #define XEN_DOMCTL_gdbsx_unpausevcpu 1002 @@ -XXX,XX +XXX,XX @@ struct xen_domctl { #if defined(__arm__) || defined(__aarch64__) struct xen_domctl_dt_overlay dt_overlay; #endif + struct xen_domctl_get_domain_state get_domain_state; uint8_t pad[128]; } u; }; diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -XXX,XX +XXX,XX @@ void send_guest_global_virq(struct domain *d, uint32_t virq); */ int set_global_virq_handler(struct domain *d, uint32_t virq); +/* + * get_global_virq_handler: Get domain handling a global virq. + * @virq: Virtual IRQ number (VIRQ_*), must be global + */ +struct domain *get_global_virq_handler(uint32_t virq); + /* * send_guest_pirq: * @d: Domain to which physical IRQ should be sent diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ void domain_resume(struct domain *d); int domain_soft_reset(struct domain *d, bool resuming); void domain_reset_states(void); +int get_domain_state(struct xen_domctl_get_domain_state *info, + struct domain *d); int vcpu_start_shutdown_deferral(struct vcpu *v); void vcpu_end_shutdown_deferral(struct vcpu *v); diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -XXX,XX +XXX,XX @@ static XSM_INLINE int cf_check xsm_domctl( case XEN_DOMCTL_unbind_pt_irq: return xsm_default_action(XSM_DM_PRIV, current->domain, d); case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_get_domain_state: return xsm_default_action(XSM_XS_PRIV, current->domain, d); default: return xsm_default_action(XSM_PRIV, current->domain, d); @@ -XXX,XX +XXX,XX @@ static XSM_INLINE int cf_check xsm_argo_send( #endif /* CONFIG_ARGO */ +static XSM_INLINE int cf_check xsm_get_domain_state( + XSM_DEFAULT_ARG struct domain *d) +{ + XSM_ASSERT_ACTION(XSM_HOOK); + return xsm_default_action(action, current->domain, d); +} + #include <public/version.h> static XSM_INLINE int cf_check xsm_xen_version(XSM_DEFAULT_ARG uint32_t op) { diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -XXX,XX +XXX,XX @@ struct xsm_ops { int (*argo_register_any_source)(const struct domain *d); int (*argo_send)(const struct domain *d, const struct domain *t); #endif + int (*get_domain_state)(struct domain *d); }; #ifdef CONFIG_XSM @@ -XXX,XX +XXX,XX @@ static inline int xsm_argo_send(const struct domain *d, const struct domain *t) #endif /* CONFIG_ARGO */ +static inline int xsm_get_domain_state(struct domain *d) +{ + return alternative_call(xsm_ops.get_domain_state, d); +} + #endif /* XSM_NO_WRAPPERS */ #ifdef CONFIG_MULTIBOOT diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index XXXXXXX..XXXXXXX 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -XXX,XX +XXX,XX @@ static const struct xsm_ops __initconst_cf_clobber dummy_ops = { .argo_register_any_source = xsm_argo_register_any_source, .argo_send = xsm_argo_send, #endif + .get_domain_state = xsm_get_domain_state, }; void __init xsm_fixup_ops(struct xsm_ops *ops) diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index XXXXXXX..XXXXXXX 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -XXX,XX +XXX,XX @@ static int cf_check flask_domctl(struct domain *d, unsigned int cmd, case XEN_DOMCTL_memory_mapping: case XEN_DOMCTL_set_target: case XEN_DOMCTL_vm_event_op: + case XEN_DOMCTL_get_domain_state: /* These have individual XSM hooks (arch/../domctl.c) */ case XEN_DOMCTL_bind_pt_irq: @@ -XXX,XX +XXX,XX @@ static int cf_check flask_argo_send( #endif +static int cf_check flask_get_domain_state(struct domain *d) +{ + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GET_DOMAIN_STATE); +} + static const struct xsm_ops __initconst_cf_clobber flask_ops = { .set_system_active = flask_set_system_active, .security_domaininfo = flask_security_domaininfo, @@ -XXX,XX +XXX,XX @@ static const struct xsm_ops __initconst_cf_clobber flask_ops = { .argo_register_any_source = flask_argo_register_any_source, .argo_send = flask_argo_send, #endif + .get_domain_state = flask_get_domain_state, }; const struct xsm_ops *__init flask_init( diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index XXXXXXX..XXXXXXX 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -XXX,XX +XXX,XX @@ class domain2 resource_map # XEN_DOMCTL_get_cpu_policy get_cpu_policy +# XEN_DOMCTL_get_domain_state + get_domain_state } # Similar to class domain, but primarily contains domctls related to HVM domains -- 2.43.0
In order to have a stable interface in user land for using stable domctl and possibly later sysctl interfaces, add a new library libxenmanage. Signed-off-by: Juergen Gross <jgross@suse.com> --- V1: - new patch --- tools/include/xenmanage.h | 98 +++++++++++++++++ tools/libs/Makefile | 1 + tools/libs/manage/Makefile | 10 ++ tools/libs/manage/Makefile.common | 1 + tools/libs/manage/core.c | 170 +++++++++++++++++++++++++++++ tools/libs/manage/libxenmanage.map | 8 ++ tools/libs/uselibs.mk | 2 + 7 files changed, 290 insertions(+) create mode 100644 tools/include/xenmanage.h create mode 100644 tools/libs/manage/Makefile create mode 100644 tools/libs/manage/Makefile.common create mode 100644 tools/libs/manage/core.c create mode 100644 tools/libs/manage/libxenmanage.map diff --git a/tools/include/xenmanage.h b/tools/include/xenmanage.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/include/xenmanage.h @@ -XXX,XX +XXX,XX @@ +/* + * Copyright (c) 2024 SUSE Software Solutions Germany GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef XENMANAGE_H +#define XENMANAGE_H + +#include <stdint.h> + +/* Callers who don't care don't need to #include <xentoollog.h> */ +struct xentoollog_logger; + +typedef struct xenmanage_handle xenmanage_handle; + +/* + * Open libxenmanage. + * + * Get a handle of the xenmanage library. The handle is required for all + * further operations of the library. + * Parameters: + * logger: Logging function to use. If NULL logging is done to stderr. + * open_flags: Only 0 supported. + * Return value: Handle or NULL if error. + */ +xenmanage_handle *xenmanage_open(struct xentoollog_logger *logger, + unsigned int open_flags); + +/* + * Close libxenmanage. + * + * Return a handle of the xenmanage library. + * Parameters: + * hdl: Handle obtained by xenmanage_open(). + * Return value: always 0. + */ +int xenmanage_close(xenmanage_handle *hdl); + +#define XENMANAGE_GETDOMSTATE_STATE_EXIST 0x0001 /* Domain is existing. */ +#define XENMANAGE_GETDOMSTATE_STATE_SHUTDOWN 0x0002 /* Shutdown finished. */ +#define XENMANAGE_GETDOMSTATE_STATE_DYING 0x0004 /* Domain dying. */ + +/* + * Return state information of an existing domain. + * + * Returns the domain state and unique id of the given domain. + * Parameters: + * hdl: handle returned by xenmanage_open() + * domid: domain id of the domain to get the information for + * state: where to store the state (XENMANAGE_GETDOMSTATE_STATE_ flags, + * nothing stored if NULL) + * unique_id: where to store the unique id of the domain (nothing stored if + * NULL) + * Return value: 0 if information was stored, -1 else (errno is set) + */ +int xenmanage_get_domain_info(xenmanage_handle *hdl, unsigned int domid, + unsigned int *state, uint64_t *unique_id); + +/* + * Return information of a domain having changed state recently. + * + * Returns the domain id, state and unique id of a domain having changed + * state (any of the state bits was modified) since the last time information + * for that domain was returned by this function. Only usable by callers who + * have registered the VIRQ_DOM_EXC event (normally Xenstore). + * Parameters: + * hdl: handle returned by xenmanage_open() + * domid: where to store the domid of the domain (not NULL) + * state: where to store the state (XENMANAGE_GETDOMSTATE_STATE_ flags, + * nothing stored if NULL) + * unique_id: where to store the unique id of the domain (nothing stored if + * NULL) + * Return value: 0 if information was stored, -1 else (errno is set) + */ +int xenmanage_get_changed_domain(xenmanage_handle *hdl, unsigned int *domid, + unsigned int *state, uint64_t *unique_id); +#endif /* XENMANAGE_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/libs/Makefile b/tools/libs/Makefile index XXXXXXX..XXXXXXX 100644 --- a/tools/libs/Makefile +++ b/tools/libs/Makefile @@ -XXX,XX +XXX,XX @@ SUBDIRS-y += devicemodel SUBDIRS-y += ctrl SUBDIRS-y += guest SUBDIRS-y += hypfs +SUBDIRS-y += manage SUBDIRS-y += store SUBDIRS-y += stat SUBDIRS-$(CONFIG_Linux) += vchan diff --git a/tools/libs/manage/Makefile b/tools/libs/manage/Makefile new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/libs/manage/Makefile @@ -XXX,XX +XXX,XX @@ +XEN_ROOT = $(CURDIR)/../../.. +include $(XEN_ROOT)/tools/Rules.mk + +MAJOR = 1 +MINOR = 0 +version-script := libxenmanage.map + +include Makefile.common + +include $(XEN_ROOT)/tools/libs/libs.mk diff --git a/tools/libs/manage/Makefile.common b/tools/libs/manage/Makefile.common new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/libs/manage/Makefile.common @@ -0,0 +1 @@ +OBJS-y += core.o diff --git a/tools/libs/manage/core.c b/tools/libs/manage/core.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/libs/manage/core.c @@ -XXX,XX +XXX,XX @@ +/* + * Copyright (c) 2024 SUSE Software Solutions Germany GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see <http://www.gnu.org/licenses/>. + */ + +#define __XEN_TOOLS__ 1 + +#define _GNU_SOURCE + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <xentoollog.h> +#include <xenmanage.h> +#include <xencall.h> +#include <xentoolcore_internal.h> + +#include <xen/xen.h> +#include <xen/domctl.h> + +struct xenmanage_handle { + xentoollog_logger *logger, *logger_tofree; + unsigned int flags; + xencall_handle *xcall; +}; + +xenmanage_handle *xenmanage_open(xentoollog_logger *logger, + unsigned open_flags) +{ + xenmanage_handle *hdl = calloc(1, sizeof(*hdl)); + int saved_errno; + + if ( !hdl ) + return NULL; + + if ( open_flags ) + { + errno = EINVAL; + goto err; + } + + hdl->flags = open_flags; + hdl->logger = logger; + hdl->logger_tofree = NULL; + + if ( !hdl->logger ) + { + hdl->logger = hdl->logger_tofree = + (xentoollog_logger *) + xtl_createlogger_stdiostream(stderr, XTL_PROGRESS, 0); + if ( !hdl->logger ) + goto err; + } + + hdl->xcall = xencall_open(hdl->logger, 0); + if ( !hdl->xcall ) + goto err; + + return hdl; + +err: + saved_errno = errno; + xenmanage_close(hdl); + errno = saved_errno; + + return NULL; +} + +int xenmanage_close(xenmanage_handle *hdl) +{ + if ( !hdl ) + return 0; + + xencall_close(hdl->xcall); + xtl_logger_destroy(hdl->logger_tofree); + free(hdl); + return 0; +} + +static int xenmanage_do_domctl_get_domain_state(xenmanage_handle *hdl, + unsigned int domid_in, + unsigned int *domid_out, + unsigned int *state, + uint64_t *unique_id) +{ + struct xen_domctl *buf; + struct xen_domctl_get_domain_state *st; + int saved_errno; + int ret; + + buf = xencall_alloc_buffer(hdl->xcall, sizeof(*buf)); + if ( !buf ) + { + errno = ENOMEM; + return -1; + } + + memset(buf, 0, sizeof(*buf)); + + buf->cmd = XEN_DOMCTL_get_domain_state; + buf->interface_version = XEN_DOMCTL_GETDOMSTATE_VERS_MAX; + buf->domain = domid_in; + + ret = xencall1(hdl->xcall, __HYPERVISOR_domctl, (unsigned long)buf); + saved_errno = errno; + if ( !ret ) + { + st = &buf->u.get_domain_state; + + if ( domid_out ) + *domid_out = st->domid; + if ( state ) + { + *state = 0; + if ( st->state & XEN_DOMCTL_GETDOMSTATE_STATE_EXIST ) + *state |= XENMANAGE_GETDOMSTATE_STATE_EXIST; + if ( st->state & XEN_DOMCTL_GETDOMSTATE_STATE_SHUTDOWN ) + *state |= XENMANAGE_GETDOMSTATE_STATE_SHUTDOWN; + if ( st->state & XEN_DOMCTL_GETDOMSTATE_STATE_DYING ) + *state |= XENMANAGE_GETDOMSTATE_STATE_DYING; + } + if ( unique_id ) + *unique_id = st->unique_id; + } + + xencall_free_buffer(hdl->xcall, buf); + + errno = saved_errno; + + return ret; +} + +int xenmanage_get_domain_info(xenmanage_handle *hdl, unsigned int domid, + unsigned int *state, uint64_t *unique_id) +{ + if ( !hdl || domid >= DOMID_FIRST_RESERVED ) + { + errno = EINVAL; + return -1; + } + + return xenmanage_do_domctl_get_domain_state(hdl, domid, NULL, state, + unique_id); +} + +int xenmanage_get_changed_domain(xenmanage_handle *hdl, unsigned int *domid, + unsigned int *state, uint64_t *unique_id) +{ + if ( !hdl || !domid ) + { + errno = EINVAL; + return -1; + } + + return xenmanage_do_domctl_get_domain_state(hdl, DOMID_INVALID, domid, + state, unique_id); +} diff --git a/tools/libs/manage/libxenmanage.map b/tools/libs/manage/libxenmanage.map new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/libs/manage/libxenmanage.map @@ -XXX,XX +XXX,XX @@ +VERS_1.0 { + global: + xenmanage_open; + xenmanage_close; + xenmanage_get_domain_info; + xenmanage_get_changed_domain; + local: *; /* Do not expose anything by default */ +}; diff --git a/tools/libs/uselibs.mk b/tools/libs/uselibs.mk index XXXXXXX..XXXXXXX 100644 --- a/tools/libs/uselibs.mk +++ b/tools/libs/uselibs.mk @@ -XXX,XX +XXX,XX @@ LIBS_LIBS += devicemodel USELIBS_devicemodel := toollog toolcore call LIBS_LIBS += hypfs USELIBS_hypfs := toollog toolcore call +LIBS_LIBS += manage +USELIBS_manage := toollog toolcore call LIBS_LIBS += ctrl USELIBS_ctrl := toollog call evtchn gnttab foreignmemory devicemodel LIBS_LIBS += guest -- 2.43.0
Instead of having to include xenctrl.h for getting definitions of cpu barriers, add a dedicated header for that purpose. Switch the xen-9pfsd daemon to use the new header instead of xenctrl.h. This is in preparation of making Xenstore independent from libxenctrl. Signed-off-by: Juergen Gross <jgross@suse.com> --- V1: - new patch --- tools/9pfsd/io.c | 5 +++- tools/include/xen-barrier.h | 51 +++++++++++++++++++++++++++++++++++++ tools/include/xenctrl.h | 28 +------------------- tools/libs/ctrl/Makefile | 2 +- 4 files changed, 57 insertions(+), 29 deletions(-) create mode 100644 tools/include/xen-barrier.h diff --git a/tools/9pfsd/io.c b/tools/9pfsd/io.c index XXXXXXX..XXXXXXX 100644 --- a/tools/9pfsd/io.c +++ b/tools/9pfsd/io.c @@ -XXX,XX +XXX,XX @@ #include <assert.h> #include <errno.h> +#include <stdarg.h> #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <syslog.h> +#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <fcntl.h> -#include <xenctrl.h> /* For cpu barriers. */ +#include <xen-barrier.h> #include <xen-tools/common-macros.h> #include "xen-9pfsd.h" diff --git a/tools/include/xen-barrier.h b/tools/include/xen-barrier.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/include/xen-barrier.h @@ -XXX,XX +XXX,XX @@ +/****************************************************************************** + * xen-barrier.h + * + * Definition of CPU barriers, part of libxenctrl. + * + * Copyright (c) 2003-2004, K A Fraser. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef XENBARRIER_H +#define XENBARRIER_H + +/* + * DEFINITIONS FOR CPU BARRIERS + */ + +#define xen_barrier() asm volatile ( "" : : : "memory") + +#if defined(__i386__) +#define xen_mb() asm volatile ( "lock addl $0, -4(%%esp)" ::: "memory" ) +#define xen_rmb() xen_barrier() +#define xen_wmb() xen_barrier() +#elif defined(__x86_64__) +#define xen_mb() asm volatile ( "lock addl $0, -32(%%rsp)" ::: "memory" ) +#define xen_rmb() xen_barrier() +#define xen_wmb() xen_barrier() +#elif defined(__arm__) +#define xen_mb() asm volatile ("dmb" : : : "memory") +#define xen_rmb() asm volatile ("dmb" : : : "memory") +#define xen_wmb() asm volatile ("dmb" : : : "memory") +#elif defined(__aarch64__) +#define xen_mb() asm volatile ("dmb sy" : : : "memory") +#define xen_rmb() asm volatile ("dmb sy" : : : "memory") +#define xen_wmb() asm volatile ("dmb sy" : : : "memory") +#else +#error "Define barriers" +#endif + +#endif /* XENBARRIER_H */ diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index XXXXXXX..XXXXXXX 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -XXX,XX +XXX,XX @@ #include <xen/platform.h> #include "xentoollog.h" +#include "xen-barrier.h" #if defined(__i386__) || defined(__x86_64__) #include <xen/foreign/x86_32.h> @@ -XXX,XX +XXX,XX @@ #define INVALID_MFN (~0UL) -/* - * DEFINITIONS FOR CPU BARRIERS - */ - -#define xen_barrier() asm volatile ( "" : : : "memory") - -#if defined(__i386__) -#define xen_mb() asm volatile ( "lock addl $0, -4(%%esp)" ::: "memory" ) -#define xen_rmb() xen_barrier() -#define xen_wmb() xen_barrier() -#elif defined(__x86_64__) -#define xen_mb() asm volatile ( "lock addl $0, -32(%%rsp)" ::: "memory" ) -#define xen_rmb() xen_barrier() -#define xen_wmb() xen_barrier() -#elif defined(__arm__) -#define xen_mb() asm volatile ("dmb" : : : "memory") -#define xen_rmb() asm volatile ("dmb" : : : "memory") -#define xen_wmb() asm volatile ("dmb" : : : "memory") -#elif defined(__aarch64__) -#define xen_mb() asm volatile ("dmb sy" : : : "memory") -#define xen_rmb() asm volatile ("dmb sy" : : : "memory") -#define xen_wmb() asm volatile ("dmb sy" : : : "memory") -#else -#error "Define barriers" -#endif - - #define XENCTRL_HAS_XC_INTERFACE 1 /* In Xen 4.0 and earlier, xc_interface_open and xc_evtchn_open would * both return ints being the file descriptor. In 4.1 and later, they diff --git a/tools/libs/ctrl/Makefile b/tools/libs/ctrl/Makefile index XXXXXXX..XXXXXXX 100644 --- a/tools/libs/ctrl/Makefile +++ b/tools/libs/ctrl/Makefile @@ -XXX,XX +XXX,XX @@ include $(XEN_ROOT)/tools/Rules.mk include Makefile.common -LIBHEADER := xenctrl.h xenctrl_compat.h +LIBHEADER := xenctrl.h xenctrl_compat.h xen-barrier.h PKG_CONFIG_FILE := xencontrol.pc PKG_CONFIG_NAME := Xencontrol -- 2.43.0
Replace the current use of the unstable xc_domain_getinfo_single() interface with the stable domctl XEN_DOMCTL_get_domain_state call via the new libxenmanage library. This will remove the last usage of libxenctrl by Xenstore, so update the library dependencies accordingly. For now only do a direct replacement without using the functionality of obtaining information about domains having changed the state. Signed-off-by: Juergen Gross <jgross@suse.com> --- V1: - use library instead of direct hypercall, only replace current libxenctrl use case Please note that this patch can be committed only after the related Mini-OS patch "config: add support for libxenmanage" has gone in AND the Mini-OS commit-id has been updated in Config.mk accordingly! --- stubdom/Makefile | 8 ++--- stubdom/mini-os.mk | 1 + tools/xenstored/Makefile | 2 +- tools/xenstored/Makefile.common | 2 +- tools/xenstored/core.h | 1 - tools/xenstored/domain.c | 52 ++++++++++++--------------------- tools/xenstored/lu.c | 1 + tools/xenstored/lu_daemon.c | 1 + 8 files changed, 28 insertions(+), 40 deletions(-) diff --git a/stubdom/Makefile b/stubdom/Makefile index XXXXXXX..XXXXXXX 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -XXX,XX +XXX,XX @@ endif # libraries under tools/libs ####### -STUB_LIBS := toolcore toollog evtchn gnttab call foreignmemory devicemodel ctrl guest +STUB_LIBS := toolcore toollog evtchn gnttab call foreignmemory devicemodel ctrl guest manage LIBDEP_guest := cross-zlib @@ -XXX,XX +XXX,XX @@ grub: cross-polarssl grub-upstream $(CROSS_ROOT) grub-$(XEN_TARGET_ARCH)-minios- # xenstore ########## -xenstore-minios.gen.cfg: APP_LIBS = gnttab evtchn toollog ctrl +xenstore-minios.gen.cfg: APP_LIBS = gnttab evtchn toollog manage xenstore-minios.gen.cfg: xenstore-minios.cfg Makefile $(GEN_config) >$@ @@ -XXX,XX +XXX,XX @@ xenstore: $(CROSS_ROOT) xenstore-minios-config.mk # xenstorepvh ############# -xenstorepvh-minios.gen.cfg: APP_LIBS = gnttab evtchn toollog ctrl +xenstorepvh-minios.gen.cfg: APP_LIBS = gnttab evtchn toollog manage xenstorepvh-minios.gen.cfg: xenstorepvh-minios.cfg Makefile $(GEN_config) >$@ @@ -XXX,XX +XXX,XX @@ else pv-grub-if-enabled: endif -XENSTORE_DEPS := libxenevtchn libxengnttab libxenctrl +XENSTORE_DEPS := libxenevtchn libxengnttab libxenmanage .PHONY: xenstore-stubdom xenstore-stubdom: mini-os-$(XEN_TARGET_ARCH)-xenstore $(XENSTORE_DEPS) xenstore diff --git a/stubdom/mini-os.mk b/stubdom/mini-os.mk index XXXXXXX..XXXXXXX 100644 --- a/stubdom/mini-os.mk +++ b/stubdom/mini-os.mk @@ -XXX,XX +XXX,XX @@ GNTTAB_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/gnttab CALL_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/call FOREIGNMEMORY_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/foreignmemory DEVICEMODEL_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/devicemodel +MANAGE_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/manage CTRL_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/ctrl GUEST_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/guest diff --git a/tools/xenstored/Makefile b/tools/xenstored/Makefile index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstored/Makefile +++ b/tools/xenstored/Makefile @@ -XXX,XX +XXX,XX @@ include Makefile.common xenstored: LDLIBS += $(LDLIBS_libxenevtchn) xenstored: LDLIBS += $(LDLIBS_libxengnttab) -xenstored: LDLIBS += $(LDLIBS_libxenctrl) +xenstored: LDLIBS += $(LDLIBS_libxenmanage) xenstored: LDLIBS += -lrt xenstored: LDLIBS += $(SOCKET_LIBS) diff --git a/tools/xenstored/Makefile.common b/tools/xenstored/Makefile.common index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstored/Makefile.common +++ b/tools/xenstored/Makefile.common @@ -XXX,XX +XXX,XX @@ XENSTORED_OBJS-$(CONFIG_MiniOS) += minios.o lu_minios.o # Include configure output (config.h) CFLAGS += -include $(XEN_ROOT)/tools/config.h CFLAGS += $(CFLAGS_libxenevtchn) -CFLAGS += $(CFLAGS_libxenctrl) +CFLAGS += $(CFLAGS_libxenmanage) CFLAGS += $(CFLAGS_libxentoolcore) $(XENSTORED_OBJS-y): CFLAGS += $(CFLAGS_libxengnttab) diff --git a/tools/xenstored/core.h b/tools/xenstored/core.h index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstored/core.h +++ b/tools/xenstored/core.h @@ -XXX,XX +XXX,XX @@ #ifndef _XENSTORED_CORE_H #define _XENSTORED_CORE_H -#include <xenctrl.h> #include <xengnttab.h> #include <sys/types.h> diff --git a/tools/xenstored/domain.c b/tools/xenstored/domain.c index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstored/domain.c +++ b/tools/xenstored/domain.c @@ -XXX,XX +XXX,XX @@ #include "control.h" #include <xenevtchn.h> -#include <xenctrl.h> +#include <xenmanage.h> +#include <xen-barrier.h> #include <xen/grant_table.h> #ifdef __MINIOS__ #include <mini-os/xenbus.h> #endif -static xc_interface **xc_handle; +static xenmanage_handle *xm_handle; xengnttab_handle **xgt_handle; static evtchn_port_t virq_port; @@ -XXX,XX +XXX,XX @@ static int destroy_domain(void *_domain) return 0; } -static bool get_domain_info(unsigned int domid, xc_domaininfo_t *dominfo) -{ - return xc_domain_getinfo_single(*xc_handle, domid, dominfo) == 0; -} - static int check_domain(const void *k, void *v, void *arg) { - xc_domaininfo_t dominfo; + unsigned int state; struct connection *conn; - bool dom_valid; + int dom_invalid; struct domain *domain = v; bool *notify = arg; - dom_valid = get_domain_info(domain->domid, &dominfo); + dom_invalid = xenmanage_get_domain_info(xm_handle, domain->domid, + &state, NULL); if (!domain->introduced) { - if (!dom_valid) + if (dom_invalid) talloc_free(domain); return 0; } - if (dom_valid) { - if ((dominfo.flags & XEN_DOMINF_shutdown) + if (!dom_invalid) { + if ((state & XENMANAGE_GETDOMSTATE_STATE_SHUTDOWN) && !domain->shutdown) { domain->shutdown = true; *notify = true; } - if (!(dominfo.flags & XEN_DOMINF_dying)) + if (!(state & XENMANAGE_GETDOMSTATE_STATE_DYING)) return 0; } if (domain->conn) { @@ -XXX,XX +XXX,XX @@ static struct domain *find_or_alloc_domain(const void *ctx, unsigned int domid) static struct domain *find_or_alloc_existing_domain(unsigned int domid) { struct domain *domain; - xc_domaininfo_t dominfo; domain = find_domain_struct(domid); - if (!domain && get_domain_info(domid, &dominfo)) + if (!domain && !xenmanage_get_domain_info(xm_handle, domid, NULL, NULL)) domain = alloc_domain(NULL, domid); return domain; @@ -XXX,XX +XXX,XX @@ int do_reset_watches(const void *ctx, struct connection *conn, return 0; } -static int close_xc_handle(void *_handle) -{ - xc_interface_close(*(xc_interface**)_handle); - return 0; -} - static int close_xgt_handle(void *_handle) { xengnttab_close(*(xengnttab_handle **)_handle); @@ -XXX,XX +XXX,XX @@ void domain_early_init(void) if (!domhash) barf_perror("Failed to allocate domain hashtable"); - xc_handle = talloc(talloc_autofree_context(), xc_interface*); - if (!xc_handle) - barf_perror("Failed to allocate domain handle"); - - *xc_handle = xc_interface_open(0,0,0); - if (!*xc_handle) - barf_perror("Failed to open connection to hypervisor"); - - talloc_set_destructor(xc_handle, close_xc_handle); + xm_handle = xenmanage_open(NULL, 0); + if (!xm_handle) + barf_perror("Failed to open connection to libxenmanage"); xgt_handle = talloc(talloc_autofree_context(), xengnttab_handle*); if (!xgt_handle) @@ -XXX,XX +XXX,XX @@ void domain_deinit(void) { if (virq_port) xenevtchn_unbind(xce_handle, virq_port); + + xenmanage_close(xm_handle); } /* @@ -XXX,XX +XXX,XX @@ int domain_alloc_permrefs(struct node_perms *perms) { unsigned int i, domid; struct domain *d; - xc_domaininfo_t dominfo; for (i = 0; i < perms->num; i++) { domid = perms->p[i].id; d = find_domain_struct(domid); if (!d) { - if (!get_domain_info(domid, &dominfo)) + if (xenmanage_get_domain_info(xm_handle, domid, + NULL, NULL)) perms->p[i].perms |= XS_PERM_IGNORE; else if (!alloc_domain(NULL, domid)) return ENOMEM; diff --git a/tools/xenstored/lu.c b/tools/xenstored/lu.c index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstored/lu.c +++ b/tools/xenstored/lu.c @@ -XXX,XX +XXX,XX @@ #include <stdlib.h> #include <syslog.h> #include <time.h> +#include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> diff --git a/tools/xenstored/lu_daemon.c b/tools/xenstored/lu_daemon.c index XXXXXXX..XXXXXXX 100644 --- a/tools/xenstored/lu_daemon.c +++ b/tools/xenstored/lu_daemon.c @@ -XXX,XX +XXX,XX @@ */ #include <syslog.h> +#include <unistd.h> #include <sys/stat.h> #include "talloc.h" -- 2.43.0