>From c6bf254298d68638ca8652825a28fa97cee51ff4 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 6 Jun 2017 13:04:22 -0400 Subject: [PATCH 4/7] x86:domctl: Add XEN_DOMCTL_get_numa_ranges This is a fairly simple hypercall - it allows us to return the list (and ranges) of NUMA nodes. Like: NODE0 0 -> 100000 NODE1 100000 -> 230000 This is different from XEN_SYSCTL_numainfo which returns size of the NODEs and its distance - but not the ranges. Alternatively this functionality can be stuffed in XEN_SYSCTL_numainfo. Also this hypercall - if nodes is set to zero, then it will return the number of nodes so that the caller can allocate right away the right buffer for it. Signed-off-by: Konrad Rzeszutek Wilk --- tools/flask/policy/policy/modules/xen/xen.te | 1 + xen/arch/x86/domctl.c | 50 ++++++++++++++++++++++++++++ xen/include/public/domctl.h | 17 ++++++++++ xen/xsm/flask/hooks.c | 3 ++ xen/xsm/flask/policy/access_vectors | 2 ++ 5 files changed, 73 insertions(+) diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te index d4974ae..5fe5381 100644 --- a/tools/flask/policy/policy/modules/xen/xen.te +++ b/tools/flask/policy/policy/modules/xen/xen.te @@ -68,6 +68,7 @@ allow dom0_t xen_t:xen { allow dom0_t xen_t:xen2 { livepatch_op module_op + get_numa_ranges }; # Allow dom0 to use all XENVER_ subops that have checks. diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 3af6b39..4eaf510 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -323,6 +323,56 @@ long arch_do_domctl( } break; + case XEN_DOMCTL_get_numa_ranges: + { + unsigned int nr = domctl->u.get_numa_ranges.nodes; + unsigned int i = 0, idx = 0; + + if ( !nr ) + { + ret = -E2BIG; + domctl->u.get_numa_ranges.nodes = num_online_nodes(); + copyback = 1; + break; + } + + if ( nr && !guest_handle_okay(domctl->u.get_numa_ranges.ranges, nr) ) + { + ret = -EINVAL; + break; + } + + ret = 0; + for_each_online_node ( i ) + { + struct xen_vmemrange range; + + range.start = node_start_pfn(i); + range.end = node_end_pfn(i); + range.nid = i; + range.flags = 0; + if ( __copy_to_guest_offset(domctl->u.get_numa_ranges.ranges, idx, &range, 1) ) + { + ret = -EFAULT; + break; + } + + idx++; + if ( idx >= nr ) + break; + } + if ( idx ) + { + copyback = 1; + /* + * idx is zero-based and num_online_nodes() has at least 1, hence + * nodes == num_online_nodes() - 1. + */ + domctl->u.get_numa_ranges.nodes = idx; + } + } + break; + case XEN_DOMCTL_getmemlist: { #define XEN_DOMCTL_getmemlist_max_pfns (GB(1) / PAGE_SIZE) diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 2a25079..a32b662 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -955,6 +955,21 @@ struct xen_domctl_smt { typedef struct xen_domctl_smt xen_domctl_smt; DEFINE_XEN_GUEST_HANDLE(xen_domctl_smt); +/* + * Returns how many more there are. If ranges is NULL + * and nodes is zero, then we provide the number of + * nodes in 'nodes'. + * + * Negative values on errors. Zero on success. + */ +struct xen_domctl_numa { + uint32_t nodes; /* IN: How many nodes are requested. + * OUT: How many copied (zero based index). */ + XEN_GUEST_HANDLE_64(xen_vmemrange_t) ranges; +}; +typedef struct xen_domctl_numa xen_domctl_numa_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_numa_t); + struct xen_domctl { uint32_t cmd; #define XEN_DOMCTL_createdomain 1 @@ -1035,6 +1050,7 @@ struct xen_domctl { #define XEN_DOMCTL_hide_device 2001 #define XEN_DOMCTL_unhide_device 2002 #define XEN_DOMCTL_setsmt 2003 +#define XEN_DOMCTL_get_numa_ranges 2004 uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */ domid_t domain; union { @@ -1094,6 +1110,7 @@ struct xen_domctl { struct xen_domctl_gdbsx_domstatus gdbsx_domstatus; struct xen_domctl_vnuma vnuma; struct xen_domctl_smt smt; + struct xen_domctl_numa get_numa_ranges; uint8_t pad[128]; } u; }; diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index be12169..d0cca5f 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -740,6 +740,9 @@ static int flask_domctl(struct domain *d, int cmd) case XEN_DOMCTL_setsmt: return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SETSMT); + case XEN_DOMCTL_get_numa_ranges: + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__GET_NUMA_RANGES); + default: printk("flask_domctl: Unknown op %d\n", cmd); return -EPERM; diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index 10f86b8..7b30cda 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -214,6 +214,8 @@ class domain2 soft_reset # XEN_DOMCTL_setsmt setsmt +# XEN_DOMCTL_get_numa_ranges + get_numa_ranges } # Similar to class domain, but primarily contains domctls related to HVM domains -- 2.9.4