Add new domctl hypercall to expose current heap values. This functionality is needed for probing how much memory is available in a given node prior to VM creation. Signed-off-by: Ryan Harper diff -r 27e993c80ceb tools/libxc/xc_domain.c --- a/tools/libxc/xc_domain.c Mon Jul 09 09:47:20 2007 +0100 +++ b/tools/libxc/xc_domain.c Tue Jul 10 14:02:53 2007 -0500 @@ -586,6 +586,34 @@ int xc_domain_ioport_permission(int xc_h domctl.u.ioport_permission.allow_access = allow_access; return do_domctl(xc_handle, &domctl); +} + +int xc_availheap(int xc_handle, + int zone_lo, + int zone_hi, + int node, + uint32_t *nr_zones, + uint32_t *nr_nodes, + uint64_t *pages) +{ + DECLARE_SYSCTL; + int rc = 0; + + sysctl.cmd = XEN_SYSCTL_availheap; + sysctl.u.availheap.zone_lo = zone_lo; + sysctl.u.availheap.zone_hi = zone_hi; + sysctl.u.availheap.node = node; + + rc = xc_sysctl(xc_handle, &sysctl); + if ( rc >= 0 ) { + if (nr_zones) + *nr_zones = sysctl.u.availheap.nr_zones; + if (nr_nodes) + *nr_nodes = sysctl.u.availheap.nr_nodes; + *pages = sysctl.u.availheap.pages; + } + + return rc; } int xc_vcpu_setcontext(int xc_handle, diff -r 27e993c80ceb tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Mon Jul 09 09:47:20 2007 +0100 +++ b/tools/libxc/xenctrl.h Tue Jul 10 14:02:53 2007 -0500 @@ -616,6 +616,22 @@ int xc_get_pfn_type_batch(int xc_handle, /* Get current total pages allocated to a domain. */ long xc_get_tot_pages(int xc_handle, uint32_t domid); +/** + * This function retrieves the the number of pages available + * in the heap in a specific range of zones and nodes. + * + * @parm xc_handle a handle to an open hypervisor interface + * @parm domid the domain to query + * @parm zone_lo the starting zone to query + * @parm zone_lo the last zone to query + * @parm node the node to query + * @parm *nr_zones caller variable to put number of zones queried + * @parm *nr_nodes caller variable to put number of nodes queried + * @parm *pages caller variable to put total pages counted + * @return 0 on success, <0 on failure. + */ +int xc_availheap(int xc_handle, int zone_lo, int zone_hi, int node, + uint32_t *nr_zones, uint32_t *nr_nodes, uint64_t *pages); /* * Trace Buffer Operations diff -r 27e993c80ceb xen/common/page_alloc.c --- a/xen/common/page_alloc.c Mon Jul 09 09:47:20 2007 +0100 +++ b/xen/common/page_alloc.c Tue Jul 10 14:09:28 2007 -0500 @@ -569,8 +569,9 @@ void init_heap_pages( } } -static unsigned long avail_heap_pages( - unsigned int zone_lo, unsigned int zone_hi, unsigned int node) +unsigned long avail_heap_pages( + unsigned int zone_lo, unsigned int zone_hi, unsigned int node, + unsigned int *nr_zones) { unsigned int i, zone, num_nodes = num_online_nodes(); unsigned long free_pages = 0; @@ -586,6 +587,9 @@ static unsigned long avail_heap_pages( if ( (node == -1) || (node == i) ) free_pages += avail[i][zone]; } + + if (nr_zones) + *nr_zones = zone_hi - zone_lo + 1; return free_pages; } @@ -834,7 +838,7 @@ struct page_info *__alloc_domheap_pages( ((order > MAX_ORDER) || (avail_heap_pages(MEMZONE_XEN + 1, dma_bitsize - PAGE_SHIFT - 1, - -1) < + -1, NULL) < (dma_emergency_pool_pages + (1UL << order)))) ) return NULL; } @@ -934,11 +938,11 @@ unsigned long avail_domheap_pages(void) avail_nrm = avail_heap_pages(dma_bitsize - PAGE_SHIFT, NR_ZONES - 1, - -1); + -1, NULL); avail_dma = avail_heap_pages(MEMZONE_XEN + 1, dma_bitsize - PAGE_SHIFT - 1, - -1); + -1, NULL); if ( avail_dma > dma_emergency_pool_pages ) avail_dma -= dma_emergency_pool_pages; @@ -950,7 +954,7 @@ unsigned long avail_domheap_pages(void) unsigned long avail_nodeheap_pages(int node) { - return avail_heap_pages(0, NR_ZONES - 1, node); + return avail_heap_pages(0, NR_ZONES - 1, node, NULL); } static void pagealloc_keyhandler(unsigned char key) @@ -960,7 +964,7 @@ static void pagealloc_keyhandler(unsigne printk("Physical memory information:\n"); printk(" Xen heap: %lukB free\n", - avail_heap_pages(zone, zone, -1) << (PAGE_SHIFT-10)); + avail_heap_pages(zone, zone, -1, NULL) << (PAGE_SHIFT-10)); while ( ++zone < NR_ZONES ) { @@ -972,7 +976,7 @@ static void pagealloc_keyhandler(unsigne total = 0; } - if ( (n = avail_heap_pages(zone, zone, -1)) != 0 ) + if ( (n = avail_heap_pages(zone, zone, -1, NULL)) != 0 ) { total += n; printk(" heap[%02u]: %lukB free\n", zone, n << (PAGE_SHIFT-10)); diff -r 27e993c80ceb xen/common/sysctl.c --- a/xen/common/sysctl.c Mon Jul 09 09:47:20 2007 +0100 +++ b/xen/common/sysctl.c Tue Jul 10 14:09:59 2007 -0500 @@ -21,6 +21,8 @@ #include #include #include +#include +#include extern long arch_do_sysctl( struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl); @@ -166,6 +168,31 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysc if ( copy_to_guest(u_sysctl, op, 1) ) ret = -EFAULT; + } + break; + + case XEN_SYSCTL_availheap: + { + ret = -EINVAL; + + if ( op->u.availheap.node >= num_online_nodes() ) + break; + if ( op->u.availheap.zone_lo > op->u.availheap.zone_hi ) + break; + + ( op->u.availheap.node < 0 ) ? + (op->u.availheap.nr_nodes=num_online_nodes()) : + (op->u.availheap.nr_nodes=1); + + op->u.availheap.pages = avail_heap_pages(op->u.availheap.zone_lo, + op->u.availheap.zone_hi, + op->u.availheap.node, + &(op->u.availheap.nr_zones)); + + if ( copy_to_guest(u_sysctl, op, 1) ) + ret = -EFAULT; + else + ret = 0; } break; diff -r 27e993c80ceb xen/include/public/sysctl.h --- a/xen/include/public/sysctl.h Mon Jul 09 09:47:20 2007 +0100 +++ b/xen/include/public/sysctl.h Tue Jul 10 14:02:53 2007 -0500 @@ -185,6 +185,20 @@ typedef struct xen_sysctl_getcpuinfo xen typedef struct xen_sysctl_getcpuinfo xen_sysctl_getcpuinfo_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_getcpuinfo_t); +#define XEN_SYSCTL_availheap 9 +struct xen_sysctl_availheap { + /* in */ + int zone_lo; /* starting zone */ + int zone_hi; /* ending zone, -1 for zone_lo to NR_ZONES */ + int node; /* query available pages in node, -1 for all */ + /* out */ + uint32_t nr_zones; /* number of zones queried */ + uint32_t nr_nodes; /* number of nodes queried */ + uint64_t pages; +}; +typedef struct xen_sysctl_availheap xen_sysctl_availheap_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_availheap_t); + struct xen_sysctl { uint32_t cmd; uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ @@ -197,6 +211,7 @@ struct xen_sysctl { struct xen_sysctl_getdomaininfolist getdomaininfolist; struct xen_sysctl_debug_keys debug_keys; struct xen_sysctl_getcpuinfo getcpuinfo; + struct xen_sysctl_availheap availheap; uint8_t pad[128]; } u; }; diff -r 27e993c80ceb xen/include/xen/mm.h --- a/xen/include/xen/mm.h Mon Jul 09 09:47:20 2007 +0100 +++ b/xen/include/xen/mm.h Tue Jul 10 14:08:03 2007 -0500 @@ -65,6 +65,10 @@ unsigned long avail_domheap_pages(void); #define alloc_domheap_page(d) (alloc_domheap_pages(d,0,0)) #define free_domheap_page(p) (free_domheap_pages(p,0)) +unsigned long avail_heap_pages( + unsigned int zone_lo, unsigned int zone_hi, unsigned int node, + unsigned int *nr_zones); + void scrub_heap_pages(void); int assign_pages(