direct-io.hg

view tools/libxc/xg_private.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 9d6bc06919e0
children bea505a69722 6b82bbbedbe1
line source
1 /******************************************************************************
2 * xg_private.c
3 *
4 * Helper functions for the rest of the library.
5 */
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <zlib.h>
10 #include <strings.h>
12 #include "xg_private.h"
14 int lock_pages(void *addr, size_t len)
15 {
16 int e = 0;
17 #ifndef __sun__
18 e = mlock(addr, len);
19 #endif
20 return (e);
21 }
23 void unlock_pages(void *addr, size_t len)
24 {
25 #ifndef __sun__
26 safe_munlock(addr, len);
27 #endif
28 }
30 char *xc_read_image(const char *filename, unsigned long *size)
31 {
32 int kernel_fd = -1;
33 gzFile kernel_gfd = NULL;
34 char *image = NULL, *tmp;
35 unsigned int bytes;
37 if ( (filename == NULL) || (size == NULL) )
38 return NULL;
40 if ( (kernel_fd = open(filename, O_RDONLY)) < 0 )
41 {
42 PERROR("Could not open kernel image");
43 goto out;
44 }
46 if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
47 {
48 PERROR("Could not allocate decompression state for state file");
49 goto out;
50 }
52 *size = 0;
54 #define CHUNK 1*1024*1024
55 while(1)
56 {
57 if ( (tmp = realloc(image, *size + CHUNK)) == NULL )
58 {
59 PERROR("Could not allocate memory for kernel image");
60 free(image);
61 image = NULL;
62 goto out;
63 }
64 image = tmp;
66 bytes = gzread(kernel_gfd, image + *size, CHUNK);
67 switch (bytes)
68 {
69 case -1:
70 PERROR("Error reading kernel image");
71 free(image);
72 image = NULL;
73 goto out;
74 case 0: /* EOF */
75 goto out;
76 default:
77 *size += bytes;
78 break;
79 }
80 }
81 #undef CHUNK
83 out:
84 if ( *size == 0 )
85 {
86 PERROR("Could not read kernel image");
87 free(image);
88 image = NULL;
89 }
90 else if ( image )
91 {
92 /* Shrink allocation to fit image. */
93 tmp = realloc(image, *size);
94 if ( tmp )
95 image = tmp;
96 }
98 if ( kernel_gfd != NULL )
99 gzclose(kernel_gfd);
100 else if ( kernel_fd >= 0 )
101 close(kernel_fd);
102 return image;
103 }
105 char *xc_inflate_buffer(const char *in_buf, unsigned long in_size,
106 unsigned long *out_size)
107 {
108 int sts;
109 z_stream zStream;
110 unsigned long out_len;
111 char *out_buf;
113 /* Not compressed? Then return the original buffer. */
114 if ( ((unsigned char)in_buf[0] != 0x1F) ||
115 ((unsigned char)in_buf[1] != 0x8B) )
116 {
117 if ( out_size != NULL )
118 *out_size = in_size;
119 return (char *)in_buf;
120 }
122 out_len = (unsigned char)in_buf[in_size-4] +
123 (256 * ((unsigned char)in_buf[in_size-3] +
124 (256 * ((unsigned char)in_buf[in_size-2] +
125 (256 * (unsigned char)in_buf[in_size-1])))));
127 bzero(&zStream, sizeof(zStream));
128 out_buf = malloc(out_len + 16); /* Leave a little extra space */
129 if ( out_buf == NULL )
130 {
131 ERROR("Error mallocing buffer\n");
132 return NULL;
133 }
135 zStream.next_in = (unsigned char *)in_buf;
136 zStream.avail_in = in_size;
137 zStream.next_out = (unsigned char *)out_buf;
138 zStream.avail_out = out_len+16;
139 sts = inflateInit2(&zStream, (MAX_WBITS+32)); /* +32 means "handle gzip" */
140 if ( sts != Z_OK )
141 {
142 ERROR("inflateInit failed, sts %d\n", sts);
143 free(out_buf);
144 return NULL;
145 }
147 /* Inflate in one pass/call */
148 sts = inflate(&zStream, Z_FINISH);
149 if ( sts != Z_STREAM_END )
150 {
151 ERROR("inflate failed, sts %d\n", sts);
152 free(out_buf);
153 return NULL;
154 }
156 if ( out_size != NULL )
157 *out_size = out_len;
159 return out_buf;
160 }
162 /*******************/
164 int pin_table(
165 int xc_handle, unsigned int type, unsigned long mfn, domid_t dom)
166 {
167 struct mmuext_op op;
169 op.cmd = type;
170 op.arg1.mfn = mfn;
172 if ( xc_mmuext_op(xc_handle, &op, 1, dom) < 0 )
173 return 1;
175 return 0;
176 }
178 /* This is shared between save and restore, and may generally be useful. */
179 unsigned long csum_page(void *page)
180 {
181 int i;
182 unsigned long *p = page;
183 unsigned long long sum=0;
185 for ( i = 0; i < (PAGE_SIZE/sizeof(unsigned long)); i++ )
186 sum += p[i];
188 return sum ^ (sum>>32);
189 }
191 __attribute__((weak)) int xc_hvm_build(
192 int xc_handle,
193 uint32_t domid,
194 int memsize,
195 const char *image_name)
196 {
197 return -ENOSYS;
198 }