xen: add new domctl get_domain_state

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 always 0.

Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Juergen Gross authored and Jan Beulich committed 2025-03-06 13:52:38 +01:00
1 parent f94360a7fe
commit 3ad3df1bd0
12 files changed
+148 -3

No files matched your search

+1
View File
@@ -41,6 +41,7 @@ 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 dt_overlay
get_domain_state
};
allow dom0_t dom0_t:resource { add remove };
+3 -2
View File
@@ -54,7 +54,8 @@ define(`create_domain_common', `
allow $1 $2:domain2 { set_cpu_policy settsc setscheduler setclaim
set_vnumainfo get_vnumainfo cacheflush
psr_cmt_op psr_alloc soft_reset
resource_map get_cpu_policy vuart_op set_llc_colors };
resource_map get_cpu_policy vuart_op set_llc_colors
get_domain_state };
allow $1 $2:security check_context;
allow $1 $2:shadow enable;
allow $1 $2:mmu { map_read map_write adjust memorymap physmap pinpage mmuext_op updatemp };
@@ -94,7 +95,7 @@ define(`manage_domain', `
getaddrsize pause unpause trigger shutdown destroy
setaffinity setdomainmaxmem getscheduler resume
setpodtarget getpodtarget getpagingmempool setpagingmempool };
allow $1 $2:domain2 { set_vnumainfo dt_overlay };
allow $1 $2:domain2 { set_vnumainfo dt_overlay get_domain_state };
')
# migrate_domain_out(priv, target)
+1
View File
@@ -13,6 +13,7 @@ allow dom0_t xenstore_t:domain set_virq_handler;
allow xenstore_t xen_t:xen writeconsole;
# Xenstore queries domaininfo on all domains
allow xenstore_t domain_type:domain getdomaininfo;
allow xenstore_t domain_type:domain2 get_domain_state;
# As a shortcut, the following 3 rules are used instead of adding a domain_comms
# rule between xenstore_t and every domain type that talks to xenstore
+74
View File
@@ -185,6 +185,80 @@ static void domain_changed_state(const struct domain *d)
unlock_dom_exc_handler(hdl);
}
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_dying )
info->state |= XEN_DOMCTL_GETDOMSTATE_STATE_DYING;
if ( d->is_dying == DOMDYING_dead )
info->state |= XEN_DOMCTL_GETDOMSTATE_STATE_DEAD;
info->unique_id = d->unique_id;
}
int get_domain_state(struct xen_domctl_get_domain_state *info, struct domain *d,
domid_t *domid)
{
unsigned int dom;
int rc = -ENOENT;
struct domain *hdl;
if ( info->pad0 || info->pad1 )
return -EINVAL;
if ( d )
{
set_domain_state_info(info, d);
return 0;
}
hdl = lock_dom_exc_handler();
/*
* Only domain registered for VIRQ_DOM_EXC event is allowed to query
* domains having changed state.
*/
if ( current->domain != hdl )
{
rc = -EACCES;
goto out;
}
while ( dom_state_changed )
{
dom = find_first_bit(dom_state_changed, DOMID_MASK + 1);
if ( dom >= DOMID_FIRST_RESERVED )
break;
if ( test_and_clear_bit(dom, dom_state_changed) )
{
*domid = dom;
d = rcu_lock_domain_by_id(dom);
if ( d )
{
set_domain_state_info(info, d);
rcu_unlock_domain(d);
}
else
memset(info, 0, sizeof(*info));
rc = 0;
break;
}
}
out:
unlock_dom_exc_handler(hdl);
return rc;
}
static void __domain_finalise_shutdown(struct domain *d)
{
struct vcpu *v;
+17 -1
View File
@@ -279,6 +279,11 @@ 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;
@@ -289,7 +294,8 @@ 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 !=
(is_stable_domctl(op->cmd) ? 0 : XEN_DOMCTL_INTERFACE_VERSION) )
return -EACCES;
switch ( op->cmd )
@@ -310,6 +316,7 @@ 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;
@@ -876,6 +883,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
ret = -EOPNOTSUPP;
break;
case XEN_DOMCTL_get_domain_state:
ret = xsm_get_domain_state(XSM_XS_PRIV, d);
if ( ret )
break;
copyback = 1;
ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
break;
default:
ret = arch_do_domctl(op, d, u_domctl);
break;
+26
View File
@@ -28,6 +28,7 @@
* 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
*/
@@ -1243,7 +1244,30 @@ struct xen_domctl_set_llc_colors {
XEN_GUEST_HANDLE_64(uint32) llc_colors;
};
/*
* 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).
* NB. xen_domctl.domain is an IN/OUT parameter for this operation.
*/
struct xen_domctl_get_domain_state {
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. */
#define XEN_DOMCTL_GETDOMSTATE_STATE_DEAD 0x0008 /* Domain dead. */
uint16_t pad0; /* Must be 0 on input, returned as 0. */
uint32_t pad1; /* Must be 0 on input, returned as 0. */
uint64_t unique_id; /* Unique domain identifier. */
};
struct xen_domctl {
/* Stable domctl ops: interface_version is required to be 0. */
uint32_t cmd;
#define XEN_DOMCTL_createdomain 1
#define XEN_DOMCTL_destroydomain 2
@@ -1333,6 +1357,7 @@ struct xen_domctl {
#define XEN_DOMCTL_dt_overlay 87
#define XEN_DOMCTL_gsi_permission 88
#define XEN_DOMCTL_set_llc_colors 89
#define XEN_DOMCTL_get_domain_state 90 /* stable interface */
#define XEN_DOMCTL_gdbsx_guestmemio 1000
#define XEN_DOMCTL_gdbsx_pausevcpu 1001
#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
@@ -1400,6 +1425,7 @@ struct xen_domctl {
struct xen_domctl_dt_overlay dt_overlay;
#endif
struct xen_domctl_set_llc_colors set_llc_colors;
struct xen_domctl_get_domain_state get_domain_state;
uint8_t pad[128];
} u;
};
+2
View File
@@ -807,6 +807,8 @@ int domain_soft_reset(struct domain *d, bool resuming);
int domain_init_states(void);
void domain_deinit_states(const struct domain *d);
int get_domain_state(struct xen_domctl_get_domain_state *info,
struct domain *d, domid_t *domid);
int vcpu_start_shutdown_deferral(struct vcpu *v);
void vcpu_end_shutdown_deferral(struct vcpu *v);
+8
View File
@@ -173,6 +173,7 @@ 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);
@@ -815,6 +816,13 @@ 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_XS_PRIV);
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)
{
+6
View File
@@ -200,6 +200,7 @@ 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
@@ -774,6 +775,11 @@ 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
+1
View File
@@ -148,6 +148,7 @@ 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)
+7
View File
@@ -688,6 +688,7 @@ 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:
@@ -1869,6 +1870,11 @@ 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_DOMAIN2, DOMAIN2__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,
@@ -2005,6 +2011,7 @@ 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(
+2
View File
@@ -257,6 +257,8 @@ class domain2
dt_overlay
# XEN_DOMCTL_set_llc_colors
set_llc_colors
# XEN_DOMCTL_get_domain_state
get_domain_state
}
# Similar to class domain, but primarily contains domctls related to HVM domains
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.