direct-io.hg

view tools/libxc/xc_private.h @ 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 cfb1136ee8f7
children 3859131c0b8b
line source
2 #ifndef XC_PRIVATE_H
3 #define XC_PRIVATE_H
5 #include <unistd.h>
6 #include <stdio.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <sys/mman.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <stdlib.h>
14 #include <sys/ioctl.h>
16 #include "xenctrl.h"
18 #include <xen/sys/privcmd.h>
20 /* valgrind cannot see when a hypercall has filled in some values. For this
21 reason, we must zero the privcmd_hypercall_t or domctl/sysctl instance
22 before a call, if using valgrind. */
23 #ifdef VALGRIND
24 #define DECLARE_HYPERCALL privcmd_hypercall_t hypercall = { 0 }
25 #define DECLARE_DOMCTL struct xen_domctl domctl = { 0 }
26 #define DECLARE_SYSCTL struct xen_sysctl sysctl = { 0 }
27 #else
28 #define DECLARE_HYPERCALL privcmd_hypercall_t hypercall
29 #define DECLARE_DOMCTL struct xen_domctl domctl
30 #define DECLARE_SYSCTL struct xen_sysctl sysctl
31 #endif
33 #undef PAGE_SHIFT
34 #undef PAGE_SIZE
35 #undef PAGE_MASK
36 #define PAGE_SHIFT XC_PAGE_SHIFT
37 #define PAGE_SIZE (1UL << PAGE_SHIFT)
38 #define PAGE_MASK (~(PAGE_SIZE-1))
40 #define DEBUG 1
41 #define INFO 1
42 #define PROGRESS 0
44 #if INFO
45 #define IPRINTF(_f, _a...) printf(_f , ## _a)
46 #else
47 #define IPRINTF(_f, _a...) ((void)0)
48 #endif
50 #if DEBUG
51 #define DPRINTF(_f, _a...) fprintf(stderr, _f , ## _a)
52 #else
53 #define DPRINTF(_f, _a...) ((void)0)
54 #endif
56 #if PROGRESS
57 #define PPRINTF(_f, _a...) fprintf(stderr, _f , ## _a)
58 #else
59 #define PPRINTF(_f, _a...)
60 #endif
62 void xc_set_error(int code, const char *fmt, ...);
64 #define ERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m , ## _a )
65 #define PERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m " (%d = %s)", \
66 _m , ## _a , errno, strerror(errno))
68 int lock_pages(void *addr, size_t len);
69 void unlock_pages(void *addr, size_t len);
71 static inline void safe_munlock(const void *addr, size_t len)
72 {
73 int saved_errno = errno;
74 (void)munlock(addr, len);
75 errno = saved_errno;
76 }
78 int do_xen_hypercall(int xc_handle, privcmd_hypercall_t *hypercall);
80 static inline int do_xen_version(int xc_handle, int cmd, void *dest)
81 {
82 DECLARE_HYPERCALL;
84 hypercall.op = __HYPERVISOR_xen_version;
85 hypercall.arg[0] = (unsigned long) cmd;
86 hypercall.arg[1] = (unsigned long) dest;
88 return do_xen_hypercall(xc_handle, &hypercall);
89 }
91 static inline int do_domctl(int xc_handle, struct xen_domctl *domctl)
92 {
93 int ret = -1;
94 DECLARE_HYPERCALL;
96 domctl->interface_version = XEN_DOMCTL_INTERFACE_VERSION;
98 hypercall.op = __HYPERVISOR_domctl;
99 hypercall.arg[0] = (unsigned long)domctl;
101 if ( lock_pages(domctl, sizeof(*domctl)) != 0 )
102 {
103 PERROR("Could not lock memory for Xen hypercall");
104 goto out1;
105 }
107 if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
108 {
109 if ( errno == EACCES )
110 DPRINTF("domctl operation failed -- need to"
111 " rebuild the user-space tool set?\n");
112 }
114 unlock_pages(domctl, sizeof(*domctl));
116 out1:
117 return ret;
118 }
120 static inline int do_sysctl(int xc_handle, struct xen_sysctl *sysctl)
121 {
122 int ret = -1;
123 DECLARE_HYPERCALL;
125 sysctl->interface_version = XEN_SYSCTL_INTERFACE_VERSION;
127 hypercall.op = __HYPERVISOR_sysctl;
128 hypercall.arg[0] = (unsigned long)sysctl;
130 if ( lock_pages(sysctl, sizeof(*sysctl)) != 0 )
131 {
132 PERROR("Could not lock memory for Xen hypercall");
133 goto out1;
134 }
136 if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
137 {
138 if ( errno == EACCES )
139 DPRINTF("sysctl operation failed -- need to"
140 " rebuild the user-space tool set?\n");
141 }
143 unlock_pages(sysctl, sizeof(*sysctl));
145 out1:
146 return ret;
147 }
149 int xc_map_foreign_ranges(int xc_handle, uint32_t dom,
150 privcmd_mmap_entry_t *entries, int nr);
152 void *map_domain_va_core(unsigned long domfd, int cpu, void *guest_va,
153 vcpu_guest_context_t *ctxt);
154 int xc_waitdomain_core(int xc_handle, int domain, int *status,
155 int options, vcpu_guest_context_t *ctxt);
157 #endif /* __XC_PRIVATE_H__ */