kernel-based memory checkpoint/restart
RFC PATCH 1/1 kernel-based memory checkpoint/restart
The following is the necessary code to checkpoint and restart a
single process's memory, with no shared memory. This is a
portion of patches posted to the [email protected] list. If you want to play with this, you can get the rest of the code
there.
At the containers mini-conference before OLS, the consensus among all the stakeholders was that doing checkpoint/restart in the kernel as much as possible was the best approach. With this approach, the kernel will export a relatively opaque 'blob' of data to userspace which can then be handed to the new kernel at restore time. This is different from what's been described at the kernel summit in previous years, so I'm mostly forwarding this to let people know of this change in direction.
The 'blob' will contain copies of select portions of kernel structures such as vmas and mm_structs. It will also contain copies of the actual memory that the process uses. Any changes in this blob's format between kernel revisions can be handled by an in-userspace conversion program.
This is a similar approach to virtually all of the commercial checkpoint/restart products out there, as well as the research project Zap.
Sorry about the C++ comments, please ignore them for now. :)
Notes on the dump format:
For each vma, there is a 'struct cr_vma'; if the vma is file-mapped, it will be followed by the file name. The cr_vma->npages will tell how many pages were dumped for this vma. Then it will be followed by the actual data: first a dump of the addresses of all dumped pages (npages entries) followed by a dump of the contents of all dumped pages (npages pages). Then will come the next vma and so on.
---
linux-2.6.git-dave/ckpt/Makefile | 2 linux-2.6.git-dave/ckpt/checkpoint.c | 6 linux-2.6.git-dave/ckpt/ckpt_hdr.h | 28 ++ linux-2.6.git-dave/ckpt/ckpt_mem.c | 421 +++++++++++++++++++++++++++++++++++ linux-2.6.git-dave/ckpt/ckpt_mem.h | 32 ++ linux-2.6.git-dave/ckpt/restart.c | 6 linux-2.6.git-dave/ckpt/rstr_mem.c | 415 ++++++++++++++++++++++++++++++++++ linux-2.6.git-dave/ckpt/sys.c | 8 8 files changed, 907 insertions(+), 11 deletions(-)
ckpt/checkpoint.c renamed from ckpt/checkpoint.c~memory_part +3 -3
@@ -333,9 +333,9 @@ static int cr_write_task(struct cr_ctx * ret =cr_write_task_struct (ctx, t);CR_PRINTK ("ret (task_struct) %d\n" , ret); -// if (!ret) -// ret = cr_write_mm(ctx, t); -// CR_PRINTK("ret (mm) %d\n", ret); +if (!ret) + ret =cr_write_mm (ctx, t); +CR_PRINTK ("ret (mm) %d\n" , ret);if (!ret) ret =cr_write_thread (ctx, t);CR_PRINTK ("ret (thread) %d\n" , ret);
ckpt/ckpt_mem.c new file +421 -0
421 lines not on this page · raw message
ckpt/ckpt_mem.h new file +32 -0
@@ -0,0 +1,32 @@ +/* +* Generic container checkpoint-restart +* +* Copyright (C) 2008 Oren Laadan +* +* This file is subject to the terms and conditions of the GNU General Public +* License. See the file COPYING in the main directory of the Linux +* distribution for more details. +*/ + +#include <linux/mm_types.h> + +/* page-array chains: each pgarr hols a list of <addr,page> tuples */ +struct cr_pgarr { +unsigned long *addrs; +struct page **pages; +struct cr_pgarr *next; +unsigned short nleft; +unsigned short nused; +}; + +/* vma subtypes */ +enum { +CR_VMA_ANON =1 , +CR_VMA_FILE +}; + +extern void _cr_pgarr_release (struct cr_ctx *ctx,struct cr_pgarr *pgarr); +extern void cr_pgarr_release (struct cr_ctx *ctx); +extern void cr_pgarr_free (struct cr_ctx *ctx); +extern struct cr_pgarr *cr_pgarr_alloc (struct cr_ctx *ctx,struct cr_pgarr **pgnew); +extern struct cr_pgarr *cr_pgarr_prep (struct cr_ctx *ctx);
ckpt/Makefile renamed from ckpt/Makefile~memory_part +1 -1
@@ -1 +1 @@ -obj-y += sys.o checkpoint.o restart.o +obj-y += sys.o checkpoint.o restart.o ckpt_mem.o rstr_mem.o
ckpt/restart.c renamed from ckpt/restart.c~memory_part +3 -3
@@ -301,9 +301,9 @@ static int cr_read_task(struct cr_ctx *c ret =cr_read_task_struct (ctx);CR_PRINTK ("ret (task_struct) %d\n" , ret); -// if (!ret) -// ret = cr_read_mm(ctx); -// CR_PRINTK("ret (mm) %d\n", ret); +if (!ret) + ret =cr_read_mm (ctx); +CR_PRINTK ("ret (mm) %d\n" , ret);if (!ret) ret =cr_read_thread (ctx);CR_PRINTK ("ret (thread) %d\n" , ret);
ckpt/rstr_mem.c new file +415 -0
415 lines not on this page · raw message
ckpt/sys.c renamed from ckpt/sys.c~memory_part +4 -4
@@ -15,7 +15,7 @@#include <linux/capability.h> #include "ckpt.h" -//include "ckpt_mem.h" +#include "ckpt_mem.h" /* * helpers to write/read to/from the image file descriptor
@@ -119,7 +119,7 @@ void cr_ctx_free(struct cr_ctx *ctx)if (ctx->vfsroot)path_put (ctx->vfsroot); -//cr_pgarr_free(ctx); +cr_pgarr_free (ctx);free_pages ((unsigned long ) ctx->tbuf,CR_ORDER_TBUF );free_pages ((unsigned long ) ctx->hbuf,CR_ORDER_HBUF );
@@ -140,8 +140,8 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, sif (!ctx->tbuf || !ctx->hbuf) goto nomem; -//if (!cr_pgarr_alloc(ctx, &ctx->pgarr)) -// goto nomem; +if (!cr_pgarr_alloc (ctx, &ctx->pgarr)) + goto nomem; ctx->pid = pid; ctx->flags = flags;
ckpt/ckpt_hdr.h renamed from ckpt/ckpt_hdr.h~memory_part +28 -0
@@ -113,3 +113,31 @@ struct cr_hdr_cpu { union thread_xstate xstate; /* i387 */ };#endif + +struct cr_hdr_mm { +__u32 tag;/* sharing identifier */ +__u64 start_code, end_code, start_data, end_data; +__u64 start_brk, brk, start_stack; +__u64 arg_start, arg_end, env_start, env_end; +__s16 map_count; +}; + +#if defined(CONFIG_X86 ) +struct cr_hdr_mm_context { +__s16 ldt_entry_size; +__s16 nldt; +}; +#endif + +struct cr_hdr_vma { +__u32 how; + +__u64 vm_start; +__u64 vm_end; +__u64 vm_page_prot; +__u64 vm_flags; +__u64 vm_pgoff; + +__s16 npages; +__s16 namelen; +};
_