1 /*
2  * xen-lowmemd: demo VIRQ_ENOMEM
3  * Andres Lagar-Cavilla (GridCentric Inc.)
4  */
5 
6 #include <stdio.h>
7 #include <xenevtchn.h>
8 #include <xenctrl.h>
9 #include <xenstore.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 static evtchn_port_t virq_port      = ~0;
14 static xenevtchn_handle *xce_handle = NULL;
15 static xc_interface *xch            = NULL;
16 static struct xs_handle *xs_handle  = NULL;
17 
cleanup(void)18 void cleanup(void)
19 {
20     if (virq_port != ~0)
21         xenevtchn_unbind(xce_handle, virq_port);
22     if (xce_handle)
23         xenevtchn_close(xce_handle);
24     if (xch)
25         xc_interface_close(xch);
26     if (xs_handle)
27         xs_daemon_close(xs_handle);
28 }
29 
30 /* Never shrink dom0 below 1 GiB */
31 #define DOM0_FLOOR  (1 << 30)
32 #define DOM0_FLOOR_PG   ((DOM0_FLOOR) >> 12)
33 
34 /* Act if free memory is less than 92 MiB */
35 #define THRESHOLD   (92 << 20)
36 #define THRESHOLD_PG    ((THRESHOLD) >> 12)
37 
38 #define BUFSZ 512
handle_low_mem(void)39 void handle_low_mem(void)
40 {
41     xc_dominfo_t  dom0_info;
42     xc_physinfo_t info;
43     unsigned long long free_pages, dom0_pages, diff, dom0_target;
44     char data[BUFSZ], error[BUFSZ];
45 
46     if (xc_physinfo(xch, &info) < 0)
47     {
48         perror("Getting physinfo failed");
49         return;
50     }
51 
52     free_pages = (unsigned long long) info.free_pages;
53     printf("Available free pages: 0x%llx:%llux\n",
54             free_pages, free_pages);
55 
56     /* Don't do anything if we have more than the threshold free */
57     if ( free_pages >= THRESHOLD_PG )
58         return;
59     diff = THRESHOLD_PG - free_pages;
60 
61     if (xc_domain_getinfo(xch, 0, 1, &dom0_info) < 1)
62     {
63         perror("Failed to get dom0 info");
64         return;
65     }
66 
67     dom0_pages = (unsigned long long) dom0_info.nr_pages;
68     printf("Dom0 pages: 0x%llx:%llu\n", dom0_pages, dom0_pages);
69     dom0_target = dom0_pages - diff;
70     if (dom0_target <= DOM0_FLOOR_PG)
71         return;
72 
73     printf("Shooting for dom0 target 0x%llx:%llu\n",
74             dom0_target, dom0_target);
75 
76     snprintf(data, BUFSZ, "%llu", dom0_target);
77     if (!xs_write(xs_handle, XBT_NULL,
78             "/local/domain/0/memory/target", data, strlen(data)))
79     {
80         snprintf(error, BUFSZ,"Failed to write target %.24s to xenstore", data);
81         perror(error);
82     }
83 }
84 
main(int argc,char * argv[])85 int main(int argc, char *argv[])
86 {
87     int rc;
88 
89     atexit(cleanup);
90 
91 	xch = xc_interface_open(NULL, NULL, 0);
92 	if (xch == NULL)
93     {
94         perror("Failed to open xc interface");
95         return 1;
96     }
97 
98 	xce_handle = xenevtchn_open(NULL, 0);
99 	if (xce_handle == NULL)
100     {
101         perror("Failed to open evtchn device");
102         return 2;
103     }
104 
105     xs_handle = xs_daemon_open();
106     if (xs_handle == NULL)
107     {
108         perror("Failed to open xenstore connection");
109         return 3;
110     }
111 
112 	if ((rc = xenevtchn_bind_virq(xce_handle, VIRQ_ENOMEM)) == -1)
113     {
114         perror("Failed to bind to domain exception virq port");
115         return 4;
116     }
117 
118     virq_port = rc;
119 
120     while(1)
121     {
122         evtchn_port_t port;
123 
124         if ((port = xenevtchn_pending(xce_handle)) == -1)
125         {
126             perror("Failed to listen for pending event channel");
127             return 5;
128         }
129 
130         if (port != virq_port)
131         {
132             char data[BUFSZ];
133             snprintf(data, BUFSZ, "Wrong port, got %d expected %d", port, virq_port);
134             perror(data);
135             return 6;
136         }
137 
138         if (xenevtchn_unmask(xce_handle, port) == -1)
139         {
140             perror("Failed to unmask port");
141             return 7;
142         }
143 
144         printf("Got a virq kick, time to get work\n");
145         handle_low_mem();
146     }
147 
148     return 0;
149 }
150