aboutsummaryrefslogtreecommitdiffstats
path: root/tools/misc/xen-lowmemd.c
blob: 82ffd752e0198fa609ec5f46183e4a60163848f6 (plain)
1
2
3
4
5
6
7
8
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
/*
 * xen-lowmemd: demo VIRQ_ENOMEM
 * Andres Lagar-Cavilla (GridCentric Inc.)
 */

#include <stdio.h>
#include <xenctrl.h>
#include <xenstore.h>
#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;
}