direct-io.hg

view tools/libxc/xc_linux.c @ 12765:2dd4569e0640

[LIBXC] Add an error reporting API to the libxc library.

- An 'xc_error' struct is used to pass around error
details. Currently contains two members 'code' an enumeration of
error types, and 'message' a free text description of the specific
problem.

- The xc_get_last_error() method returns a const pointer to the
internal instance of this struct manged by libxc. By returning a
const pointer we can add extra members to the end of the struct at
any time without worrying about ABI of callers. This will let us
provide more fine-grained info if needed in the future.

- The xc_error instance is statically defined inside libxc and marked
__thread. This ensures that errors are recorded per-thread, and
that when dealing with errors we never need to call malloc - all
storage needed is statically allocated.

- The xc_clear_last_error() method resets any currently recorded
error details

- The xc_error_code_to_desc() method converts the integer error code
into a generic user facing messsage. eg "Invalid kernel". Together
with the 'message' field from xc_error, this provides the user
visible feedback. eg "Invalid kernel: Non PAE-kernel on PAE host."

- A callback can be registered with xc_set_error_handler to receive
notification whenever an error is recorded, rather than querying
for error details after the fact with xc_get_last_error

- If built with -DDEBUG set, a default error handler will be
registered which calls fprintf(stderr), thus maintaining current
behaviour of logging errors to stderr during developer builds.

- The python binding for libxc is updated to use xc_get_last_error
to pull out error details whenever appropriate, instead of
returning info based on 'errno'

- The xc_set_error method is private to libxc internals, and is used
for setting error details

- The ERROR and PERROR macros have been updated to call xc_set_error
automatically specifying XC_INTERNAL_ERROR as the error code. This
gives a generic error report for all current failure points

- Some uses of the ERROR macro have been replaced with explicit
calls to xc_set_error to enable finer grained error reporting. In
particular the code dealing with invalid kernel types uses this
to report about PAE/architecture/wordsize mismatches

The patch has been tested by calling xm create against a varietry of
config files defining invalid kernels of various kinds. It has also
been tested with libvirt talking to xend. In both cases the error
messages were propagated all the way back up the stack.

There is only one place where I need to do further work. The suspend
& restore APIs in Xend invoke external helper programs rather than
calling libxc directly. This means that error details are essentially
lost. Since there is already code in XenD which scans STDERR from
these programs I will investigate adapting this to extract actual
error messages from these helpers.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author kfraser@localhost.localdomain
date Thu Dec 07 11:36:26 2006 +0000 (2006-12-07)
parents f7b7daed94d6
children 59b8d5168cc1
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 /*
332 * Local variables:
333 * mode: C
334 * c-set-style: "BSD"
335 * c-basic-offset: 4
336 * tab-width: 4
337 * indent-tabs-mode: nil
338 * End:
339 */