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