ia64/xen-unstable

view tools/libxc/xc_linux.c @ 14114:59b8d5168cc1

Reduce impact of saving/restoring/dumping large domains on Dom0 memory
usage by means of fadvise64() to tell the OS to discard the cache
pages used for the save/dump file.

Signed-off-by: Simon Graham <Simon.Graham@stratus.com>
author Keir Fraser <keir@xensource.com>
date Sat Feb 24 14:48:17 2007 +0000 (2007-02-24)
parents f7b7daed94d6
children d66dff09338a
line source
1 /******************************************************************************
2 *
3 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
4 * Use is subject to license terms.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2 of the
9 * License.
10 */
12 #include "xc_private.h"
14 #include <xen/memory.h>
15 #include <xen/sys/evtchn.h>
16 #include <unistd.h>
17 #include <fcntl.h>
19 int xc_interface_open(void)
20 {
21 int flags, saved_errno;
22 int fd = open("/proc/xen/privcmd", O_RDWR);
24 if ( fd == -1 )
25 {
26 PERROR("Could not obtain handle on privileged command interface");
27 return -1;
28 }
30 /* Although we return the file handle as the 'xc handle' the API
31 does not specify / guarentee that this integer is in fact
32 a file handle. Thus we must take responsiblity to ensure
33 it doesn't propagate (ie leak) outside the process */
34 if ( (flags = fcntl(fd, F_GETFD)) < 0 )
35 {
36 PERROR("Could not get file handle flags");
37 goto error;
38 }
39 flags |= FD_CLOEXEC;
40 if ( fcntl(fd, F_SETFD, flags) < 0 )
41 {
42 PERROR("Could not set file handle flags");
43 goto error;
44 }
46 return fd;
48 error:
49 saved_errno = errno;
50 close(fd);
51 errno = saved_errno;
52 return -1;
53 }
55 int xc_interface_close(int xc_handle)
56 {
57 return close(xc_handle);
58 }
60 void *xc_map_foreign_batch(int xc_handle, uint32_t dom, int prot,
61 xen_pfn_t *arr, int num)
62 {
63 privcmd_mmapbatch_t ioctlx;
64 void *addr;
65 addr = mmap(NULL, num*PAGE_SIZE, prot, MAP_SHARED, xc_handle, 0);
66 if ( addr == MAP_FAILED )
67 return NULL;
69 ioctlx.num=num;
70 ioctlx.dom=dom;
71 ioctlx.addr=(unsigned long)addr;
72 ioctlx.arr=arr;
73 if ( ioctl(xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx) < 0 )
74 {
75 int saved_errno = errno;
76 perror("XXXXXXXX");
77 (void)munmap(addr, num*PAGE_SIZE);
78 errno = saved_errno;
79 return NULL;
80 }
81 return addr;
83 }
85 void *xc_map_foreign_range(int xc_handle, uint32_t dom,
86 int size, int prot,
87 unsigned long mfn)
88 {
89 privcmd_mmap_t ioctlx;
90 privcmd_mmap_entry_t entry;
91 void *addr;
92 addr = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0);
93 if ( addr == MAP_FAILED )
94 return NULL;
96 ioctlx.num=1;
97 ioctlx.dom=dom;
98 ioctlx.entry=&entry;
99 entry.va=(unsigned long) addr;
100 entry.mfn=mfn;
101 entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT;
102 if ( ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx) < 0 )
103 {
104 int saved_errno = errno;
105 (void)munmap(addr, size);
106 errno = saved_errno;
107 return NULL;
108 }
109 return addr;
110 }
112 int xc_map_foreign_ranges(int xc_handle, uint32_t dom,
113 privcmd_mmap_entry_t *entries, int nr)
114 {
115 privcmd_mmap_t ioctlx;
117 ioctlx.num = nr;
118 ioctlx.dom = dom;
119 ioctlx.entry = entries;
121 return ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx);
122 }
124 static int do_privcmd(int xc_handle, unsigned int cmd, unsigned long data)
125 {
126 return ioctl(xc_handle, cmd, data);
127 }
129 int do_xen_hypercall(int xc_handle, privcmd_hypercall_t *hypercall)
130 {
131 return do_privcmd(xc_handle,
132 IOCTL_PRIVCMD_HYPERCALL,
133 (unsigned long)hypercall);
134 }
136 #define MTAB "/proc/mounts"
137 #define MAX_PATH 255
138 #define _STR(x) #x
139 #define STR(x) _STR(x)
141 static int find_sysfsdir(char *sysfsdir)
142 {
143 FILE *fp;
144 char type[MAX_PATH + 1];
146 if ( (fp = fopen(MTAB, "r")) == NULL )
147 return -1;
149 while ( fscanf(fp, "%*s %"
150 STR(MAX_PATH)
151 "s %"
152 STR(MAX_PATH)
153 "s %*s %*d %*d\n",
154 sysfsdir, type) == 2 )
155 {
156 if ( strncmp(type, "sysfs", 5) == 0 )
157 break;
158 }
160 fclose(fp);
162 return ((strncmp(type, "sysfs", 5) == 0) ? 0 : -1);
163 }
165 int xc_find_device_number(const char *name)
166 {
167 FILE *fp;
168 int i, major, minor;
169 char sysfsdir[MAX_PATH + 1];
170 static char *classlist[] = { "xen", "misc" };
172 for ( i = 0; i < (sizeof(classlist) / sizeof(classlist[0])); i++ )
173 {
174 if ( find_sysfsdir(sysfsdir) < 0 )
175 goto not_found;
177 /* <base>/class/<classname>/<devname>/dev */
178 strncat(sysfsdir, "/class/", MAX_PATH);
179 strncat(sysfsdir, classlist[i], MAX_PATH);
180 strncat(sysfsdir, "/", MAX_PATH);
181 strncat(sysfsdir, name, MAX_PATH);
182 strncat(sysfsdir, "/dev", MAX_PATH);
184 if ( (fp = fopen(sysfsdir, "r")) != NULL )
185 goto found;
186 }
188 not_found:
189 errno = -ENOENT;
190 return -1;
192 found:
193 if ( fscanf(fp, "%d:%d", &major, &minor) != 2 )
194 {
195 fclose(fp);
196 goto not_found;
197 }
199 fclose(fp);
201 return makedev(major, minor);
202 }
204 #define EVTCHN_DEV_NAME "/dev/xen/evtchn"
206 int xc_evtchn_open(void)
207 {
208 struct stat st;
209 int fd;
210 int devnum;
212 devnum = xc_find_device_number("evtchn");
214 /* Make sure any existing device file links to correct device. */
215 if ( (lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
216 (st.st_rdev != devnum) )
217 (void)unlink(EVTCHN_DEV_NAME);
219 reopen:
220 if ( (fd = open(EVTCHN_DEV_NAME, O_RDWR)) == -1 )
221 {
222 if ( (errno == ENOENT) &&
223 ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
224 (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, devnum) == 0) )
225 goto reopen;
227 PERROR("Could not open event channel interface");
228 return -1;
229 }
231 return fd;
232 }
234 int xc_evtchn_close(int xce_handle)
235 {
236 return close(xce_handle);
237 }
239 int xc_evtchn_fd(int xce_handle)
240 {
241 return xce_handle;
242 }
244 int xc_evtchn_notify(int xce_handle, evtchn_port_t port)
245 {
246 struct ioctl_evtchn_notify notify;
248 notify.port = port;
250 return ioctl(xce_handle, IOCTL_EVTCHN_NOTIFY, &notify);
251 }
253 evtchn_port_t xc_evtchn_bind_unbound_port(int xce_handle, int domid)
254 {
255 struct ioctl_evtchn_bind_unbound_port bind;
257 bind.remote_domain = domid;
259 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind);
260 }
262 evtchn_port_t xc_evtchn_bind_interdomain(int xce_handle, int domid,
263 evtchn_port_t remote_port)
264 {
265 struct ioctl_evtchn_bind_interdomain bind;
267 bind.remote_domain = domid;
268 bind.remote_port = remote_port;
270 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
271 }
273 int xc_evtchn_unbind(int xce_handle, evtchn_port_t port)
274 {
275 struct ioctl_evtchn_unbind unbind;
277 unbind.port = port;
279 return ioctl(xce_handle, IOCTL_EVTCHN_UNBIND, &unbind);
280 }
282 evtchn_port_t xc_evtchn_bind_virq(int xce_handle, unsigned int virq)
283 {
284 struct ioctl_evtchn_bind_virq bind;
286 bind.virq = virq;
288 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_VIRQ, &bind);
289 }
291 static int dorw(int fd, char *data, size_t size, int do_write)
292 {
293 size_t offset = 0;
294 ssize_t len;
296 while ( offset < size )
297 {
298 if (do_write)
299 len = write(fd, data + offset, size - offset);
300 else
301 len = read(fd, data + offset, size - offset);
303 if ( len == -1 )
304 {
305 if ( errno == EINTR )
306 continue;
307 return -1;
308 }
310 offset += len;
311 }
313 return 0;
314 }
316 evtchn_port_t xc_evtchn_pending(int xce_handle)
317 {
318 evtchn_port_t port;
320 if ( dorw(xce_handle, (char *)&port, sizeof(port), 0) == -1 )
321 return -1;
323 return port;
324 }
326 int xc_evtchn_unmask(int xce_handle, evtchn_port_t port)
327 {
328 return dorw(xce_handle, (char *)&port, sizeof(port), 1);
329 }
331 /* Optionally flush file to disk and discard page cache */
332 int discard_file_cache(int fd, int flush)
333 {
334 off_t cur = 0;
336 if ( flush && (fsync(fd) < 0) )
337 {
338 PERROR("Failed to flush file: %s", strerror(errno));
339 return -errno;
340 }
342 /*
343 * Calculate last page boundary of amount written so far
344 * unless we are flushing in which case entire cache
345 * is discarded.
346 */
347 if ( !flush )
348 {
349 if ( (cur = lseek(fd, 0, SEEK_CUR)) == (off_t)-1 )
350 cur = 0;
351 cur &= ~(PAGE_SIZE-1);
352 }
354 /* Discard from the buffer cache. */
355 if ( posix_fadvise64(fd, 0, cur, POSIX_FADV_DONTNEED) < 0 )
356 {
357 PERROR("Failed to discard cache: %s", strerror(errno));
358 return -errno;
359 }
361 return 0;
362 }
364 /*
365 * Local variables:
366 * mode: C
367 * c-set-style: "BSD"
368 * c-basic-offset: 4
369 * tab-width: 4
370 * indent-tabs-mode: nil
371 * End:
372 */