direct-io.hg

view tools/libxc/xg_save_restore.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 f8af7041bf5b
children 98271ea55d94
line source
1 /*
2 ** xg_save_restore.h
3 **
4 ** Defintions and utilities for save / restore.
5 */
7 #include "xc_private.h"
9 /*
10 ** We process save/restore/migrate in batches of pages; the below
11 ** determines how many pages we (at maximum) deal with in each batch.
12 */
13 #define MAX_BATCH_SIZE 1024 /* up to 1024 pages (4MB) at a time */
15 /* When pinning page tables at the end of restore, we also use batching. */
16 #define MAX_PIN_BATCH 1024
20 /*
21 ** Determine various platform information required for save/restore, in
22 ** particular:
23 **
24 ** - the maximum MFN on this machine, used to compute the size of
25 ** the M2P table;
26 **
27 ** - the starting virtual address of the the hypervisor; we use this
28 ** to determine which parts of guest address space(s) do and don't
29 ** require canonicalization during save/restore; and
30 **
31 ** - the number of page-table levels for save/ restore. This should
32 ** be a property of the domain, but for the moment we just read it
33 ** from the hypervisor.
34 **
35 ** Returns 1 on success, 0 on failure.
36 */
37 static int get_platform_info(int xc_handle, uint32_t dom,
38 /* OUT */ unsigned long *max_mfn,
39 /* OUT */ unsigned long *hvirt_start,
40 /* OUT */ unsigned int *pt_levels)
42 {
43 xen_capabilities_info_t xen_caps = "";
44 xen_platform_parameters_t xen_params;
46 if (xc_version(xc_handle, XENVER_platform_parameters, &xen_params) != 0)
47 return 0;
49 if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0)
50 return 0;
52 *max_mfn = xc_memory_op(xc_handle, XENMEM_maximum_ram_page, NULL);
54 *hvirt_start = xen_params.virt_start;
56 if (strstr(xen_caps, "xen-3.0-x86_64"))
57 *pt_levels = 4;
58 else if (strstr(xen_caps, "xen-3.0-x86_32p"))
59 *pt_levels = 3;
60 else if (strstr(xen_caps, "xen-3.0-x86_32"))
61 *pt_levels = 2;
62 else
63 return 0;
65 return 1;
66 }
69 /*
70 ** Save/restore deal with the mfn_to_pfn (M2P) and pfn_to_mfn (P2M) tables.
71 ** The M2P simply holds the corresponding PFN, while the top bit of a P2M
72 ** entry tell us whether or not the the PFN is currently mapped.
73 */
75 #define PFN_TO_KB(_pfn) ((_pfn) << (PAGE_SHIFT - 10))
76 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
79 /*
80 ** The M2P is made up of some number of 'chunks' of at least 2MB in size.
81 ** The below definitions and utility function(s) deal with mapping the M2P
82 ** regarldess of the underlying machine memory size or architecture.
83 */
84 #define M2P_SHIFT L2_PAGETABLE_SHIFT_PAE
85 #define M2P_CHUNK_SIZE (1 << M2P_SHIFT)
86 #define M2P_SIZE(_m) ROUNDUP(((_m) * sizeof(xen_pfn_t)), M2P_SHIFT)
87 #define M2P_CHUNKS(_m) (M2P_SIZE((_m)) >> M2P_SHIFT)
89 /* Size in bytes of the P2M (rounded up to the nearest PAGE_SIZE bytes) */
90 #define P2M_SIZE ROUNDUP((max_pfn * sizeof(xen_pfn_t)), PAGE_SHIFT)
92 /* Number of xen_pfn_t in a page */
93 #define fpp (PAGE_SIZE/sizeof(xen_pfn_t))
95 /* Number of entries in the pfn_to_mfn_frame_list */
96 #define P2M_FL_ENTRIES (((max_pfn)+fpp-1)/fpp)
98 /* Size in bytes of the pfn_to_mfn_frame_list */
99 #define P2M_FL_SIZE ((P2M_FL_ENTRIES)*sizeof(unsigned long))
101 /* Number of entries in the pfn_to_mfn_frame_list_list */
102 #define P2M_FLL_ENTRIES (((max_pfn)+(fpp*fpp)-1)/(fpp*fpp))
104 /* Current guests allow 8MB 'slack' in their P2M */
105 #define NR_SLACK_ENTRIES ((8 * 1024 * 1024) / PAGE_SIZE)
107 /* Is the given PFN within the 'slack' region at the top of the P2M? */
108 #define IS_REAL_PFN(_pfn) ((max_pfn - (_pfn)) > NR_SLACK_ENTRIES)
110 /* Returns TRUE if the PFN is currently mapped */
111 #define is_mapped(pfn_type) (!((pfn_type) & 0x80000000UL))
113 #define INVALID_P2M_ENTRY (~0UL)