xen-lowmemd.c 3.45 KB
Newer Older
1 2 3 4 5 6 7
/*
 * xen-lowmemd: demo VIRQ_ENOMEM
 * Andres Lagar-Cavilla (GridCentric Inc.)
 */

#include <stdio.h>
#include <xenctrl.h>
8
#include <xenstore.h>
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
#include <stdlib.h>
#include <string.h>

static evtchn_port_t virq_port      = -1;
static xc_evtchn *xce_handle        = NULL;
static xc_interface *xch            = NULL;
static struct xs_handle *xs_handle  = NULL;

void cleanup(void)
{
    if (virq_port > -1)
        xc_evtchn_unbind(xce_handle, virq_port);
    if (xce_handle)
        xc_evtchn_close(xce_handle);
    if (xch)
        xc_interface_close(xch);
    if (xs_handle)
        xs_daemon_close(xs_handle);
}

/* Never shrink dom0 below 1 GiB */
#define DOM0_FLOOR  (1 << 30)
#define DOM0_FLOOR_PG   ((DOM0_FLOOR) >> 12)

/* Act if free memory is less than 92 MiB */
#define THRESHOLD   (92 << 20)
#define THRESHOLD_PG    ((THRESHOLD) >> 12)

#define BUFSZ 512
void handle_low_mem(void)
{
    xc_dominfo_t  dom0_info;
    xc_physinfo_t info;
    unsigned long long free_pages, dom0_pages, diff, dom0_target;
    char data[BUFSZ], error[BUFSZ];

    if (xc_physinfo(xch, &info) < 0)
    {
        perror("Getting physinfo failed");
        return;
    }

    free_pages = (unsigned long long) info.free_pages;
    printf("Available free pages: 0x%llx:%llux\n",
            free_pages, free_pages);

    /* Don't do anything if we have more than the threshold free */
    if ( free_pages >= THRESHOLD_PG )
        return;
    diff = THRESHOLD_PG - free_pages; 

    if (xc_domain_getinfo(xch, 0, 1, &dom0_info) < 1)
    {
        perror("Failed to get dom0 info");
        return;
    }

    dom0_pages = (unsigned long long) dom0_info.nr_pages;
    printf("Dom0 pages: 0x%llx:%llu\n", dom0_pages, dom0_pages);
    dom0_target = dom0_pages - diff;
    if (dom0_target <= DOM0_FLOOR_PG)
        return;

    printf("Shooting for dom0 target 0x%llx:%llu\n", 
            dom0_target, dom0_target);

    snprintf(data, BUFSZ, "%llu", dom0_target);
    if (!xs_write(xs_handle, XBT_NULL, 
            "/local/domain/0/memory/target", data, strlen(data)))
    {
        snprintf(error, BUFSZ,"Failed to write target %s to xenstore", data);
        perror(error);
    }
}

int main(int argc, char *argv[])
{
    int rc;

    atexit(cleanup);

	xch = xc_interface_open(NULL, NULL, 0);
	if (xch == NULL)
    {
        perror("Failed to open xc interface");
        return 1;
    }

	xce_handle = xc_evtchn_open(NULL, 0);
	if (xce_handle == NULL)
    {
        perror("Failed to open evtchn device");
        return 2;
    }

    xs_handle = xs_daemon_open();
    if (xs_handle == NULL)
    {
        perror("Failed to open xenstore connection");
        return 3;
    }

	if ((rc = xc_evtchn_bind_virq(xce_handle, VIRQ_ENOMEM)) == -1)
    {
        perror("Failed to bind to domain exception virq port");
        return 4;
    }

    virq_port = rc;
    
    while(1)
    {
        evtchn_port_t port;

        if ((port = xc_evtchn_pending(xce_handle)) == -1)
        {
            perror("Failed to listen for pending event channel");
            return 5;
        }

        if (port != virq_port)
        {
            char data[BUFSZ];
            snprintf(data, BUFSZ, "Wrong port, got %d expected %d", port, virq_port);
            perror(data);
            return 6;
        }

        if (xc_evtchn_unmask(xce_handle, port) == -1)
        {
            perror("Failed to unmask port");
            return 7;
        }

        printf("Got a virq kick, time to get work\n");
        handle_low_mem();
    }

    return 0;
}