X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Finclude%2Fpalacios%2Fvmm_checkpoint.h;h=8bd5f5abea627a71d01b56a7452135fa46182f78;hb=626494b00fd477070f7eb43693eb16c4dc45f66b;hp=4281d5e1e2bc2948df9f76aa9b1a18363f815414;hpb=793f9cd53a472668dbeb16341085e5512484485c;p=palacios.git diff --git a/palacios/include/palacios/vmm_checkpoint.h b/palacios/include/palacios/vmm_checkpoint.h index 4281d5e..8bd5f5a 100644 --- a/palacios/include/palacios/vmm_checkpoint.h +++ b/palacios/include/palacios/vmm_checkpoint.h @@ -12,6 +12,8 @@ * All rights reserved. * * Authors: Madhav Suresh + * Mark Cartwright (live migration) + * Peter Dinda (store interface changes) * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "V3VEE_LICENSE". @@ -23,28 +25,156 @@ #ifdef __V3VEE__ #include -#include + + +/* + This code implements both checkpointing and live migration. The + main difference between these two is how the memory of the VM is + transfered. + + A checkpoint is written to/read from a checkpoint store. A + checkpoint store is conceptually an unseekable stream. This allows + us to reuse the same model for things like: + + - checkpoint to memory + - checkpoint to directory of files + - checkpoint to gem5 + - checkpoint to network + - live migrate over network + + To save data to a checkpoint store, you first open a context on the + checkpoint store, then you save data to the context. The data + consists of blobs tagged with strings. + + Only a single context can be open at a time, and a context cannot be + reopened once it has been closed. These invariants are also essential + to maximizing compatability with different implementations. + + The result of these constraints is that the stream that the + checkpoint store records will look like: + + [contextname1][tag1len][tag1]][datalen][data][tag2len][tag2][datalen][data].... + [contextname2][tag1len][tag1]][datalen][data][tag2len][tag2][datalen][data].... + ... + + The code implemented here assures that + [tag?len][tag?][datalen][data] is written as shown above. The + checkpoint store handles [contextname?] internally. For example, it + might use the context names as files for a checkpoint, or it might + communicate the context names over a network stream. + + To add checkpointing to your code, the primary thing you need to do + is implement save and load functions. For a device, you then add them + to your dev_ops structure. The save function takes an context. + You then write on this context using one of the following functions/macros: + + 1. v3_chkpt_save(context, tag, datalen, dataptr); + 2. V3_CHKPT_SAVE(context, tag, data, faillabel); + 3. V3_CHKPT_SAVE_AUTOTAG(context, data, faillabel) + + Here (2) is a macro that computes the data length from sizeof(data) + while (3) does the same, and uses as the tag the name of the variable data. + We strongly recommend the use of (2). + + These functions and macros will return -1 if the save is unsuccessful. + The faillabel argumnent is optional, if supplied and an error occurs, + the macro will goto the label. + + Some classes of devices, for example IDE HDs and CD-ROMs, and PCI + devices have a class-specific component and a device-specific + component. For such devices, the class implementation (e.g., IDE, PCI) + will provide a class-specific save function that should be called first + in the device's save function. For example: + + #include + + static int my_device_save(struct v3_chkpt_ctx *ctx, void *priv) + { + struct my_device *dev = priv; + + if (v3_pci_save(ctx, dev->pci)<0) { + goto fail; + } + + V3_CHKPT_SAVE(ctx, "myfoo", dev->foo, failout),; + V3_CHKPT_SAVE(ctx, "mybar", dev->bar, failout); + + // Success + return 0; + +failout: + + PrintError(info->vm_info, info, "Failed to save device\n"); + return -1; + + } + + The load side is symmetric. + +*/ struct v3_chkpt; struct v3_chkpt_ctx { - struct v3_chkpt * chkpt; - struct v3_chkpt_ctx * parent; - void * store_ctx; + struct v3_chkpt * chkpt; + void *store_ctx; }; -int v3_chkpt_save(struct v3_chkpt_ctx * ctx, char * tag, uint64_t len, void * buf); -int v3_chkpt_load(struct v3_chkpt_ctx * ctx, char * tag, uint64_t len, void * buf); -int v3_chkpt_close_ctx(struct v3_chkpt_ctx * ctx); -struct v3_chkpt_ctx * v3_chkpt_open_ctx(struct v3_chkpt * chkpt, struct v3_chkpt_ctx * parent, char * name); +/* + * You do not need to look behind this curtain + */ +#define SELECT(x,A,FUNC, ...) FUNC +#define V3_CHKPT_SAVE_BASE(context, tag, data) v3_chkpt_save(context,tag,sizeof(data),&(data)) +#define V3_CHKPT_SAVE_LABELED(context, tag, data, faillabel) (({if (V3_CHKPT_SAVE_BASE(context,tag,data)<0) { goto faillabel; } 0; }), 0) +#define V3_CHKPT_LOAD_BASE(context, tag, data) v3_chkpt_load(context,tag,sizeof(data),&(data)) +#define V3_CHKPT_LOAD_LABELED(context, tag, data, faillabel) (({if (V3_CHKPT_LOAD_BASE(context,tag,data)<0) { goto faillabel; } 0; }), 0) +/* + * Safe to open your eyes again + */ + + +// +// Functions and macros to save to a context +// +// +int v3_chkpt_save(struct v3_chkpt_ctx * ctx, char * tag, uint64_t len, void * buf); +#define V3_CHKPT_SAVE(context, tag, data, ...) SELECT(,##__VA_ARGS__,V3_CHKPT_SAVE_LABELED(context,tag,data,__VA_ARGS__),V3_CHKPT_SAVE_BASE(context,tag,data)) +#define V3_CHKPT_SAVE_AUTOTAG(context, data, ...) V3_CHKPT_SAVE(context, #data ,data,__VA_ARGS__) + +// +// Funtions and macros to load from a context +// +// +int v3_chkpt_load(struct v3_chkpt_ctx * ctx, char * tag, uint64_t len, void * buf); +#define V3_CHKPT_LOAD(context, tag, data, ...) SELECT(,##__VA_ARGS__,V3_CHKPT_LOAD_LABELED(context,tag,data,__VA_ARGS__),V3_CHKPT_LOAD_BASE(context,tag,data)) +#define V3_CHKPT_LOAD_AUTOTAG(context, data, ...) V3_CHKPT_LOAD(context, #data ,data,__VA_ARGS__) + -int v3_chkpt_save_vm(struct v3_vm_info * vm, char * store, char * url); -int v3_chkpt_load_vm(struct v3_vm_info * vm, char * store, char * url); +struct v3_chkpt_ctx * v3_chkpt_open_ctx(struct v3_chkpt * chkpt, char * name); +int v3_chkpt_close_ctx(struct v3_chkpt_ctx * ctx); +typedef uint64_t v3_chkpt_options_t; +// The options are a bitwise or of the following +#define V3_CHKPT_OPT_NONE 0 +#define V3_CHKPT_OPT_SKIP_MEM 1 // don't write memory to store +#define V3_CHKPT_OPT_SKIP_DEVS 2 // don't write devices to store +#define V3_CHKPT_OPT_SKIP_CORES 4 // don't write core arch ind data to store +#define V3_CHKPT_OPT_SKIP_ARCHDEP 8 // don't write core arch dep data to store + +int v3_chkpt_save_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts); +int v3_chkpt_load_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts); + +#ifdef V3_CONFIG_LIVE_MIGRATION +int v3_chkpt_send_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts); +int v3_chkpt_receive_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts); +#endif + +int V3_init_checkpoint(); +int V3_deinit_checkpoint(); #endif