kernel-based checkpoint-restart
v2 cover kernel-based checkpoint-restart
These patches are from Oren Laadan. I've refactored them a bit to make them a wee bit more reviewable by:
1. Removing code that we're not yet using
2. Separating out i386 code into a separate patch
3. Simplyifying the filename handling
This should also be at least build-bisetable.
TODO:
- Investigate using anon_inodes for the sys_checkpoint() side
- Move all the structure declarations to somewhere that we can easily export them to userspace.
- Lots of ABI issues to work out.
- Combine the "cleanup" patches later in the series into the base patches.
--
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 that what had been proposed before, which was that a userspace application would be responsible for collecting all of this data. We were also planning on adding lots of new, little kernel interfaces for all of the things that needed checkpointing. This unites those into a single, grand interface.
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.
These patches basically serialize internel kernel state and write it out to a file descriptor. The checkpoint and restore are done with two new system calls: sys_checkpoint and sys_restart.
In this incarnation, they can only work checkpoint and restore a single task. The task's address space may consist of only private, simple vma's - anonymous or file-mapped.
--
Oren's original announcement
In the recent mini-summit at OLS 2008 and the following days it was agreed to tackle the checkpoint/restart (CR) by beginning with a very simple case: save and restore a single task, with simple memory layout, disregarding other task state such as files, signals etc.
Following these discussions I coded a prototype that can do exactly that, as a starter. This code adds two system calls - sys_checkpoint and sys_restart - that a task can call to save and restore its state respectively. It also demonstrates how the checkpoint image file can be formatted, as well as show its nested nature (e.g. cr_write_mm() -> cr_write_vma() nesting).
The state that is saved/restored is the following:
* some of the task_struct
* some of the thread_struct and thread_info
* the cpu state (including FPU)
* the memory address space
[The patch is against commit fb2e405fc1fc8b20d9c78eaa1c7fd5a297efde43 of Linus's tree (uhhh.. don't ask why), but against tonight's head too].
In the current code, sys_checkpoint will checkpoint the current task, although the logic exists to checkpoint other tasks (not in the checkpointee's execution context). A simple loop will extend this to handle multiple processes. sys_restart restarts the current tasks, and with multiple tasks each task will call the syscall independently. (Actually, to checkpoint outside the context of a task, it is also necessary to also handle restart-block logic when saving/restoring the thread data).
It takes longer to describe what isn't implemented or supported by this prototype ... basically everything that isn't as simple as the above.
As for containers - since we still don't have a representation for a container, this patch has no notion of a container. The tests for consistent namespaces (and isolation) are also omitted.
Below are two example programs: one uses checkpoint (called ckpt) and one uses restart (called rstr). Execute like this (as a superuser):
orenl:~/test$ ./ckpt > out.1
hello, world! (ret=1) <-- sys_checkpoint returns positive id
<-- ctrl-c
orenl:~/test$ ./ckpt > out.2
hello, world! (ret=2)
<-- ctrl-c
orenl:~/test$ ./rstr < out.1
hello, world! (ret=0) <-- sys_restart return 0(if you check the output of ps, you'll see that "rstr" changed its name to "ckpt", as expected).
Hoping this will accelerate the discussion. Comments are welcome. Let the fun begin :)
Oren.
============================== ckpt.c ================================
#define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <asm/unistd_32.h>
#include <sys/syscall.h>
int main(int argc, char *argv[])
{
pid_t pid = getpid();
int ret;
ret = syscall(__NR_checkpoint, pid, STDOUT_FILENO, 0);
if (ret < 0)
perror("checkpoint");
fprintf(stderr, "hello, world! (ret=%d)\n", ret);
while (1)
;
return 0;
}============================== rstr.c ================================
#define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <asm/unistd_32.h>
#include <sys/syscall.h>
int main(int argc, char *argv[])
{
pid_t pid = getpid();
int ret;
ret = syscall(__NR_restart, pid, STDIN_FILENO, 0);
if (ret < 0)
perror("restart");
printf("should not reach here !\n");
return 0;
}_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers
RFC PATCH v2 1/9 checkpoint-restart: general infrastructure
This patch adds those interfaces, as well as all of the helpers needed to easily manage the file format.
The code is roughly broken out as follows:
ckpt/sys.c - user/kernel data transfer, as well as setting up of the
checkpoint/restart context (a per-checkpoint data structure for housekeeping)ckpt/checkpoint.c - output wrappers and basic checkpoint handling ckpt/restart.c - input wrappers and basic restart handling
Patches to add the per-architecture support as well as the actual work to do the memory checkpoint follow in subsequent patches.
changes from last version:
- Moved over to pr_debug() from CR_PRINTK()
- Moved magic number over to linux/magic.h
TODO:
- Investigate using anon_inodes for the sys_checkpoint() side
- Move all the structure declarations to somewhere that we can easily export them to userspace.
- Lots of ABI issues to work out.
---
oren-cr.git-dave/Makefile | 2 oren-cr.git-dave/checkpoint/Makefile | 1 oren-cr.git-dave/checkpoint/checkpoint.c | 208 +++++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/ckpt.h | 71 +++++++++ oren-cr.git-dave/checkpoint/ckpt_hdr.h | 69 +++++++++ oren-cr.git-dave/checkpoint/restart.c | 190 +++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/sys.c | 233 +++++++++++++++++++++++++++++++ oren-cr.git-dave/include/linux/magic.h | 2 8 files changed, 775 insertions(+), 1 deletion(-)
checkpoint/checkpoint.c new file +208 -0
@@ -0,0 +1,208 @@ +/* +* Checkpoint logic and helpers +* +* 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/version.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/dcache.h> +#include <linux/magic.h> +#include <linux/mount.h> +#include <asm/ptrace.h> + +#include "ckpt.h" +#include "ckpt_hdr.h" + +/** +* cr_get_fname - return pathname of a given file +* @file: file pointer +* @buf: buffer for pathname +* @n: buffer length (in) and pathname length (out) +* +* if the buffer provivded by the caller is too small, allocate a new +* buffer; caller should call cr_put_pathname() for cleanup +*/ +char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n) +{ +char *fname; + + fname =__d_path (path, root, buf, *n); + +if (IS_ERR (fname) &&PTR_ERR (fname) == -ENAMETOOLONG ) { +if (!(buf = (char *)__get_free_pages (GFP_KERNEL ,0 ))) +return ERR_PTR (-ENOMEM ); + fname =__d_path (path, root, buf,PAGE_SIZE ); +if (IS_ERR (fname)) +free_pages ((unsigned long ) buf,0 ); + } +if (!IS_ERR (fname)) + *n = (buf + *n - fname); + +return fname; +} + +/** +* cr_put_fname - (possibly) cleanup pathname buffer +* @buf: original buffer that was given to cr_get_pathname() +* @fname: resulting pathname from cr_get_pathname() +* @n: length of original buffer +*/ +void cr_put_fname (char *buf,char *fname,int n) +{ +if (fname && (fname < buf || fname >= buf + n)) +free_pages ((unsigned long ) buf,0 ); +} + +/** +* cr_write_obj - write a record described by a cr_hdr +* @ctx: checkpoint context +* @h: record descriptor +* @buf: record buffer +*/ +int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf) +{ +int ret; + +if ((ret =cr_kwrite (ctx, h,sizeof (*h))) <0 ) +return ret; +return cr_kwrite (ctx, buf, h->len); +} + +/** +* cr_write_str - write a string record +* @ctx: checkpoint context +* @str: string buffer +* @n: string length +*/ +int cr_write_str (struct cr_ctx *ctx,char *str,int n) +{ +struct cr_hdr h; + + h.type =CR_HDR_STR ; + h.len = n; + h.id =0 ; + +return cr_write_obj (ctx, &h, str); +} + +/* write the checkpoint header */ +static int cr_write_hdr (struct cr_ctx *ctx) +{ +struct cr_hdr h; +struct cr_hdr_head *hh = ctx->tbuf; +struct timeval ktv; + + h.type =CR_HDR_HEAD ; + h.len =sizeof (hh); + h.id =0 ; + +do_gettimeofday (&ktv); + + hh->magic =CR_HEADER_MAGIC ; + hh->major = (LINUX_VERSION_CODE >>16 ) &0xff ; + hh->minor = (LINUX_VERSION_CODE >>8 ) &0xff ; + hh->patch = (LINUX_VERSION_CODE ) &0xff ; + + hh->version =1 ; + + hh->flags = ctx->flags; + hh->time = ktv.tv_sec; + +return cr_write_obj (ctx, &h, hh); +} + +/* write the checkpoint trailer */ +static int cr_write_tail (struct cr_ctx *ctx) +{ +struct cr_hdr h; +struct cr_hdr_tail *hh = ctx->tbuf; + + h.type =CR_HDR_TAIL ; + h.len =sizeof (*hh); + h.id =0 ; + + hh->magic =CR_HEADER_MAGIC ; + hh->cksum[0 ] = hh->cksum[1 ] =1 ;/* TBD ... */ + +return cr_write_obj (ctx, &h, hh); +} + +/* dump the task_struct of a given task */ +static int cr_write_task_struct (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_task *hh = ctx->tbuf; + + h.type =CR_HDR_TASK ; + h.len =sizeof (*hh); + h.id = ctx->pid; + + hh->state = t->state; + hh->exit_state = t->exit_state; + hh->exit_code = t->exit_code; + hh->exit_signal = t->exit_signal; + + hh->pid = t->pid; + hh->tgid = t->tgid; + + hh->utime = t->utime; + hh->stime = t->stime; + hh->utimescaled = t->utimescaled; + hh->stimescaled = t->stimescaled; + hh->gtime = t->gtime; + hh->prev_utime = t->prev_utime; + hh->prev_stime = t->prev_stime; + hh->nvcsw = t->nvcsw; + hh->nivcsw = t->nivcsw; + hh->start_time_sec = t->start_time.tv_sec; + hh->start_time_nsec = t->start_time.tv_nsec; + hh->real_start_time_sec = t->real_start_time.tv_sec; + hh->real_start_time_nsec = t->real_start_time.tv_nsec; + hh->min_flt = t->min_flt; + hh->maj_flt = t->maj_flt; + + hh->task_comm_len =TASK_COMM_LEN ; +memcpy (hh->comm, t->comm,TASK_COMM_LEN ); + +return cr_write_obj (ctx, &h, hh); +} + +/* dump the entire state of a given task */ +static int cr_write_task (struct cr_ctx *ctx,struct task_struct *t) +{ +int ret ; + +BUG_ON (t->state ==TASK_DEAD ); + + ret =cr_write_task_struct (ctx, t); +pr_debug ("ret (task_struct) %d\n" , ret); + +return ret; +} + +int do_checkpoint (struct cr_ctx *ctx) +{ +int ret; + +/* FIX: need to test whether container is checkpointable */ + + ret =cr_write_hdr (ctx); +if (!ret) + ret =cr_write_task (ctx, current); +if (!ret) + ret =cr_write_tail (ctx); + +/* on success, return (unique) checkpoint identifier */ +if (!ret) + ret = ctx->crid; + +return ret; +}
checkpoint/ckpt.h new file +71 -0
71 lines not on this page · raw message
checkpoint/ckpt_hdr.h new file +69 -0
69 lines not on this page · raw message
checkpoint/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-y += sys.o checkpoint.o restart.o
checkpoint/restart.c new file +190 -0
190 lines not on this page · raw message
checkpoint/sys.c new file +233 -0
233 lines not on this page · raw message
include/linux/magic.h renamed from include/linux/magic.h~0001-checkpoint-restart-general-infrastructure +2 -0
@@ -42,4 +42,6 @@#define FUTEXFS_SUPER_MAGIC 0xBAD1DEA#define INOTIFYFS_SUPER_MAGIC 0x2BAD1DEA +#define CR_HEADER_MAGIC 0x002d2a00 +#endif /* __LINUX_MAGIC_H__ */
Makefile renamed from Makefile~0001-checkpoint-restart-general-infrastructure +1 -1
@@ -619,7 +619,7 @@ export mod_strip_cmd ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ +core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ checkpoint/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
_
Re: [RFC v2][PATCH 1/9] checkpoint-restart: general infrastructure
Quoted 238 lines · Dave Hansen
This patch adds those interfaces, as well as all of the helpers needed to easily manage the file format.
The code is roughly broken out as follows:
ckpt/sys.c- user/kernel data transfer, as well as setting up of the
checkpoint/restart context (a per-checkpoint data structure for housekeeping)ckpt/checkpoint.c- output wrappers and basic checkpoint handlingckpt/restart.c- input wrappers and basic restart handlingPatches to add the per-architecture support as well as the actual work to do the memory checkpoint follow in subsequent patches.
changes from last version:
- Moved over topr_debug()fromCR_PRINTK()
- Moved magic number over tolinux/magic.hTODO:
- Investigate usinganon_inodesfor thesys_checkpoint()side
- Move all the structure declarations to somewhere that we can easily export them to userspace.
- Lots of ABI issues to work out.Signed-off-by Oren Laadan <[email protected]>---
oren-cr.git-dave/Makefile | 2 oren-cr.git-dave/checkpoint/Makefile | 1 oren-cr.git-dave/checkpoint/checkpoint.c | 208 +++++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/ckpt.h | 71 +++++++++ oren-cr.git-dave/checkpoint/ckpt_hdr.h | 69 +++++++++ oren-cr.git-dave/checkpoint/restart.c | 190 +++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/sys.c | 233 +++++++++++++++++++++++++++++++ oren-cr.git-dave/include/linux/magic.h | 2 8 files changed, 775 insertions(+), 1 deletion(-)diff -puN
/dev/nullcheckpoint/checkpoint.ccheckpoint/checkpoint.c new file +197
-0@@ -0,0 +1,208 @@ +/* +* Checkpoint logic and helpers +* +* 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/version.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/dcache.h> +#include <linux/magic.h> +#include <linux/mount.h> +#include <asm/ptrace.h> + +#include "ckpt.h" +#include "ckpt_hdr.h" + +/** +* cr_get_fname - return pathname of a given file +* @file: file pointer +* @buf: buffer for pathname +* @n: buffer length (in) and pathname length (out) +* +* if the buffer provivded by the caller is too small, allocate a new +* buffer; caller should call cr_put_pathname() for cleanup +*/ +char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n) +{ +char *fname; + + fname =__d_path (path, root, buf, *n); + +if (IS_ERR (fname) &&PTR_ERR (fname) == -ENAMETOOLONG ) { +if (!(buf = (char *)__get_free_pages (GFP_KERNEL ,0 ))) +return ERR_PTR (-ENOMEM ); + fname =__d_path (path, root, buf,PAGE_SIZE ); +if (IS_ERR (fname)) +free_pages ((unsigned long ) buf,0 ); + } +if (!IS_ERR (fname)) + *n = (buf + *n - fname); + +return fname; +} + +/** +* cr_put_fname - (possibly) cleanup pathname buffer +* @buf: original buffer that was given to cr_get_pathname() +* @fname: resulting pathname from cr_get_pathname() +* @n: length of original buffer +*/ +void cr_put_fname (char *buf,char *fname,int n) +{ +if (fname && (fname < buf || fname >= buf + n)) +free_pages ((unsigned long ) buf,0 ); +} + +/** +* cr_write_obj - write a record described by a cr_hdr +* @ctx: checkpoint context +* @h: record descriptor +* @buf: record buffer +*/ +int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf) +{ +int ret; + +if ((ret =cr_kwrite (ctx, h,sizeof (*h))) <0 ) +return ret; +return cr_kwrite (ctx, buf, h->len); +} + +/** +* cr_write_str - write a string record +* @ctx: checkpoint context +* @str: string buffer +* @n: string length +*/ +int cr_write_str (struct cr_ctx *ctx,char *str,int n) +{ +struct cr_hdr h; + + h.type =CR_HDR_STR ; + h.len = n; + h.id =0 ; + +return cr_write_obj (ctx, &h, str); +} + +/* write the checkpoint header */ +static int cr_write_hdr (struct cr_ctx *ctx) +{ +struct cr_hdr h; +struct cr_hdr_head *hh = ctx->tbuf; +struct timeval ktv; + + h.type =CR_HDR_HEAD ; + h.len =sizeof (hh); + h.id =0 ; + +do_gettimeofday (&ktv); + + hh->magic =CR_HEADER_MAGIC ; + hh->major = (LINUX_VERSION_CODE >>16 ) &0xff ; + hh->minor = (LINUX_VERSION_CODE >>8 ) &0xff ; + hh->patch = (LINUX_VERSION_CODE ) &0xff ; + + hh->version =1 ; + + hh->flags = ctx->flags; + hh->time = ktv.tv_sec; + +return cr_write_obj (ctx, &h, hh); +} + +/* write the checkpoint trailer */ +static int cr_write_tail (struct cr_ctx *ctx) +{ +struct cr_hdr h; +struct cr_hdr_tail *hh = ctx->tbuf; + + h.type =CR_HDR_TAIL ; + h.len =sizeof (*hh); + h.id =0 ; + + hh->magic =CR_HEADER_MAGIC ; + hh->cksum[0 ] = hh->cksum[1 ] =1 ;/* TBD ... */ + +return cr_write_obj (ctx, &h, hh); +} + +/* dump the task_struct of a given task */ +static int cr_write_task_struct (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_task *hh = ctx->tbuf; + + h.type =CR_HDR_TASK ; + h.len =sizeof (*hh); + h.id = ctx->pid; + + hh->state = t->state; + hh->exit_state = t->exit_state; + hh->exit_code = t->exit_code; + hh->exit_signal = t->exit_signal; + + hh->pid = t->pid; + hh->tgid = t->tgid; + + hh->utime = t->utime; + hh->stime = t->stime; + hh->utimescaled = t->utimescaled; + hh->stimescaled = t->stimescaled; + hh->gtime = t->gtime; + hh->prev_utime = t->prev_utime; + hh->prev_stime = t->prev_stime; + hh->nvcsw = t->nvcsw; + hh->nivcsw = t->nivcsw; + hh->start_time_sec = t->start_time.tv_sec; + hh->start_time_nsec = t->start_time.tv_nsec; + hh->real_start_time_sec = t->real_start_time.tv_sec; + hh->real_start_time_nsec = t->real_start_time.tv_nsec; + hh->min_flt = t->min_flt; + hh->maj_flt = t->maj_flt; + + hh->task_comm_len =TASK_COMM_LEN ; +memcpy (hh->comm, t->comm,TASK_COMM_LEN ); + +return cr_write_obj (ctx, &h, hh); +} + +/* dump the entire state of a given task */ +static int cr_write_task (struct cr_ctx *ctx,struct task_struct *t) +{ +int ret ; + +BUG_ON (t->state ==TASK_DEAD ); + + ret =cr_write_task_struct (ctx, t); +pr_debug ("ret (task_struct) %d\n" , ret); + +return ret; +} + +int do_checkpoint (struct cr_ctx *ctx) +{ +int ret; + +/* FIX: need to test whether container is checkpointable */ + + ret =cr_write_hdr (ctx);
checkpoint/checkpoint.c line 207
Quoted 10 lines
checkpoint/checkpoint.c new file +10
-0+if (!ret) + ret =cr_write_task (ctx, current); +if (!ret) + ret =cr_write_tail (ctx); + +/* on success, return (unique) checkpoint identifier */ +if (!ret) + ret = ctx->crid; + +return ret;
How about conforming to existing kernel style by inverting the ret tests and using goto here:
ret = cr_write_hdr(ctx); if (ret) goto out; ret = cr_write_task(ctx, current); if (ret) goto out; ret = cr_write_tail(ctx); if (ret) goto out; ret = ctx->crid; out: return ret;
That means that if we aren't always assigning to ret we won't always need to (re)test it. Granted the compiler output is probably the same, but I think this is much more readable by reviewers. It may also be easier to maintain since you won't have to test ret before adding new code here.
Quoted 335 lines
checkpoint/checkpoint.c new file +1
-0+}diff -puN
/dev/nullcheckpoint/ckpt.hcheckpoint/ckpt.h new file +71
-0@@ -0,0 +1,71 @@ +#ifndef _CKPT_CKPT_H_ +#define _CKPT_CKPT_H_ +/* +* 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/path.h> +#include <linux/fs.h> + +struct cr_pgarr ; + +struct cr_ctx { +pid_t pid;/* container identifier */ +int crid;/* unique checkpoint id */ + +unsigned long flags; +unsigned long oflags;/* restart: old flags */ + +struct file *file; +int total;/* total read/written */ + +void *tbuf;/* temp: to avoid many alloc/dealloc */ +void *hbuf;/* header: to avoid many alloc/dealloc */ +int hpos; + +struct cr_pgarr *pgarr; +struct cr_pgarr *pgcur; + +struct path *vfsroot;/* container root */ +}; + +/* cr_ctx: flags */ +#define CR_CTX_CKPT 0x1 +#define CR_CTX_RSTR 0x2 + +/* allocation defaults */ +#define CR_ORDER_TBUF 1 +#define CR_ORDER_HBUF 1 + +#define CR_TBUF_TOTAL ((PAGE_SIZE << CR_ORDER_TBUF) / sizeof(void *)) +#define CR_HBUF_TOTAL ((PAGE_SIZE << CR_ORDER_HBUF) / sizeof(void *)) + +extern void cr_put_fname (char *buf,char *fname,int n); +extern char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n); + +extern int cr_uwrite (struct cr_ctx *ctx,void *buf,int count); +extern int cr_kwrite (struct cr_ctx *ctx,void *buf,int count); +extern int cr_uread (struct cr_ctx *ctx,void *buf,int count); +extern int cr_kread (struct cr_ctx *ctx,void *buf,int count); + +struct cr_hdr ; + +extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf); +extern int cr_write_str (struct cr_ctx *ctx,char *str,int n); +extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t); + +extern int cr_read_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf,int n); +extern int cr_read_obj_type (struct cr_ctx *ctx,void *buf,int n,int type); +extern int cr_read_str (struct cr_ctx *ctx,void *str,int n); +extern int cr_read_mm (struct cr_ctx *ctx); + +extern int do_checkpoint (struct cr_ctx *ctx); +extern int do_restart (struct cr_ctx *ctx); + +#endif /* _CKPT_CKPT_H_ */ diff -puN
/dev/nullcheckpoint/ckpt_hdr.hcheckpoint/ckpt_hdr.h new file +69
-0@@ -0,0 +1,69 @@ +/* +* 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/types.h> + +struct cr_hdr { +__s16 type; +__s16 len; +__u32 id; +}; + +enum { +CR_HDR_HEAD =1 , +CR_HDR_STR , + +CR_HDR_TASK =101 , +CR_HDR_THREAD , +CR_HDR_CPU , + +CR_HDR_MM =201 , +CR_HDR_VMA , +CR_HDR_MM_CONTEXT , + +CR_HDR_TAIL =5001 +}; + +struct cr_hdr_head { +__u32 magic; +__u16 major; +__u16 minor; +__u16 patch; +__u16 version; +__u32 flags;/* checkpoint options */ +__u64 time;/* when checkpoint taken */ +}; + +struct cr_hdr_tail { +__u32 magic; +__u32 cksum[2 ]; +}; + +struct cr_hdr_task { +__u64 state; +__u32 exit_state; +__u32 exit_code, exit_signal; + +__u16 pid; +__u16 tgid; + +__u64 utime, stime, utimescaled, stimescaled; +__u64 gtime; +__u64 prev_utime, prev_stime; +__u64 nvcsw, nivcsw; +__u64 start_time_sec, start_time_nsec; +__u64 real_start_time_sec, real_start_time_nsec; +__u64 min_flt, maj_flt; + +__s16 task_comm_len; +char comm[TASK_COMM_LEN ]; +}; + +diff -puN
/dev/nullcheckpoint/Makefilecheckpoint/Makefile new file +1
-0@@ -0,0 +1 @@ +obj-y += sys.o checkpoint.o restart.odiff -puN
/dev/nullcheckpoint/restart.ccheckpoint/restart.c new file +177
-0@@ -0,0 +1,190 @@ +/* +* Restart logic and helpers +* +* 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. +*/ + +/* +* During restart the code reads in data from the chekcpoint image into a +* temporary buffer (ctx->hbuf). Because operations can be nested, one +* should call cr_hbuf_get() to reserve space in the buffer, and then +* cr_hbuf_put() when it no longer needs that space +*/ + +#include <linux/version.h> +#include <linux/magic.h> +#include <linux/sched.h> +#include <linux/file.h> + +#include "ckpt.h" +#include "ckpt_hdr.h" + +/** +* cr_hbuf_get - reserve space on the hbuf +* @ctx: checkpoint context +* @n: number of bytes to reserve +*/ +void *cr_hbuf_get (struct cr_ctx *ctx,int n) +{ +void *ptr; + +BUG_ON (ctx->hpos + n >CR_HBUF_TOTAL ); + ptr = (void *) (((char *) ctx->hbuf) + ctx->hpos); + ctx->hpos += n; +return ptr; +} + +/** +* cr_hbuf_put - unreserve space on the hbuf +* @ctx: checkpoint context +* @n: number of bytes to reserve +*/ +void cr_hbuf_put (struct cr_ctx *ctx,int n) +{ +BUG_ON (ctx->hpos < n); + ctx->hpos -= n; +} + +/** +* cr_read_obj - read a whole record (cr_hdr followed by payload) +* @ctx: checkpoint context +* @h: record descriptor +* @buf: record buffer +* @n: available buffer size +*/ +int cr_read_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf,int n) +{ +int ret; + + ret =cr_kread (ctx, h,sizeof (*h)); +if (ret <0 ) +return ret; + +pr_debug ("type %d len %d id %d (%d)\n" , h->type, h->len, h->id, n); +if (h->len <0 || h->len > n) +return -EINVAL ; + +return cr_kread (ctx, buf, h->len); +} + +/** +* cr_read_obj_type - read a whole record of expected type +* @ctx: checkpoint context +* @buf: record buffer +* @n: available buffer size +* @type: expected record type +*/ +int cr_read_obj_type (struct cr_ctx *ctx,void *buf,int n,int type) +{ +struct cr_hdr h; +int ret; + + ret =cr_read_obj (ctx, &h, buf, n); +if (!ret) + ret = (h.type == type ? h.id : -EINVAL ); +return ret; +} + +/** +* cr_read_str - read a string record +* @ctx: checkpoint context +* @str: string buffer +* @n: string length +*/ +int cr_read_str (struct cr_ctx *ctx,void *str,int n) +{ +return cr_read_obj_type (ctx, str, n,CR_HDR_STR ); +} + +/* read the checkpoint header */ +static int cr_read_hdr (struct cr_ctx *ctx) +{ +struct cr_hdr_head *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_HEAD ); +if (ret <0 ) +return ret; + +if (hh->magic !=CR_HEADER_MAGIC || hh->version !=1 || + hh->major != ((LINUX_VERSION_CODE >>16 ) &0xff ) || + hh->minor != ((LINUX_VERSION_CODE >>8 ) &0xff ) || + hh->patch != ((LINUX_VERSION_CODE ) &0xff )) +return -EINVAL ; + +if (hh->flags & ~CR_CTX_CKPT ) +return -EINVAL ; + + ctx->oflags = hh->flags; + +cr_hbuf_put (ctx,sizeof (*hh)); +return 0 ; +} + +/* read the checkpoint trailer */ +static int cr_read_tail (struct cr_ctx *ctx) +{ +struct cr_hdr_tail *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TAIL ); +if (ret <0 ) +return ret; + +if (hh->magic !=CR_HEADER_MAGIC || + hh->cksum[0 ] !=1 || hh->cksum[1 ] !=1 ) +return -EINVAL ; + +cr_hbuf_put (ctx,sizeof (*hh)); +return 0 ; +} + +/* read the task_struct into the current task */ +static int cr_read_task_struct (struct cr_ctx *ctx) +{ +struct cr_hdr_task *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct task_struct *t = current; +int ret; + + ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TASK ); +if (ret <0 ) +return ret; + +/* for now, only restore t->comm */ +if (hh->task_comm_len <0 || hh->task_comm_len >TASK_COMM_LEN ) +return -EINVAL ; + +memset (t->comm,0 ,TASK_COMM_LEN ); +memcpy (t->comm, hh->comm, hh->task_comm_len); + +cr_hbuf_put (ctx,sizeof (*hh)); +return 0 ; +} + +/* read the entire state of the current task */ +static int cr_read_task (struct cr_ctx *ctx) +{ +int ret; + + ret =cr_read_task_struct (ctx); +pr_debug ("ret (task_struct) %d\n" , ret); + +return ret; +}
checkpoint/restart.c line 187
Quoted 10 lines
checkpoint/restart.c new file +10
-0+ +int do_restart (struct cr_ctx *ctx) +{ +int ret; + + ret =cr_read_hdr (ctx); +if (!ret) + ret =cr_read_task (ctx); +if (!ret) + ret =cr_read_tail (ctx);
same comment
Quoted 267 lines
checkpoint/restart.c new file +3
-0+ +return ret; +}diff -puN
/dev/nullcheckpoint/sys.ccheckpoint/sys.c new file +233
-0@@ -0,0 +1,233 @@ +/* +* 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/sched.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/uaccess.h> +#include <linux/capability.h> + +#include "ckpt.h" + +/* +* helpers to write/read to/from the image file descriptor +* +* cr_uwrite() - write a user-space buffer to the checkpoint image +* cr_kwrite() - write a kernel-space buffer to the checkpoint image +* cr_uread() - read from the checkpoint image to a user-space buffer +* cr_kread() - read from the checkpoint image to a kernel-space buffer +* +*/ + +/* (temporarily added file_pos_read() and file_pos_write() because they +* are static in fs/read_write.c... should cleanup and remove later) */ +static inline loff_t file_pos_read (struct file *file) +{ +return file->f_pos; +} + +static inline void file_pos_write (struct file *file,loff_t pos) +{ + file->f_pos = pos; +} + +int cr_uwrite (struct cr_ctx *ctx,void *buf,int count) +{ +struct file *file = ctx->file; +ssize_t nwrite; +int nleft; + +for (nleft = count; nleft; nleft -= nwrite) { +loff_t pos =file_pos_read (file); + nwrite =vfs_write (file, (char __user *) buf, nleft, &pos); +file_pos_write (file, pos); +if (unlikely (nwrite <=0 ))/* zero tolerance */ +return (nwrite ? : -EIO ); + buf += nwrite; + } + + ctx->total += count; +return 0 ; +} + +int cr_kwrite (struct cr_ctx *ctx,void *buf,int count) +{ +mm_segment_t oldfs; +int ret; + + oldfs =get_fs (); +set_fs (KERNEL_DS ); + ret =cr_uwrite (ctx, buf, count); +set_fs (oldfs); + +return ret; +} + +int cr_uread (struct cr_ctx *ctx,void *buf,int count) +{ +struct file *file = ctx->file; +ssize_t nread; +int nleft; + +for (nleft = count; nleft; nleft -= nread) { +loff_t pos =file_pos_read (file); + nread =vfs_read (file, (char __user *) buf, nleft, &pos); +file_pos_write (file, pos); +if (unlikely (nread <=0 ))/* zero tolerance */ +return (nread ? : -EIO ); + buf += nread; + } + + ctx->total += count; +return 0 ; +} + +int cr_kread (struct cr_ctx *ctx,void *buf,int count) +{ +mm_segment_t oldfs; +int ret; + + oldfs =get_fs (); +set_fs (KERNEL_DS ); + ret =cr_uread (ctx, buf, count); +set_fs (oldfs); + +return ret; +} + + +/* +* helpers to manage CR contexts: allocated for each checkpoint and/or +* restart operation, and persists until the operation is completed. +*/ + +static atomic_t cr_ctx_count;/* unique checkpoint identifier */ + +void cr_ctx_free (struct cr_ctx *ctx) +{ + +if (ctx->file) +fput (ctx->file); +if (ctx->vfsroot) +path_put (ctx->vfsroot); + +free_pages ((unsigned long ) ctx->tbuf,CR_ORDER_TBUF ); +free_pages ((unsigned long ) ctx->hbuf,CR_ORDER_HBUF ); + +kfree (ctx); +} + +struct cr_ctx *cr_ctx_alloc (pid_t pid,struct file *file,unsigned long flags) +{ +struct cr_ctx *ctx; + + ctx =kzalloc (sizeof (*ctx),GFP_KERNEL ); +if (!ctx) +return NULL ; + + ctx->tbuf = (void *)__get_free_pages (GFP_KERNEL ,CR_ORDER_TBUF ); + ctx->hbuf = (void *)__get_free_pages (GFP_KERNEL ,CR_ORDER_HBUF ); +if (!ctx->tbuf || !ctx->hbuf) + goto nomem; + + ctx->pid = pid; + ctx->flags = flags; + + ctx->file = file; +get_file (file); + +/* assume checkpointer is in container's root vfs */ + ctx->vfsroot = ¤t->fs->root; +path_get (ctx->vfsroot); + + ctx->crid =atomic_inc_return (&cr_ctx_count); + +return ctx; + + nomem: +cr_ctx_free (ctx); +return NULL ; +} + +/** +* sys_checkpoint - checkpoint a container +* @pid: pid of the container init(1) process +* @fd: file to which dump the checkpoint image +* @flags: checkpoint operation flags +*/ +asmlinkage long sys_checkpoint (pid_t pid,int fd,unsigned long flags) +{ +struct cr_ctx *ctx; +struct file *file; +int fput_needed; +int ret; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + + file =fget_light (fd, &fput_needed); +if (!file) +return -EBADF ; + +/* no flags for now */ +if (flags) +return -EINVAL ; + + ctx =cr_ctx_alloc (pid, file, flags |CR_CTX_CKPT ); +if (!ctx) { +fput_light (file, fput_needed); +return -ENOMEM ; + } + + ret =do_checkpoint (ctx); + +cr_ctx_free (ctx); +fput_light (file, fput_needed); +pr_debug ("ckpt retval = %d\n" , ret); +return ret; +} + +/** +* sys_restart - restart a container +* @crid: checkpoint image identifier +* @fd: file from which read the checkpoint image +* @flags: restart operation flags +*/ +asmlinkage long sys_restart (int crid,int fd,unsigned long flags) +{ +struct cr_ctx *ctx; +struct file *file; +int fput_needed; +int ret; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + + file =fget_light (fd, &fput_needed); +if (!file) +return -EBADF ; + +/* no flags for now */ +if (flags) +return -EINVAL ; + + ctx =cr_ctx_alloc (crid, file, flags |CR_CTX_RSTR ); +if (!ctx) { +fput_light (file, fput_needed); +return -ENOMEM ; + } + + ret =do_restart (ctx); + +cr_ctx_free (ctx); +fput_light (file, fput_needed); +pr_debug ("restart retval = %d\n" , ret); +return ret; +}diff -puN
include/linux/magic.h~0001-checkpoint-restart-general-infrastructureinclude/linux/magic.hinclude/linux/magic.h renamed from include/linux/magic.h~0001-checkpoint-restart-general-infrastructure +2
-0@@ -42,4 +42,6 @@#define FUTEXFS_SUPER_MAGIC 0xBAD1DEA#define INOTIFYFS_SUPER_MAGIC 0x2BAD1DEA +#define CR_HEADER_MAGIC 0x002d2a00 +#endif /* __LINUX_MAGIC_H__ */ diff -puN Makefile~0001-checkpoint-restart-general-infrastructure
MakefileMakefile renamed from Makefile~0001-checkpoint-restart-general-infrastructure +1
-1@@ -619,7 +619,7 @@ export mod_strip_cmd ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ +core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ checkpoint/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \_
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linux-foundation.org/mailman/listinfo/containers
Re: [RFC v2][PATCH 1/9] checkpoint-restart: general infrastructure
In reply to Dave HansenQuoted 238 lines · Dave Hansen
This patch adds those interfaces, as well as all of the helpers needed to easily manage the file format.
The code is roughly broken out as follows:
ckpt/sys.c- user/kernel data transfer, as well as setting up of the
checkpoint/restart context (a per-checkpoint data structure for housekeeping)ckpt/checkpoint.c- output wrappers and basic checkpoint handlingckpt/restart.c- input wrappers and basic restart handlingPatches to add the per-architecture support as well as the actual work to do the memory checkpoint follow in subsequent patches.
changes from last version:
- Moved over topr_debug()fromCR_PRINTK()
- Moved magic number over tolinux/magic.hTODO:
- Investigate usinganon_inodesfor thesys_checkpoint()side
- Move all the structure declarations to somewhere that we can easily export them to userspace.
- Lots of ABI issues to work out.Signed-off-by Oren Laadan <[email protected]>---
oren-cr.git-dave/Makefile | 2 oren-cr.git-dave/checkpoint/Makefile | 1 oren-cr.git-dave/checkpoint/checkpoint.c | 208 +++++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/ckpt.h | 71 +++++++++ oren-cr.git-dave/checkpoint/ckpt_hdr.h | 69 +++++++++ oren-cr.git-dave/checkpoint/restart.c | 190 +++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/sys.c | 233 +++++++++++++++++++++++++++++++ oren-cr.git-dave/include/linux/magic.h | 2 8 files changed, 775 insertions(+), 1 deletion(-)diff -puN
/dev/nullcheckpoint/checkpoint.ccheckpoint/checkpoint.c new file +197
-0@@ -0,0 +1,208 @@ +/* +* Checkpoint logic and helpers +* +* 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/version.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/dcache.h> +#include <linux/magic.h> +#include <linux/mount.h> +#include <asm/ptrace.h> + +#include "ckpt.h" +#include "ckpt_hdr.h" + +/** +* cr_get_fname - return pathname of a given file +* @file: file pointer +* @buf: buffer for pathname +* @n: buffer length (in) and pathname length (out) +* +* if the buffer provivded by the caller is too small, allocate a new +* buffer; caller should call cr_put_pathname() for cleanup +*/ +char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n) +{ +char *fname; + + fname =__d_path (path, root, buf, *n); + +if (IS_ERR (fname) &&PTR_ERR (fname) == -ENAMETOOLONG ) { +if (!(buf = (char *)__get_free_pages (GFP_KERNEL ,0 ))) +return ERR_PTR (-ENOMEM ); + fname =__d_path (path, root, buf,PAGE_SIZE ); +if (IS_ERR (fname)) +free_pages ((unsigned long ) buf,0 ); + } +if (!IS_ERR (fname)) + *n = (buf + *n - fname); + +return fname; +} + +/** +* cr_put_fname - (possibly) cleanup pathname buffer +* @buf: original buffer that was given to cr_get_pathname() +* @fname: resulting pathname from cr_get_pathname() +* @n: length of original buffer +*/ +void cr_put_fname (char *buf,char *fname,int n) +{ +if (fname && (fname < buf || fname >= buf + n)) +free_pages ((unsigned long ) buf,0 ); +} + +/** +* cr_write_obj - write a record described by a cr_hdr +* @ctx: checkpoint context +* @h: record descriptor +* @buf: record buffer +*/ +int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf) +{ +int ret; + +if ((ret =cr_kwrite (ctx, h,sizeof (*h))) <0 ) +return ret; +return cr_kwrite (ctx, buf, h->len); +} + +/** +* cr_write_str - write a string record +* @ctx: checkpoint context +* @str: string buffer +* @n: string length +*/ +int cr_write_str (struct cr_ctx *ctx,char *str,int n) +{ +struct cr_hdr h; + + h.type =CR_HDR_STR ; + h.len = n; + h.id =0 ; + +return cr_write_obj (ctx, &h, str); +} + +/* write the checkpoint header */ +static int cr_write_hdr (struct cr_ctx *ctx) +{ +struct cr_hdr h; +struct cr_hdr_head *hh = ctx->tbuf; +struct timeval ktv; + + h.type =CR_HDR_HEAD ; + h.len =sizeof (hh); + h.id =0 ; + +do_gettimeofday (&ktv); + + hh->magic =CR_HEADER_MAGIC ; + hh->major = (LINUX_VERSION_CODE >>16 ) &0xff ; + hh->minor = (LINUX_VERSION_CODE >>8 ) &0xff ; + hh->patch = (LINUX_VERSION_CODE ) &0xff ; + + hh->version =1 ; + + hh->flags = ctx->flags; + hh->time = ktv.tv_sec; + +return cr_write_obj (ctx, &h, hh); +} + +/* write the checkpoint trailer */ +static int cr_write_tail (struct cr_ctx *ctx) +{ +struct cr_hdr h; +struct cr_hdr_tail *hh = ctx->tbuf; + + h.type =CR_HDR_TAIL ; + h.len =sizeof (*hh); + h.id =0 ; + + hh->magic =CR_HEADER_MAGIC ; + hh->cksum[0 ] = hh->cksum[1 ] =1 ;/* TBD ... */ + +return cr_write_obj (ctx, &h, hh); +} + +/* dump the task_struct of a given task */ +static int cr_write_task_struct (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_task *hh = ctx->tbuf; + + h.type =CR_HDR_TASK ; + h.len =sizeof (*hh); + h.id = ctx->pid; + + hh->state = t->state; + hh->exit_state = t->exit_state; + hh->exit_code = t->exit_code; + hh->exit_signal = t->exit_signal; + + hh->pid = t->pid; + hh->tgid = t->tgid; + + hh->utime = t->utime; + hh->stime = t->stime; + hh->utimescaled = t->utimescaled; + hh->stimescaled = t->stimescaled; + hh->gtime = t->gtime; + hh->prev_utime = t->prev_utime; + hh->prev_stime = t->prev_stime; + hh->nvcsw = t->nvcsw; + hh->nivcsw = t->nivcsw; + hh->start_time_sec = t->start_time.tv_sec; + hh->start_time_nsec = t->start_time.tv_nsec; + hh->real_start_time_sec = t->real_start_time.tv_sec; + hh->real_start_time_nsec = t->real_start_time.tv_nsec; + hh->min_flt = t->min_flt; + hh->maj_flt = t->maj_flt; + + hh->task_comm_len =TASK_COMM_LEN ; +memcpy (hh->comm, t->comm,TASK_COMM_LEN ); + +return cr_write_obj (ctx, &h, hh); +} + +/* dump the entire state of a given task */ +static int cr_write_task (struct cr_ctx *ctx,struct task_struct *t) +{ +int ret ; + +BUG_ON (t->state ==TASK_DEAD ); + + ret =cr_write_task_struct (ctx, t); +pr_debug ("ret (task_struct) %d\n" , ret); + +return ret; +} + +int do_checkpoint (struct cr_ctx *ctx) +{ +int ret; + +/* FIX: need to test whether container is checkpointable */ + + ret =cr_write_hdr (ctx);
checkpoint/checkpoint.c line 207
Quoted 10 lines
checkpoint/checkpoint.c new file +10
-0+if (!ret) + ret =cr_write_task (ctx, current); +if (!ret) + ret =cr_write_tail (ctx); + +/* on success, return (unique) checkpoint identifier */ +if (!ret) + ret = ctx->crid; + +return ret;
How about conforming to existing kernel style by inverting the ret tests and using goto here:
ret = cr_write_hdr(ctx); if (ret) goto out; ret = cr_write_task(ctx, current); if (ret) goto out; ret = cr_write_tail(ctx); if (ret) goto out; ret = ctx->crid; out: return ret;
That means that if we aren't always assigning to ret we won't always need to (re)test it. Granted the compiler output is probably the same, but I think this is much more readable by reviewers. It may also be easier to maintain since you won't have to test ret before adding new code here.
Quoted 335 lines
checkpoint/checkpoint.c new file +1
-0+}diff -puN
/dev/nullcheckpoint/ckpt.hcheckpoint/ckpt.h new file +71
-0@@ -0,0 +1,71 @@ +#ifndef _CKPT_CKPT_H_ +#define _CKPT_CKPT_H_ +/* +* 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/path.h> +#include <linux/fs.h> + +struct cr_pgarr ; + +struct cr_ctx { +pid_t pid;/* container identifier */ +int crid;/* unique checkpoint id */ + +unsigned long flags; +unsigned long oflags;/* restart: old flags */ + +struct file *file; +int total;/* total read/written */ + +void *tbuf;/* temp: to avoid many alloc/dealloc */ +void *hbuf;/* header: to avoid many alloc/dealloc */ +int hpos; + +struct cr_pgarr *pgarr; +struct cr_pgarr *pgcur; + +struct path *vfsroot;/* container root */ +}; + +/* cr_ctx: flags */ +#define CR_CTX_CKPT 0x1 +#define CR_CTX_RSTR 0x2 + +/* allocation defaults */ +#define CR_ORDER_TBUF 1 +#define CR_ORDER_HBUF 1 + +#define CR_TBUF_TOTAL ((PAGE_SIZE << CR_ORDER_TBUF) / sizeof(void *)) +#define CR_HBUF_TOTAL ((PAGE_SIZE << CR_ORDER_HBUF) / sizeof(void *)) + +extern void cr_put_fname (char *buf,char *fname,int n); +extern char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n); + +extern int cr_uwrite (struct cr_ctx *ctx,void *buf,int count); +extern int cr_kwrite (struct cr_ctx *ctx,void *buf,int count); +extern int cr_uread (struct cr_ctx *ctx,void *buf,int count); +extern int cr_kread (struct cr_ctx *ctx,void *buf,int count); + +struct cr_hdr ; + +extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf); +extern int cr_write_str (struct cr_ctx *ctx,char *str,int n); +extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t); + +extern int cr_read_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf,int n); +extern int cr_read_obj_type (struct cr_ctx *ctx,void *buf,int n,int type); +extern int cr_read_str (struct cr_ctx *ctx,void *str,int n); +extern int cr_read_mm (struct cr_ctx *ctx); + +extern int do_checkpoint (struct cr_ctx *ctx); +extern int do_restart (struct cr_ctx *ctx); + +#endif /* _CKPT_CKPT_H_ */ diff -puN
/dev/nullcheckpoint/ckpt_hdr.hcheckpoint/ckpt_hdr.h new file +69
-0@@ -0,0 +1,69 @@ +/* +* 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/types.h> + +struct cr_hdr { +__s16 type; +__s16 len; +__u32 id; +}; + +enum { +CR_HDR_HEAD =1 , +CR_HDR_STR , + +CR_HDR_TASK =101 , +CR_HDR_THREAD , +CR_HDR_CPU , + +CR_HDR_MM =201 , +CR_HDR_VMA , +CR_HDR_MM_CONTEXT , + +CR_HDR_TAIL =5001 +}; + +struct cr_hdr_head { +__u32 magic; +__u16 major; +__u16 minor; +__u16 patch; +__u16 version; +__u32 flags;/* checkpoint options */ +__u64 time;/* when checkpoint taken */ +}; + +struct cr_hdr_tail { +__u32 magic; +__u32 cksum[2 ]; +}; + +struct cr_hdr_task { +__u64 state; +__u32 exit_state; +__u32 exit_code, exit_signal; + +__u16 pid; +__u16 tgid; + +__u64 utime, stime, utimescaled, stimescaled; +__u64 gtime; +__u64 prev_utime, prev_stime; +__u64 nvcsw, nivcsw; +__u64 start_time_sec, start_time_nsec; +__u64 real_start_time_sec, real_start_time_nsec; +__u64 min_flt, maj_flt; + +__s16 task_comm_len; +char comm[TASK_COMM_LEN ]; +}; + +diff -puN
/dev/nullcheckpoint/Makefilecheckpoint/Makefile new file +1
-0@@ -0,0 +1 @@ +obj-y += sys.o checkpoint.o restart.odiff -puN
/dev/nullcheckpoint/restart.ccheckpoint/restart.c new file +177
-0@@ -0,0 +1,190 @@ +/* +* Restart logic and helpers +* +* 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. +*/ + +/* +* During restart the code reads in data from the chekcpoint image into a +* temporary buffer (ctx->hbuf). Because operations can be nested, one +* should call cr_hbuf_get() to reserve space in the buffer, and then +* cr_hbuf_put() when it no longer needs that space +*/ + +#include <linux/version.h> +#include <linux/magic.h> +#include <linux/sched.h> +#include <linux/file.h> + +#include "ckpt.h" +#include "ckpt_hdr.h" + +/** +* cr_hbuf_get - reserve space on the hbuf +* @ctx: checkpoint context +* @n: number of bytes to reserve +*/ +void *cr_hbuf_get (struct cr_ctx *ctx,int n) +{ +void *ptr; + +BUG_ON (ctx->hpos + n >CR_HBUF_TOTAL ); + ptr = (void *) (((char *) ctx->hbuf) + ctx->hpos); + ctx->hpos += n; +return ptr; +} + +/** +* cr_hbuf_put - unreserve space on the hbuf +* @ctx: checkpoint context +* @n: number of bytes to reserve +*/ +void cr_hbuf_put (struct cr_ctx *ctx,int n) +{ +BUG_ON (ctx->hpos < n); + ctx->hpos -= n; +} + +/** +* cr_read_obj - read a whole record (cr_hdr followed by payload) +* @ctx: checkpoint context +* @h: record descriptor +* @buf: record buffer +* @n: available buffer size +*/ +int cr_read_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf,int n) +{ +int ret; + + ret =cr_kread (ctx, h,sizeof (*h)); +if (ret <0 ) +return ret; + +pr_debug ("type %d len %d id %d (%d)\n" , h->type, h->len, h->id, n); +if (h->len <0 || h->len > n) +return -EINVAL ; + +return cr_kread (ctx, buf, h->len); +} + +/** +* cr_read_obj_type - read a whole record of expected type +* @ctx: checkpoint context +* @buf: record buffer +* @n: available buffer size +* @type: expected record type +*/ +int cr_read_obj_type (struct cr_ctx *ctx,void *buf,int n,int type) +{ +struct cr_hdr h; +int ret; + + ret =cr_read_obj (ctx, &h, buf, n); +if (!ret) + ret = (h.type == type ? h.id : -EINVAL ); +return ret; +} + +/** +* cr_read_str - read a string record +* @ctx: checkpoint context +* @str: string buffer +* @n: string length +*/ +int cr_read_str (struct cr_ctx *ctx,void *str,int n) +{ +return cr_read_obj_type (ctx, str, n,CR_HDR_STR ); +} + +/* read the checkpoint header */ +static int cr_read_hdr (struct cr_ctx *ctx) +{ +struct cr_hdr_head *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_HEAD ); +if (ret <0 ) +return ret; + +if (hh->magic !=CR_HEADER_MAGIC || hh->version !=1 || + hh->major != ((LINUX_VERSION_CODE >>16 ) &0xff ) || + hh->minor != ((LINUX_VERSION_CODE >>8 ) &0xff ) || + hh->patch != ((LINUX_VERSION_CODE ) &0xff )) +return -EINVAL ; + +if (hh->flags & ~CR_CTX_CKPT ) +return -EINVAL ; + + ctx->oflags = hh->flags; + +cr_hbuf_put (ctx,sizeof (*hh)); +return 0 ; +} + +/* read the checkpoint trailer */ +static int cr_read_tail (struct cr_ctx *ctx) +{ +struct cr_hdr_tail *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TAIL ); +if (ret <0 ) +return ret; + +if (hh->magic !=CR_HEADER_MAGIC || + hh->cksum[0 ] !=1 || hh->cksum[1 ] !=1 ) +return -EINVAL ; + +cr_hbuf_put (ctx,sizeof (*hh)); +return 0 ; +} + +/* read the task_struct into the current task */ +static int cr_read_task_struct (struct cr_ctx *ctx) +{ +struct cr_hdr_task *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct task_struct *t = current; +int ret; + + ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TASK ); +if (ret <0 ) +return ret; + +/* for now, only restore t->comm */ +if (hh->task_comm_len <0 || hh->task_comm_len >TASK_COMM_LEN ) +return -EINVAL ; + +memset (t->comm,0 ,TASK_COMM_LEN ); +memcpy (t->comm, hh->comm, hh->task_comm_len); + +cr_hbuf_put (ctx,sizeof (*hh)); +return 0 ; +} + +/* read the entire state of the current task */ +static int cr_read_task (struct cr_ctx *ctx) +{ +int ret; + + ret =cr_read_task_struct (ctx); +pr_debug ("ret (task_struct) %d\n" , ret); + +return ret; +}
checkpoint/restart.c line 187
Quoted 10 lines
checkpoint/restart.c new file +10
-0+ +int do_restart (struct cr_ctx *ctx) +{ +int ret; + + ret =cr_read_hdr (ctx); +if (!ret) + ret =cr_read_task (ctx); +if (!ret) + ret =cr_read_tail (ctx);
same comment
Quoted 267 lines
checkpoint/restart.c new file +3
-0+ +return ret; +}diff -puN
/dev/nullcheckpoint/sys.ccheckpoint/sys.c new file +233
-0@@ -0,0 +1,233 @@ +/* +* 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/sched.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/uaccess.h> +#include <linux/capability.h> + +#include "ckpt.h" + +/* +* helpers to write/read to/from the image file descriptor +* +* cr_uwrite() - write a user-space buffer to the checkpoint image +* cr_kwrite() - write a kernel-space buffer to the checkpoint image +* cr_uread() - read from the checkpoint image to a user-space buffer +* cr_kread() - read from the checkpoint image to a kernel-space buffer +* +*/ + +/* (temporarily added file_pos_read() and file_pos_write() because they +* are static in fs/read_write.c... should cleanup and remove later) */ +static inline loff_t file_pos_read (struct file *file) +{ +return file->f_pos; +} + +static inline void file_pos_write (struct file *file,loff_t pos) +{ + file->f_pos = pos; +} + +int cr_uwrite (struct cr_ctx *ctx,void *buf,int count) +{ +struct file *file = ctx->file; +ssize_t nwrite; +int nleft; + +for (nleft = count; nleft; nleft -= nwrite) { +loff_t pos =file_pos_read (file); + nwrite =vfs_write (file, (char __user *) buf, nleft, &pos); +file_pos_write (file, pos); +if (unlikely (nwrite <=0 ))/* zero tolerance */ +return (nwrite ? : -EIO ); + buf += nwrite; + } + + ctx->total += count; +return 0 ; +} + +int cr_kwrite (struct cr_ctx *ctx,void *buf,int count) +{ +mm_segment_t oldfs; +int ret; + + oldfs =get_fs (); +set_fs (KERNEL_DS ); + ret =cr_uwrite (ctx, buf, count); +set_fs (oldfs); + +return ret; +} + +int cr_uread (struct cr_ctx *ctx,void *buf,int count) +{ +struct file *file = ctx->file; +ssize_t nread; +int nleft; + +for (nleft = count; nleft; nleft -= nread) { +loff_t pos =file_pos_read (file); + nread =vfs_read (file, (char __user *) buf, nleft, &pos); +file_pos_write (file, pos); +if (unlikely (nread <=0 ))/* zero tolerance */ +return (nread ? : -EIO ); + buf += nread; + } + + ctx->total += count; +return 0 ; +} + +int cr_kread (struct cr_ctx *ctx,void *buf,int count) +{ +mm_segment_t oldfs; +int ret; + + oldfs =get_fs (); +set_fs (KERNEL_DS ); + ret =cr_uread (ctx, buf, count); +set_fs (oldfs); + +return ret; +} + + +/* +* helpers to manage CR contexts: allocated for each checkpoint and/or +* restart operation, and persists until the operation is completed. +*/ + +static atomic_t cr_ctx_count;/* unique checkpoint identifier */ + +void cr_ctx_free (struct cr_ctx *ctx) +{ + +if (ctx->file) +fput (ctx->file); +if (ctx->vfsroot) +path_put (ctx->vfsroot); + +free_pages ((unsigned long ) ctx->tbuf,CR_ORDER_TBUF ); +free_pages ((unsigned long ) ctx->hbuf,CR_ORDER_HBUF ); + +kfree (ctx); +} + +struct cr_ctx *cr_ctx_alloc (pid_t pid,struct file *file,unsigned long flags) +{ +struct cr_ctx *ctx; + + ctx =kzalloc (sizeof (*ctx),GFP_KERNEL ); +if (!ctx) +return NULL ; + + ctx->tbuf = (void *)__get_free_pages (GFP_KERNEL ,CR_ORDER_TBUF ); + ctx->hbuf = (void *)__get_free_pages (GFP_KERNEL ,CR_ORDER_HBUF ); +if (!ctx->tbuf || !ctx->hbuf) + goto nomem; + + ctx->pid = pid; + ctx->flags = flags; + + ctx->file = file; +get_file (file); + +/* assume checkpointer is in container's root vfs */ + ctx->vfsroot = ¤t->fs->root; +path_get (ctx->vfsroot); + + ctx->crid =atomic_inc_return (&cr_ctx_count); + +return ctx; + + nomem: +cr_ctx_free (ctx); +return NULL ; +} + +/** +* sys_checkpoint - checkpoint a container +* @pid: pid of the container init(1) process +* @fd: file to which dump the checkpoint image +* @flags: checkpoint operation flags +*/ +asmlinkage long sys_checkpoint (pid_t pid,int fd,unsigned long flags) +{ +struct cr_ctx *ctx; +struct file *file; +int fput_needed; +int ret; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + + file =fget_light (fd, &fput_needed); +if (!file) +return -EBADF ; + +/* no flags for now */ +if (flags) +return -EINVAL ; + + ctx =cr_ctx_alloc (pid, file, flags |CR_CTX_CKPT ); +if (!ctx) { +fput_light (file, fput_needed); +return -ENOMEM ; + } + + ret =do_checkpoint (ctx); + +cr_ctx_free (ctx); +fput_light (file, fput_needed); +pr_debug ("ckpt retval = %d\n" , ret); +return ret; +} + +/** +* sys_restart - restart a container +* @crid: checkpoint image identifier +* @fd: file from which read the checkpoint image +* @flags: restart operation flags +*/ +asmlinkage long sys_restart (int crid,int fd,unsigned long flags) +{ +struct cr_ctx *ctx; +struct file *file; +int fput_needed; +int ret; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + + file =fget_light (fd, &fput_needed); +if (!file) +return -EBADF ; + +/* no flags for now */ +if (flags) +return -EINVAL ; + + ctx =cr_ctx_alloc (crid, file, flags |CR_CTX_RSTR ); +if (!ctx) { +fput_light (file, fput_needed); +return -ENOMEM ; + } + + ret =do_restart (ctx); + +cr_ctx_free (ctx); +fput_light (file, fput_needed); +pr_debug ("restart retval = %d\n" , ret); +return ret; +}diff -puN
include/linux/magic.h~0001-checkpoint-restart-general-infrastructureinclude/linux/magic.hinclude/linux/magic.h renamed from include/linux/magic.h~0001-checkpoint-restart-general-infrastructure +2
-0@@ -42,4 +42,6 @@#define FUTEXFS_SUPER_MAGIC 0xBAD1DEA#define INOTIFYFS_SUPER_MAGIC 0x2BAD1DEA +#define CR_HEADER_MAGIC 0x002d2a00 +#endif /* __LINUX_MAGIC_H__ */ diff -puN Makefile~0001-checkpoint-restart-general-infrastructure
MakefileMakefile renamed from Makefile~0001-checkpoint-restart-general-infrastructure +1
-1@@ -619,7 +619,7 @@ export mod_strip_cmd ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ +core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ checkpoint/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \_
_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers
RFC PATCH v2 2/9 Remove CAP_SYS_ADMIN for checkpoint/restart
In reply to Dave HansenWe need to do this so that we think about the security concerns as we add each and every bit of c/r functionality. There's nothing that we need privileges for, yet. Let's keep it that way as long as possible.
---
oren-cr.git-dave/checkpoint/sys.c | 6 ------ 1 file changed, 6 deletions(-)
checkpoint/sys.c renamed from checkpoint/sys.c~0003-Remove-CAP_SYS_ADMIN-for-checkpoint-restart +0 -6
@@ -169,9 +169,6 @@ asmlinkage long sys_checkpoint(pid_t pidint fput_needed;int ret; -if (!capable (CAP_SYS_ADMIN )) -return -EPERM ; - file =fget_light (fd, &fput_needed);if (!file)return -EBADF ;
@@ -207,9 +204,6 @@ asmlinkage long sys_restart(int crid, inint fput_needed;int ret; -if (!capable (CAP_SYS_ADMIN )) -return -EPERM ; - file =fget_light (fd, &fput_needed);if (!file)return -EBADF ;
_
RFC PATCH v2 3/9 checkpoint/restart: x86 support
In reply to Dave HansenThe original version of Oren's patch contained a good hunk of #ifdefs. I've extracted all of those and created a bit of an API for new architectures to follow.
Leaving Oren's sign-off because this is all still his code, even though he hasn't seen it mangled like this before.
---
oren-cr.git-dave/checkpoint/Makefile | 1 oren-cr.git-dave/checkpoint/checkpoint.c | 7 oren-cr.git-dave/checkpoint/ckpt.h | 3 oren-cr.git-dave/checkpoint/ckpt_arch.h | 6 oren-cr.git-dave/checkpoint/restart.c | 7 oren-cr.git-dave/checkpoint/x86.c | 270 +++++++++++++++++++++++++++++++ oren-cr.git-dave/include/asm-x86/ckpt.h | 46 +++++ 7 files changed, 340 insertions(+)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0004-checkpoint-restart-x86-support +7 -0
@@ -20,6 +20,7 @@#include "ckpt.h" #include "ckpt_hdr.h" +#include "ckpt_arch.h" /** * cr_get_fname - return pathname of a given file
@@ -184,6 +185,12 @@ static int cr_write_task(struct cr_ctx * ret =cr_write_task_struct (ctx, t);pr_debug ("ret (task_struct) %d\n" , ret); +if (!ret) + ret =cr_write_thread (ctx, t); +pr_debug ("ret (thread) %d\n" , ret); +if (!ret) + ret =cr_write_cpu (ctx, t); +pr_debug ("ret (cpu) %d\n" , ret);return ret; }
checkpoint/ckpt_arch.h new file +6 -0
@@ -0,0 +1,6 @@ +#include "ckpt.h" + +int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t); +int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t); +int cr_read_thread (struct cr_ctx *ctx); +int cr_read_cpu (struct cr_ctx *ctx);
checkpoint/ckpt.h renamed from checkpoint/ckpt.h~0004-checkpoint-restart-x86-support +3 -0
@@ -54,6 +54,9 @@ extern int cr_kwrite(struct cr_ctx *ctx,extern int cr_uread (struct cr_ctx *ctx,void *buf,int count);extern int cr_kread (struct cr_ctx *ctx,void *buf,int count); +extern void *cr_hbuf_get (struct cr_ctx *ctx,int size); +extern void cr_hbuf_put (struct cr_ctx *ctx,int n); +struct cr_hdr ;extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf);
checkpoint/Makefile renamed from checkpoint/Makefile~0004-checkpoint-restart-x86-support +1 -0
@@ -1 +1,2 @@ obj-y += sys.o checkpoint.o restart.o +obj-$(CONFIG_X86) += x86.o
checkpoint/restart.c renamed from checkpoint/restart.c~0004-checkpoint-restart-x86-support +7 -0
@@ -22,6 +22,7 @@#include "ckpt.h" #include "ckpt_hdr.h" +#include "ckpt_arch.h" /** * cr_hbuf_get - reserve space on the hbuf
@@ -172,6 +173,12 @@ static int cr_read_task(struct cr_ctx *c ret =cr_read_task_struct (ctx);pr_debug ("ret (task_struct) %d\n" , ret); +if (!ret) + ret =cr_read_thread (ctx); +pr_debug ("ret (thread) %d\n" , ret); +if (!ret) + ret =cr_read_cpu (ctx); +pr_debug ("ret (cpu) %d\n" , ret);return ret; }
checkpoint/x86.c new file +270 -0
270 lines not on this page · raw message
include/asm-x86/ckpt.h new file +46 -0
46 lines not on this page · raw message
_
RFC PATCH v2 4/9 checkpoint/restart: memory management
In reply to Dave HansenFor 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.
I guess I could also separate out the x86-specific bits here, but they're pretty small, comparatively.
---
oren-cr.git-dave/arch/x86/kernel/ldt.c | 2 oren-cr.git-dave/checkpoint/Makefile | 2 oren-cr.git-dave/checkpoint/ckpt_arch.h | 2 oren-cr.git-dave/checkpoint/ckpt_hdr.h | 21 + oren-cr.git-dave/checkpoint/ckpt_mem.c | 392 ++++++++++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/ckpt_mem.h | 32 ++ oren-cr.git-dave/checkpoint/rstr_mem.c | 354 ++++++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/sys.c | 13 - oren-cr.git-dave/checkpoint/x86.c | 83 ++++++ oren-cr.git-dave/include/asm-x86/ckpt.h | 5 oren-cr.git-dave/include/asm-x86/desc.h | 3 11 files changed, 895 insertions(+), 14 deletions(-)
arch/x86/kernel/ldt.c renamed from arch/x86/kernel/ldt.c~0005-checkpoint-restart-memory-management +1 -1
@@ -181,7 +181,7 @@ static int read_default_ldt(void __userreturn bytecount; } -static int write_ldt (void __user *ptr,unsigned long bytecount,int oldmode) +int write_ldt (void __user *ptr,unsigned long bytecount,int oldmode) {struct mm_struct *mm = current->mm;struct desc_struct ldt;
checkpoint/ckpt_arch.h renamed from checkpoint/ckpt_arch.h~0005-checkpoint-restart-memory-management +2 -0
@@ -4,3 +4,5 @@ int cr_write_thread(struct cr_ctx *ctx,int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t);int cr_read_thread (struct cr_ctx *ctx);int cr_read_cpu (struct cr_ctx *ctx); +int cr_write_mm_context (struct cr_ctx *ctx,struct mm_struct *mm); +int cr_read_mm_context (struct cr_ctx *ctx,struct mm_struct *mm);
checkpoint/ckpt_hdr.h renamed from checkpoint/ckpt_hdr.h~0005-checkpoint-restart-memory-management +21 -0
@@ -67,3 +67,24 @@ struct cr_hdr_task { }; + +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; +}; + +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; +};
checkpoint/ckpt_mem.c new file +392 -0
392 lines not on this page · raw message
checkpoint/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);
checkpoint/Makefile renamed from checkpoint/Makefile~0005-checkpoint-restart-memory-management +1 -1
@@ -1,2 +1,2 @@ -obj-y += sys.o checkpoint.o restart.o +obj-y += sys.o checkpoint.o restart.o ckpt_mem.o rstr_mem.o obj-$(CONFIG_X86) += x86.o
checkpoint/rstr_mem.c new file +354 -0
354 lines not on this page · raw message
checkpoint/sys.c renamed from checkpoint/sys.c~0005-checkpoint-restart-memory-management +2 -11
@@ -15,6 +15,7 @@#include <linux/capability.h> #include "ckpt.h" +#include "ckpt_mem.h" /* * helpers to write/read to/from the image file descriptor
@@ -118,8 +119,7 @@ void cr_ctx_free(struct cr_ctx *ctx)if (ctx->vfsroot)path_put (ctx->vfsroot); -free_pages ((unsigned long ) ctx->tbuf,CR_ORDER_TBUF ); -free_pages ((unsigned long ) ctx->hbuf,CR_ORDER_HBUF ); +cr_pgarr_free (ctx);kfree (ctx); }
@@ -132,11 +132,6 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, sif (!ctx)return NULL ; - ctx->tbuf = (void *)__get_free_pages (GFP_KERNEL ,CR_ORDER_TBUF ); - ctx->hbuf = (void *)__get_free_pages (GFP_KERNEL ,CR_ORDER_HBUF ); -if (!ctx->tbuf || !ctx->hbuf) - goto nomem; - ctx->pid = pid; ctx->flags = flags;
@@ -150,10 +145,6 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, s ctx->crid =atomic_inc_return (&cr_ctx_count);return ctx; - - nomem: -cr_ctx_free (ctx); -return NULL ; }/**
checkpoint/x86.c renamed from checkpoint/x86.c~0005-checkpoint-restart-memory-management +83 -0
91 lines not on this page · raw message
include/asm-x86/ckpt.h renamed from include/asm-x86/ckpt.h~0005-checkpoint-restart-memory-management +5 -0
@@ -43,4 +43,9 @@ struct cr_hdr_cpu { union thread_xstate xstate; /* i387 */ }; +struct cr_hdr_mm_context { +__s16 ldt_entry_size; +__s16 nldt; +}; +#endif /* __ASM_X86_CKPT_H */
include/asm-x86/desc.h renamed from include/asm-x86/desc.h~0005-checkpoint-restart-memory-management +2 -1
@@ -111,6 +111,8 @@ static inline void native_write_ldt_entrmemcpy (&ldt[entry], desc,8 ); } +int write_ldt (void __user *ptr,unsigned long bytecount,int oldmode); +static inline void native_write_gdt_entry (struct desc_struct *gdt,int entry,const void *desc,int type) {
@@ -394,7 +396,6 @@ static inline void set_system_gate_ist(ishll $16, base; \ movw idx * 8 + 2(gdt), lo_w; -#endif /* __ASSEMBLY__ */ #endif
_
RFC PATCH v2 2/9 Remove CAP_SYS_ADMIN for checkpoint/restart
In reply to Dave HansenWe need to do this so that we think about the security concerns as we add each and every bit of c/r functionality. There's nothing that we need privileges for, yet. Let's keep it that way as long as possible.
---
oren-cr.git-dave/checkpoint/sys.c | 6 ------ 1 file changed, 6 deletions(-)
checkpoint/sys.c renamed from checkpoint/sys.c~0003-Remove-CAP_SYS_ADMIN-for-checkpoint-restart +0 -6
@@ -169,9 +169,6 @@ asmlinkage long sys_checkpoint(pid_t pidint fput_needed;int ret; -if (!capable (CAP_SYS_ADMIN )) -return -EPERM ; - file =fget_light (fd, &fput_needed);if (!file)return -EBADF ;
@@ -207,9 +204,6 @@ asmlinkage long sys_restart(int crid, inint fput_needed;int ret; -if (!capable (CAP_SYS_ADMIN )) -return -EPERM ; - file =fget_light (fd, &fput_needed);if (!file)return -EBADF ;
_
RFC PATCH v2 6/9 Simplify filename handling for now
In reply to Dave HansenThe filename handling is a bit clunky, as one of the reviewers noted. It can allocate memory in one of two places and that makes things look a bit weird.
We don't *really* need the filename sitting around in its own buffer, so let's just combine the writing and the filename generation.
It moves the order in which the things in the VMA are done, but it doens't change the order in which they are written to the checkpoint file.
Note how much code this removes.
---
oren-cr.git-dave/checkpoint/checkpoint.c | 48 ++++++++++++------------------- oren-cr.git-dave/checkpoint/ckpt.h | 1 oren-cr.git-dave/checkpoint/ckpt_mem.c | 36 ++++++----------------- 3 files changed, 30 insertions(+), 55 deletions(-)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0007-fixup-filename-handling +19 -29
@@ -23,43 +23,33 @@#include "ckpt_arch.h" /** -* cr_get_fname - return pathname of a given file -* @file: file pointer -* @buf: buffer for pathname -* @n: buffer length (in) and pathname length (out) -* -* if the buffer provivded by the caller is too small, allocate a new -* buffer; caller should call cr_put_pathname() for cleanup +* cr_write_fname - write a string record for a filename +* @ctx: checkpoint context +* @path: path name to write +* @root: root from which to find the path */ -char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n) +int cr_write_fname (struct cr_ctx *ctx,struct path *path,struct path *root) { +char *fname_buf =kmalloc (PAGE_SIZE ,GFP_KERNEL );char *fname; +int ret; +int len; - fname =__d_path (path, root, buf, *n); +if (!fname_buf) +return -ENOMEM ; -if (IS_ERR (fname) &&PTR_ERR (fname) == -ENAMETOOLONG ) { -if (!(buf = (char *)__get_free_pages (GFP_KERNEL ,0 ))) -return ERR_PTR (-ENOMEM ); - fname =__d_path (path, root, buf,PAGE_SIZE ); -if (IS_ERR (fname)) -free_pages ((unsigned long ) buf,0 ); + fname =__d_path (path, root, fname_buf,PAGE_SIZE ); +if (IS_ERR (fname)) { + ret =PTR_ERR (fname); + goto out_free; } -if (!IS_ERR (fname)) - *n = (buf + *n - fname); -return fname; -} + len =PAGE_SIZE + fname_buf - fname; + ret =cr_write_str (ctx, fname, len); -/** -* cr_put_fname - (possibly) cleanup pathname buffer -* @buf: original buffer that was given to cr_get_pathname() -* @fname: resulting pathname from cr_get_pathname() -* @n: length of original buffer -*/ -void cr_put_fname (char *buf,char *fname,int n) -{ -if (fname && (fname < buf || fname >= buf + n)) -free_pages ((unsigned long ) buf,0 ); +out_free: +kfree (fname_buf); +return ret; }/**
checkpoint/ckpt.h renamed from checkpoint/ckpt.h~0007-fixup-filename-handling +1 -0
@@ -48,6 +48,7 @@ struct cr_ctx {extern void cr_put_fname (char *buf,char *fname,int n);extern char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n); +extern int cr_write_fname (struct cr_ctx *ctx,struct path *path,struct path *root);extern int cr_uwrite (struct cr_ctx *ctx,void *buf,int count);extern int cr_kwrite (struct cr_ctx *ctx,void *buf,int count);
checkpoint/ckpt_mem.c renamed from checkpoint/ckpt_mem.c~0007-fixup-filename-handling +10 -26
@@ -262,8 +262,7 @@ static int cr_write_vma(struct cr_ctx *c {struct cr_hdr h;struct cr_hdr_vma *hh = ctx->tbuf; -char *fname =NULL ; -int how, nr, ret; +int nr, ret; h.type =CR_HDR_VMA ; h.len =sizeof (*hh);
@@ -280,23 +279,10 @@ static int cr_write_vma(struct cr_ctx *creturn -ETXTBSY ; } -/* by default assume anon memory */ - how =CR_VMA_ANON ; - -/* if there is a backing file, assume private-mapped */ -/* (NEED: check if the file is unlinked) */ -if (vma->vm_file) { - nr =PAGE_SIZE ; - fname =cr_get_fname (&vma->vm_file->f_path, - ctx->vfsroot, ctx->tbuf, &nr); -if (IS_ERR (fname)) -return PTR_ERR (fname); - hh->namelen = nr; - how =CR_VMA_FILE ; - }else - hh->namelen =0 ; - - hh->how = how; + hh->how =CR_VMA_ANON ; + hh->namelen =0 ; +if (vma->vm_file) + hh->how =CR_VMA_FILE ;/* * it seems redundant now, but we do it in 3 steps for because:
@@ -310,18 +296,16 @@ static int cr_write_vma(struct cr_ctx *c* pages to dump, and make those pages COW. keep the list of pages * (and a reference to each page) on the checkpoint ctx */ nr =cr_vma_scan_pages (ctx, vma); -if (nr <0 ) { -cr_put_fname (ctx->tbuf, fname,PAGE_SIZE ); +if (nr <0 )return nr; - } hh->npages = nr; ret =cr_write_obj (ctx, &h, hh); -if (!ret && hh->namelen) - ret =cr_write_str (ctx, fname, hh->namelen); - -cr_put_fname (ctx->tbuf, fname,PAGE_SIZE ); +/* if there is a backing file, assume private-mapped */ +/* (NEED: check if the file is unlinked) */ +if (hh->how ==CR_VMA_FILE ) + ret =cr_write_fname (ctx, &vma->vm_file->f_path, ctx->vfsroot);if (ret <0 )return ret;
_
RFC PATCH v2 3/9 checkpoint/restart: x86 support
In reply to Dave HansenThe original version of Oren's patch contained a good hunk of #ifdefs. I've extracted all of those and created a bit of an API for new architectures to follow.
Leaving Oren's sign-off because this is all still his code, even though he hasn't seen it mangled like this before.
---
oren-cr.git-dave/checkpoint/Makefile | 1 oren-cr.git-dave/checkpoint/checkpoint.c | 7 oren-cr.git-dave/checkpoint/ckpt.h | 3 oren-cr.git-dave/checkpoint/ckpt_arch.h | 6 oren-cr.git-dave/checkpoint/restart.c | 7 oren-cr.git-dave/checkpoint/x86.c | 270 +++++++++++++++++++++++++++++++ oren-cr.git-dave/include/asm-x86/ckpt.h | 46 +++++ 7 files changed, 340 insertions(+)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0004-checkpoint-restart-x86-support +7 -0
@@ -20,6 +20,7 @@#include "ckpt.h" #include "ckpt_hdr.h" +#include "ckpt_arch.h" /** * cr_get_fname - return pathname of a given file
@@ -184,6 +185,12 @@ static int cr_write_task(struct cr_ctx * ret =cr_write_task_struct (ctx, t);pr_debug ("ret (task_struct) %d\n" , ret); +if (!ret) + ret =cr_write_thread (ctx, t); +pr_debug ("ret (thread) %d\n" , ret); +if (!ret) + ret =cr_write_cpu (ctx, t); +pr_debug ("ret (cpu) %d\n" , ret);return ret; }
checkpoint/ckpt_arch.h new file +6 -0
@@ -0,0 +1,6 @@ +#include "ckpt.h" + +int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t); +int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t); +int cr_read_thread (struct cr_ctx *ctx); +int cr_read_cpu (struct cr_ctx *ctx);
checkpoint/ckpt.h renamed from checkpoint/ckpt.h~0004-checkpoint-restart-x86-support +3 -0
@@ -54,6 +54,9 @@ extern int cr_kwrite(struct cr_ctx *ctx,extern int cr_uread (struct cr_ctx *ctx,void *buf,int count);extern int cr_kread (struct cr_ctx *ctx,void *buf,int count); +extern void *cr_hbuf_get (struct cr_ctx *ctx,int size); +extern void cr_hbuf_put (struct cr_ctx *ctx,int n); +struct cr_hdr ;extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf);
checkpoint/Makefile renamed from checkpoint/Makefile~0004-checkpoint-restart-x86-support +1 -0
@@ -1 +1,2 @@ obj-y += sys.o checkpoint.o restart.o +obj-$(CONFIG_X86) += x86.o
checkpoint/restart.c renamed from checkpoint/restart.c~0004-checkpoint-restart-x86-support +7 -0
@@ -22,6 +22,7 @@#include "ckpt.h" #include "ckpt_hdr.h" +#include "ckpt_arch.h" /** * cr_hbuf_get - reserve space on the hbuf
@@ -172,6 +173,12 @@ static int cr_read_task(struct cr_ctx *c ret =cr_read_task_struct (ctx);pr_debug ("ret (task_struct) %d\n" , ret); +if (!ret) + ret =cr_read_thread (ctx); +pr_debug ("ret (thread) %d\n" , ret); +if (!ret) + ret =cr_read_cpu (ctx); +pr_debug ("ret (cpu) %d\n" , ret);return ret; }
checkpoint/x86.c new file +270 -0
270 lines not on this page · raw message
include/asm-x86/ckpt.h new file +46 -0
46 lines not on this page · raw message
_
RFC PATCH v2 8/9 Remove some BUG_ON()s that need some proper error handling instead.
In reply to Dave Hansen---
oren-cr.git-dave/checkpoint/checkpoint.c | 12 ++++++++++-- oren-cr.git-dave/checkpoint/restart.c | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +10 -2
@@ -125,7 +125,8 @@ static int cr_write_tail(struct cr_ctx * h.id =0 ; hh->magic =CR_HEADER_MAGIC ; - hh->cksum[0 ] = hh->cksum[1 ] =1 ;/* TBD ... */ + hh->cksum[0 ] =1 ; + hh->cksum[1 ] =1 ;/* TBD ... */ ret =cr_write_obj (ctx, &h, hh);kfree (hh);
@@ -183,7 +184,14 @@ static int cr_write_task(struct cr_ctx * {int ret ; -BUG_ON (t->state ==TASK_DEAD ); +/* +* This was a BUG_ON(), which kinda makes sense if you +* are only allowing checkpointing of 'current'. But, +* it is still pretty silly in that case. Make it +* something a bit more sensible. +*/ +if (t->state ==TASK_DEAD ) +return -EAGAIN ; ret =cr_write_task_struct (ctx, t);pr_debug ("ret (task_struct) %d\n" , ret);
checkpoint/restart.c renamed from checkpoint/restart.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +15 -0
@@ -74,6 +74,11 @@ static int cr_read_hdr(struct cr_ctx *ctstruct cr_hdr_head *hh =kmalloc (sizeof (*hh),GFP_KERNEL );int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for header\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_HEAD );if (ret <0 )return ret;
@@ -99,6 +104,11 @@ static int cr_read_tail(struct cr_ctx *cstruct cr_hdr_tail *hh =kmalloc (sizeof (*hh),GFP_KERNEL );int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for tail\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TAIL );if (ret <0 )return ret;
@@ -118,6 +128,11 @@ static int cr_read_task_struct(struct crstruct task_struct *t = current;int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for task\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TASK );if (ret <0 )return ret;
_
RFC PATCH v2 9/9 remove ->cksum field
In reply to Dave HansenThis is unused so far. We'll add it back later.
---
oren-cr.git-dave/checkpoint/checkpoint.c | 2 -- oren-cr.git-dave/checkpoint/ckpt_hdr.h | 1 - oren-cr.git-dave/checkpoint/restart.c | 3 +-- 3 files changed, 1 insertion(+), 5 deletions(-)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~remove-unused-cksum +0 -2
@@ -125,8 +125,6 @@ static int cr_write_tail(struct cr_ctx * h.id =0 ; hh->magic =CR_HEADER_MAGIC ; - hh->cksum[0 ] =1 ; - hh->cksum[1 ] =1 ;/* TBD ... */ ret =cr_write_obj (ctx, &h, hh);kfree (hh);
checkpoint/ckpt_hdr.h renamed from checkpoint/ckpt_hdr.h~remove-unused-cksum +0 -1
@@ -43,7 +43,6 @@ struct cr_hdr_head {struct cr_hdr_tail {__u32 magic; -__u32 cksum[2 ]; };struct cr_hdr_task {
checkpoint/restart.c renamed from checkpoint/restart.c~remove-unused-cksum +1 -2
@@ -113,8 +113,7 @@ static int cr_read_tail(struct cr_ctx *cif (ret <0 )return ret; -if (hh->magic !=CR_HEADER_MAGIC || - hh->cksum[0 ] !=1 || hh->cksum[1 ] !=1 ) +if (hh->magic !=CR_HEADER_MAGIC )return -EINVAL ;kfree (hh);
_
RFC PATCH v2 4/9 checkpoint/restart: memory management
In reply to Dave HansenFor 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.
I guess I could also separate out the x86-specific bits here, but they're pretty small, comparatively.
---
oren-cr.git-dave/arch/x86/kernel/ldt.c | 2 oren-cr.git-dave/checkpoint/Makefile | 2 oren-cr.git-dave/checkpoint/ckpt_arch.h | 2 oren-cr.git-dave/checkpoint/ckpt_hdr.h | 21 + oren-cr.git-dave/checkpoint/ckpt_mem.c | 392 ++++++++++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/ckpt_mem.h | 32 ++ oren-cr.git-dave/checkpoint/rstr_mem.c | 354 ++++++++++++++++++++++++++++ oren-cr.git-dave/checkpoint/sys.c | 13 - oren-cr.git-dave/checkpoint/x86.c | 83 ++++++ oren-cr.git-dave/include/asm-x86/ckpt.h | 5 oren-cr.git-dave/include/asm-x86/desc.h | 3 11 files changed, 895 insertions(+), 14 deletions(-)
arch/x86/kernel/ldt.c renamed from arch/x86/kernel/ldt.c~0005-checkpoint-restart-memory-management +1 -1
@@ -181,7 +181,7 @@ static int read_default_ldt(void __userreturn bytecount; } -static int write_ldt (void __user *ptr,unsigned long bytecount,int oldmode) +int write_ldt (void __user *ptr,unsigned long bytecount,int oldmode) {struct mm_struct *mm = current->mm;struct desc_struct ldt;
checkpoint/ckpt_arch.h renamed from checkpoint/ckpt_arch.h~0005-checkpoint-restart-memory-management +2 -0
@@ -4,3 +4,5 @@ int cr_write_thread(struct cr_ctx *ctx,int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t);int cr_read_thread (struct cr_ctx *ctx);int cr_read_cpu (struct cr_ctx *ctx); +int cr_write_mm_context (struct cr_ctx *ctx,struct mm_struct *mm); +int cr_read_mm_context (struct cr_ctx *ctx,struct mm_struct *mm);
checkpoint/ckpt_hdr.h renamed from checkpoint/ckpt_hdr.h~0005-checkpoint-restart-memory-management +21 -0
@@ -67,3 +67,24 @@ struct cr_hdr_task { }; + +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; +}; + +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; +};
checkpoint/ckpt_mem.c new file +392 -0
392 lines not on this page · raw message
checkpoint/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);
checkpoint/Makefile renamed from checkpoint/Makefile~0005-checkpoint-restart-memory-management +1 -1
@@ -1,2 +1,2 @@ -obj-y += sys.o checkpoint.o restart.o +obj-y += sys.o checkpoint.o restart.o ckpt_mem.o rstr_mem.o obj-$(CONFIG_X86) += x86.o
checkpoint/rstr_mem.c new file +354 -0
354 lines not on this page · raw message
checkpoint/sys.c renamed from checkpoint/sys.c~0005-checkpoint-restart-memory-management +2 -11
@@ -15,6 +15,7 @@#include <linux/capability.h> #include "ckpt.h" +#include "ckpt_mem.h" /* * helpers to write/read to/from the image file descriptor
@@ -118,8 +119,7 @@ void cr_ctx_free(struct cr_ctx *ctx)if (ctx->vfsroot)path_put (ctx->vfsroot); -free_pages ((unsigned long ) ctx->tbuf,CR_ORDER_TBUF ); -free_pages ((unsigned long ) ctx->hbuf,CR_ORDER_HBUF ); +cr_pgarr_free (ctx);kfree (ctx); }
@@ -132,11 +132,6 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, sif (!ctx)return NULL ; - ctx->tbuf = (void *)__get_free_pages (GFP_KERNEL ,CR_ORDER_TBUF ); - ctx->hbuf = (void *)__get_free_pages (GFP_KERNEL ,CR_ORDER_HBUF ); -if (!ctx->tbuf || !ctx->hbuf) - goto nomem; - ctx->pid = pid; ctx->flags = flags;
@@ -150,10 +145,6 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, s ctx->crid =atomic_inc_return (&cr_ctx_count);return ctx; - - nomem: -cr_ctx_free (ctx); -return NULL ; }/**
checkpoint/x86.c renamed from checkpoint/x86.c~0005-checkpoint-restart-memory-management +83 -0
91 lines not on this page · raw message
include/asm-x86/ckpt.h renamed from include/asm-x86/ckpt.h~0005-checkpoint-restart-memory-management +5 -0
@@ -43,4 +43,9 @@ struct cr_hdr_cpu { union thread_xstate xstate; /* i387 */ }; +struct cr_hdr_mm_context { +__s16 ldt_entry_size; +__s16 nldt; +}; +#endif /* __ASM_X86_CKPT_H */
include/asm-x86/desc.h renamed from include/asm-x86/desc.h~0005-checkpoint-restart-memory-management +2 -1
@@ -111,6 +111,8 @@ static inline void native_write_ldt_entrmemcpy (&ldt[entry], desc,8 ); } +int write_ldt (void __user *ptr,unsigned long bytecount,int oldmode); +static inline void native_write_gdt_entry (struct desc_struct *gdt,int entry,const void *desc,int type) {
@@ -394,7 +396,6 @@ static inline void set_system_gate_ist(ishll $16, base; \ movw idx * 8 + 2(gdt), lo_w; -#endif /* __ASSEMBLY__ */ #endif
_
RFC PATCH v2 5/9 Create trivial sys_checkpoint and sys_restore system calls
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Create trivial sys_checkpoint and sys_restore system calls. They will enable to checkpoint and restart an entire container, to and from a checkpoint image file.
First create a template for both syscalls: they take a file descriptor (for the image file) and flags as arguments. For sys_checkpoint the first argument identifies the target container; for sys_restart it will identify the checkpoint image.
---
oren-cr.git-dave/arch/x86/kernel/syscall_table_32.S | 2 ++ oren-cr.git-dave/include/asm-x86/unistd_32.h | 2 ++ oren-cr.git-dave/include/linux/syscalls.h | 3 +++ 3 files changed, 7 insertions(+)
arch/x86/kernel/syscall_table_32.S renamed from arch/x86/kernel/syscall_table_32.S~0006-Create-trivial-sys_checkpoint-and-sys_restore-system +2 -0
@@ -332,3 +332,5 @@ ENTRY(sys_call_table) .long sys_dup3 /* 330 */ .long sys_pipe2 .long sys_inotify_init1 + .long sys_checkpoint + .long sys_restart
include/asm-x86/unistd_32.h renamed from include/asm-x86/unistd_32.h~0006-Create-trivial-sys_checkpoint-and-sys_restore-system +2 -0
@@ -338,6 +338,8 @@#define __NR_dup3 330#define __NR_pipe2 331#define __NR_inotify_init1 332 +#define __NR_checkpoint 333 +#define __NR_restart 334#ifdef __KERNEL__
include/linux/syscalls.h renamed from include/linux/syscalls.h~0006-Create-trivial-sys_checkpoint-and-sys_restore-system +3 -0
@@ -625,4 +625,7 @@ asmlinkage long sys_fallocate(int fd, inint kernel_execve (const char *filename,char *const argv[],char *const envp[]); +asmlinkage long sys_checkpoint (pid_t pid,int fd,unsigned long flags); +asmlinkage long sys_restart (int crid,int fd,unsigned long flags); +#endif
_
RFC PATCH v2 6/9 Simplify filename handling for now
In reply to Dave HansenThe filename handling is a bit clunky, as one of the reviewers noted. It can allocate memory in one of two places and that makes things look a bit weird.
We don't *really* need the filename sitting around in its own buffer, so let's just combine the writing and the filename generation.
It moves the order in which the things in the VMA are done, but it doens't change the order in which they are written to the checkpoint file.
Note how much code this removes.
---
oren-cr.git-dave/checkpoint/checkpoint.c | 48 ++++++++++++------------------- oren-cr.git-dave/checkpoint/ckpt.h | 1 oren-cr.git-dave/checkpoint/ckpt_mem.c | 36 ++++++----------------- 3 files changed, 30 insertions(+), 55 deletions(-)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0007-fixup-filename-handling +19 -29
@@ -23,43 +23,33 @@#include "ckpt_arch.h" /** -* cr_get_fname - return pathname of a given file -* @file: file pointer -* @buf: buffer for pathname -* @n: buffer length (in) and pathname length (out) -* -* if the buffer provivded by the caller is too small, allocate a new -* buffer; caller should call cr_put_pathname() for cleanup +* cr_write_fname - write a string record for a filename +* @ctx: checkpoint context +* @path: path name to write +* @root: root from which to find the path */ -char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n) +int cr_write_fname (struct cr_ctx *ctx,struct path *path,struct path *root) { +char *fname_buf =kmalloc (PAGE_SIZE ,GFP_KERNEL );char *fname; +int ret; +int len; - fname =__d_path (path, root, buf, *n); +if (!fname_buf) +return -ENOMEM ; -if (IS_ERR (fname) &&PTR_ERR (fname) == -ENAMETOOLONG ) { -if (!(buf = (char *)__get_free_pages (GFP_KERNEL ,0 ))) -return ERR_PTR (-ENOMEM ); - fname =__d_path (path, root, buf,PAGE_SIZE ); -if (IS_ERR (fname)) -free_pages ((unsigned long ) buf,0 ); + fname =__d_path (path, root, fname_buf,PAGE_SIZE ); +if (IS_ERR (fname)) { + ret =PTR_ERR (fname); + goto out_free; } -if (!IS_ERR (fname)) - *n = (buf + *n - fname); -return fname; -} + len =PAGE_SIZE + fname_buf - fname; + ret =cr_write_str (ctx, fname, len); -/** -* cr_put_fname - (possibly) cleanup pathname buffer -* @buf: original buffer that was given to cr_get_pathname() -* @fname: resulting pathname from cr_get_pathname() -* @n: length of original buffer -*/ -void cr_put_fname (char *buf,char *fname,int n) -{ -if (fname && (fname < buf || fname >= buf + n)) -free_pages ((unsigned long ) buf,0 ); +out_free: +kfree (fname_buf); +return ret; }/**
checkpoint/ckpt.h renamed from checkpoint/ckpt.h~0007-fixup-filename-handling +1 -0
@@ -48,6 +48,7 @@ struct cr_ctx {extern void cr_put_fname (char *buf,char *fname,int n);extern char *cr_get_fname (struct path *path,struct path *root,char *buf,int *n); +extern int cr_write_fname (struct cr_ctx *ctx,struct path *path,struct path *root);extern int cr_uwrite (struct cr_ctx *ctx,void *buf,int count);extern int cr_kwrite (struct cr_ctx *ctx,void *buf,int count);
checkpoint/ckpt_mem.c renamed from checkpoint/ckpt_mem.c~0007-fixup-filename-handling +10 -26
@@ -262,8 +262,7 @@ static int cr_write_vma(struct cr_ctx *c {struct cr_hdr h;struct cr_hdr_vma *hh = ctx->tbuf; -char *fname =NULL ; -int how, nr, ret; +int nr, ret; h.type =CR_HDR_VMA ; h.len =sizeof (*hh);
@@ -280,23 +279,10 @@ static int cr_write_vma(struct cr_ctx *creturn -ETXTBSY ; } -/* by default assume anon memory */ - how =CR_VMA_ANON ; - -/* if there is a backing file, assume private-mapped */ -/* (NEED: check if the file is unlinked) */ -if (vma->vm_file) { - nr =PAGE_SIZE ; - fname =cr_get_fname (&vma->vm_file->f_path, - ctx->vfsroot, ctx->tbuf, &nr); -if (IS_ERR (fname)) -return PTR_ERR (fname); - hh->namelen = nr; - how =CR_VMA_FILE ; - }else - hh->namelen =0 ; - - hh->how = how; + hh->how =CR_VMA_ANON ; + hh->namelen =0 ; +if (vma->vm_file) + hh->how =CR_VMA_FILE ;/* * it seems redundant now, but we do it in 3 steps for because:
@@ -310,18 +296,16 @@ static int cr_write_vma(struct cr_ctx *c* pages to dump, and make those pages COW. keep the list of pages * (and a reference to each page) on the checkpoint ctx */ nr =cr_vma_scan_pages (ctx, vma); -if (nr <0 ) { -cr_put_fname (ctx->tbuf, fname,PAGE_SIZE ); +if (nr <0 )return nr; - } hh->npages = nr; ret =cr_write_obj (ctx, &h, hh); -if (!ret && hh->namelen) - ret =cr_write_str (ctx, fname, hh->namelen); - -cr_put_fname (ctx->tbuf, fname,PAGE_SIZE ); +/* if there is a backing file, assume private-mapped */ +/* (NEED: check if the file is unlinked) */ +if (hh->how ==CR_VMA_FILE ) + ret =cr_write_fname (ctx, &vma->vm_file->f_path, ctx->vfsroot);if (ret <0 )return ret;
_
RFC PATCH v2 7/9 remove temporary buffer structures
In reply to Dave HansenThese will eventually help the efficiency of the restore and aid in creating incremental checkpoints. But, for now, they do not give us much, and introduce some unnecessary abstraction. Kill them for now, but we can always add them back later.
We use stack allocations for some of these, and kmalloc() for the larger ones.
---
oren-cr.git-dave/checkpoint/checkpoint.c | 38 +++++++---- oren-cr.git-dave/checkpoint/ckpt_mem.c | 58 ++++++++--------- oren-cr.git-dave/checkpoint/restart.c | 47 ++------------ oren-cr.git-dave/checkpoint/rstr_mem.c | 11 +-- oren-cr.git-dave/checkpoint/x86.c | 104 ++++++++++++++++++++++--------- 5 files changed, 142 insertions(+), 116 deletions(-)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0009-hbuf-compile-fixes +25 -13
@@ -88,7 +88,7 @@ int cr_write_str(struct cr_ctx *ctx, chastatic int cr_write_hdr (struct cr_ctx *ctx) {struct cr_hdr h; -struct cr_hdr_head *hh = ctx->tbuf; +struct cr_hdr_head hh;struct timeval ktv; h.type =CR_HDR_HEAD ;
@@ -97,24 +97,28 @@ static int cr_write_hdr(struct cr_ctx *cdo_gettimeofday (&ktv); - hh->magic =CR_HEADER_MAGIC ; - hh->major = (LINUX_VERSION_CODE >>16 ) &0xff ; - hh->minor = (LINUX_VERSION_CODE >>8 ) &0xff ; - hh->patch = (LINUX_VERSION_CODE ) &0xff ; + hh.magic =CR_HEADER_MAGIC ; + hh.major = (LINUX_VERSION_CODE >>16 ) &0xff ; + hh.minor = (LINUX_VERSION_CODE >>8 ) &0xff ; + hh.patch = (LINUX_VERSION_CODE ) &0xff ; - hh->version =1 ; + hh.version =1 ; - hh->flags = ctx->flags; - hh->time = ktv.tv_sec; + hh.flags = ctx->flags; + hh.time = ktv.tv_sec; -return cr_write_obj (ctx, &h, hh); +return cr_write_obj (ctx, &h, &hh); }/* write the checkpoint trailer */ static int cr_write_tail (struct cr_ctx *ctx) {struct cr_hdr h; -struct cr_hdr_tail *hh = ctx->tbuf; +struct cr_hdr_tail *hh =kmalloc (sizeof (*hh),GFP_KERNEL ); +int ret; + +if (!hh) +return -ENOMEM ; h.type =CR_HDR_TAIL ; h.len =sizeof (*hh);
@@ -123,14 +127,20 @@ static int cr_write_tail(struct cr_ctx * hh->magic =CR_HEADER_MAGIC ; hh->cksum[0 ] = hh->cksum[1 ] =1 ;/* TBD ... */ -return cr_write_obj (ctx, &h, hh); + ret =cr_write_obj (ctx, &h, hh); +kfree (hh); +return ret; }/* dump the task_struct of a given task */ static int cr_write_task_struct (struct cr_ctx *ctx,struct task_struct *t) {struct cr_hdr h; -struct cr_hdr_task *hh = ctx->tbuf; +struct cr_hdr_task *hh =kmalloc (sizeof (*hh),GFP_KERNEL ); +int ret; + +if (!hh) +return -ENOMEM ; h.type =CR_HDR_TASK ; h.len =sizeof (*hh);
@@ -163,7 +173,9 @@ static int cr_write_task_struct(struct c hh->task_comm_len =TASK_COMM_LEN ;memcpy (hh->comm, t->comm,TASK_COMM_LEN ); -return cr_write_obj (ctx, &h, hh); + ret =cr_write_obj (ctx, &h, hh); +kfree (hh); +return ret; }/* dump the entire state of a given task */
checkpoint/ckpt_mem.c renamed from checkpoint/ckpt_mem.c~0009-hbuf-compile-fixes +29 -29
105 lines not on this page · raw message
checkpoint/restart.c renamed from checkpoint/restart.c~0009-hbuf-compile-fixes +7 -40
95 lines not on this page · raw message
checkpoint/rstr_mem.c renamed from checkpoint/rstr_mem.c~0009-hbuf-compile-fixes +6 -5
@@ -187,7 +187,7 @@ static unsigned long cr_calc_map_flags_bstatic int cr_read_vma (struct cr_ctx *ctx,struct mm_struct *mm) { -struct cr_hdr_vma *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct cr_hdr_vma *hh =kmalloc (sizeof (*hh),GFP_KERNEL );unsigned long vm_size, vm_flags, vm_prot, vm_pgoff;void *addr;unsigned long flags;
@@ -214,7 +214,7 @@ static int cr_read_vma(struct cr_ctx *ct vm_pgoff = hh->vm_pgoff;if (hh->namelen) { - fname = ctx->tbuf; + fname =kmalloc (PAGE_SIZE ,GFP_KERNEL ); ret =cr_read_str (ctx, fname,PAGE_SIZE );if (ret <0 )return ret;
@@ -280,8 +280,9 @@ static int cr_read_vma(struct cr_ctx *ctif (vm_prot &PROT_EXEC )flush_icache_range (hh->vm_start, hh->vm_end); -cr_hbuf_put (ctx,sizeof (*hh)); +kfree (hh);pr_debug ("vma retval %d\n" , ret); +kfree (fname);return 0 ; }
@@ -303,7 +304,7 @@ static int cr_destroy_mm(struct mm_strucint cr_read_mm (struct cr_ctx *ctx) { -struct cr_hdr_mm *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct cr_hdr_mm *hh =kmalloc (sizeof (*hh),GFP_KERNEL );struct mm_struct *mm;int nr, ret;
@@ -348,7 +349,7 @@ int cr_read_mm(struct cr_ctx *ctx)return ret; } -cr_hbuf_put (ctx,sizeof (*hh)); +kfree (hh);return cr_read_mm_context (ctx, mm); }
checkpoint/x86.c renamed from checkpoint/x86.c~0009-hbuf-compile-fixes +75 -29
244 lines not on this page · raw message
_
RFC PATCH v2 8/9 Remove some BUG_ON()s that need some proper error handling instead.
In reply to Dave Hansen---
oren-cr.git-dave/checkpoint/checkpoint.c | 12 ++++++++++-- oren-cr.git-dave/checkpoint/restart.c | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +10 -2
@@ -125,7 +125,8 @@ static int cr_write_tail(struct cr_ctx * h.id =0 ; hh->magic =CR_HEADER_MAGIC ; - hh->cksum[0 ] = hh->cksum[1 ] =1 ;/* TBD ... */ + hh->cksum[0 ] =1 ; + hh->cksum[1 ] =1 ;/* TBD ... */ ret =cr_write_obj (ctx, &h, hh);kfree (hh);
@@ -183,7 +184,14 @@ static int cr_write_task(struct cr_ctx * {int ret ; -BUG_ON (t->state ==TASK_DEAD ); +/* +* This was a BUG_ON(), which kinda makes sense if you +* are only allowing checkpointing of 'current'. But, +* it is still pretty silly in that case. Make it +* something a bit more sensible. +*/ +if (t->state ==TASK_DEAD ) +return -EAGAIN ; ret =cr_write_task_struct (ctx, t);pr_debug ("ret (task_struct) %d\n" , ret);
checkpoint/restart.c renamed from checkpoint/restart.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +15 -0
@@ -74,6 +74,11 @@ static int cr_read_hdr(struct cr_ctx *ctstruct cr_hdr_head *hh =kmalloc (sizeof (*hh),GFP_KERNEL );int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for header\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_HEAD );if (ret <0 )return ret;
@@ -99,6 +104,11 @@ static int cr_read_tail(struct cr_ctx *cstruct cr_hdr_tail *hh =kmalloc (sizeof (*hh),GFP_KERNEL );int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for tail\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TAIL );if (ret <0 )return ret;
@@ -118,6 +128,11 @@ static int cr_read_task_struct(struct crstruct task_struct *t = current;int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for task\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TASK );if (ret <0 )return ret;
_
Re: [RFC v2][PATCH 8/9] Remove some BUG_ON()s that need some proper error handling instead.
checkpoint/checkpoint.c 2008-08-20 12:12:51.000000000 -0700 static int cr_write_tail(struct cr_ctx * · line 132
Quoted 13 lines · Dave Hansen
diff -puN checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha
checkpoint/checkpoint.ccheckpoint/checkpoint.c 2008-08-20 12:12:51.000000000 -0700 renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha 2008-08-20 12:12:51.000000000 -0700 +2
-1@@ -125,7 +125,8 @@ static int cr_write_tail(struct cr_ctx * h.id = 0; hh->magic = CR_HEADER_MAGIC; - hh->cksum[0] = hh->cksum[1] = 1; /* TBD ... */ + hh->cksum[0] = 1; + hh->cksum[1] = 1; /* TBD ... */ ret = cr_write_obj(ctx, &h, hh); kfree(hh);
Whoops, that's a bad hunk that belongs in the next patch. Sorry.
-- Dave
Re: [RFC v2][PATCH 8/9] Remove some BUG_ON()s that need some proper error handling instead.
In reply to Dave Hansencheckpoint/checkpoint.c 2008-08-20 12:12:51.000000000 -0700 static int cr_write_tail(struct cr_ctx * · line 132
Quoted 13 lines · Dave Hansen
diff -puN checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha
checkpoint/checkpoint.ccheckpoint/checkpoint.c 2008-08-20 12:12:51.000000000 -0700 renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha 2008-08-20 12:12:51.000000000 -0700 +2
-1@@ -125,7 +125,8 @@ static int cr_write_tail(struct cr_ctx * h.id = 0; hh->magic = CR_HEADER_MAGIC; - hh->cksum[0] = hh->cksum[1] = 1; /* TBD ... */ + hh->cksum[0] = 1; + hh->cksum[1] = 1; /* TBD ... */ ret = cr_write_obj(ctx, &h, hh); kfree(hh);
Whoops, that's a bad hunk that belongs in the next patch. Sorry.
-- Dave
Re: [RFC v2][PATCH 8/9] Remove some BUG_ON()s that need some proper error handling instead.
In reply to Dave HansenQuoted 24 lines · Dave Hansen
---
oren-cr.git-dave/checkpoint/checkpoint.c | 12 ++++++++++-- oren-cr.git-dave/checkpoint/restart.c | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-)diff -puN checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha
checkpoint/checkpoint.ccheckpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +2
-1@@ -125,7 +125,8 @@ static int cr_write_tail(struct cr_ctx * h.id =0 ; hh->magic =CR_HEADER_MAGIC ; - hh->cksum[0 ] = hh->cksum[1 ] =1 ;/* TBD ... */ + hh->cksum[0 ] =1 ; + hh->cksum[1 ] =1 ;/* TBD ... */ ret =cr_write_obj (ctx, &h, hh);kfree (hh);@@ -183,7 +184,14 @@ static int cr_write_task(struct cr_ctx * {int ret ;
checkpoint/checkpoint.c static int cr_write_task(struct cr_ctx * · line 194
Quoted 10 lines
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +8
-1-BUG_ON (t->state ==TASK_DEAD ); +/* +* This was a BUG_ON(), which kinda makes sense if you +* are only allowing checkpointing of 'current'. But, +* it is still pretty silly in that case. Make it +* something a bit more sensible. +*/ +if (t->state ==TASK_DEAD ) +return -EAGAIN ;
This is OK for a debug patch but I think in the end we'd want to do
something similar early in sys_checkpoint -- before we start writing anything. We should check to ensure the task is properly frozen there and return -EBUSY if not frozen. Something like:
/* Only current can self-checkpoint. Everything else must be frozen first. */
for_each_task_being_checkpointed(t) {
if ((t != current) && !is_task_frozen_enough(t))
return -EBUSY;
}is_task_frozen_enough() current lives in kernel/cgroup_freezer.c. I think it can easily be pulled out of the cgroup_freezer.c code so that we don't introduce a CONFIG dependency...
Quoted 46 lines
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +0
-0ret =cr_write_task_struct (ctx, t);pr_debug ("ret (task_struct) %d\n" , ret);diff -puN checkpoint/restart.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha
checkpoint/restart.ccheckpoint/restart.c renamed from checkpoint/restart.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +15
-0@@ -74,6 +74,11 @@ static int cr_read_hdr(struct cr_ctx *ctstruct cr_hdr_head *hh =kmalloc (sizeof (*hh),GFP_KERNEL );int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for header\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_HEAD );if (ret <0 )return ret;@@ -99,6 +104,11 @@ static int cr_read_tail(struct cr_ctx *cstruct cr_hdr_tail *hh =kmalloc (sizeof (*hh),GFP_KERNEL );int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for tail\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TAIL );if (ret <0 )return ret;@@ -118,6 +128,11 @@ static int cr_read_task_struct(struct crstruct task_struct *t = current;int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for task\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TASK );if (ret <0 )return ret;_
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linux-foundation.org/mailman/listinfo/containers
Re: [RFC v2][PATCH 8/9] Remove some BUG_ON()s that need some proper error handling instead.
In reply to Dave HansenQuoted 24 lines · Dave Hansen
---
oren-cr.git-dave/checkpoint/checkpoint.c | 12 ++++++++++-- oren-cr.git-dave/checkpoint/restart.c | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-)diff -puN checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha
checkpoint/checkpoint.ccheckpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +2
-1@@ -125,7 +125,8 @@ static int cr_write_tail(struct cr_ctx * h.id =0 ; hh->magic =CR_HEADER_MAGIC ; - hh->cksum[0 ] = hh->cksum[1 ] =1 ;/* TBD ... */ + hh->cksum[0 ] =1 ; + hh->cksum[1 ] =1 ;/* TBD ... */ ret =cr_write_obj (ctx, &h, hh);kfree (hh);@@ -183,7 +184,14 @@ static int cr_write_task(struct cr_ctx * {int ret ;
checkpoint/checkpoint.c static int cr_write_task(struct cr_ctx * · line 194
Quoted 10 lines
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +8
-1-BUG_ON (t->state ==TASK_DEAD ); +/* +* This was a BUG_ON(), which kinda makes sense if you +* are only allowing checkpointing of 'current'. But, +* it is still pretty silly in that case. Make it +* something a bit more sensible. +*/ +if (t->state ==TASK_DEAD ) +return -EAGAIN ;
This is OK for a debug patch but I think in the end we'd want to do
something similar early in sys_checkpoint -- before we start writing anything. We should check to ensure the task is properly frozen there and return -EBUSY if not frozen. Something like:
/* Only current can self-checkpoint. Everything else must be frozen first. */
for_each_task_being_checkpointed(t) {
if ((t != current) && !is_task_frozen_enough(t))
return -EBUSY;
}is_task_frozen_enough() current lives in kernel/cgroup_freezer.c. I think it can easily be pulled out of the cgroup_freezer.c code so that we don't introduce a CONFIG dependency...
Quoted 46 lines
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +0
-0ret =cr_write_task_struct (ctx, t);pr_debug ("ret (task_struct) %d\n" , ret);diff -puN checkpoint/restart.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha
checkpoint/restart.ccheckpoint/restart.c renamed from checkpoint/restart.c~0002-Remove-some-BUG_ON-s-that-need-some-proper-error-ha +15
-0@@ -74,6 +74,11 @@ static int cr_read_hdr(struct cr_ctx *ctstruct cr_hdr_head *hh =kmalloc (sizeof (*hh),GFP_KERNEL );int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for header\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_HEAD );if (ret <0 )return ret;@@ -99,6 +104,11 @@ static int cr_read_tail(struct cr_ctx *cstruct cr_hdr_tail *hh =kmalloc (sizeof (*hh),GFP_KERNEL );int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for tail\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TAIL );if (ret <0 )return ret;@@ -118,6 +128,11 @@ static int cr_read_task_struct(struct crstruct task_struct *t = current;int ret; +if (!hh) { +pr_debug ("unable to get %d bytes from ctx buf for task\n" , +sizeof (*hh)); +return -ENOMEM ; + } ret =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_TASK );if (ret <0 )return ret;_
_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers
RFC PATCH v2 9/9 remove ->cksum field
In reply to Dave HansenThis is unused so far. We'll add it back later.
---
oren-cr.git-dave/checkpoint/checkpoint.c | 2 -- oren-cr.git-dave/checkpoint/ckpt_hdr.h | 1 - oren-cr.git-dave/checkpoint/restart.c | 3 +-- 3 files changed, 1 insertion(+), 5 deletions(-)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~remove-unused-cksum +0 -2
@@ -125,8 +125,6 @@ static int cr_write_tail(struct cr_ctx * h.id =0 ; hh->magic =CR_HEADER_MAGIC ; - hh->cksum[0 ] =1 ; - hh->cksum[1 ] =1 ;/* TBD ... */ ret =cr_write_obj (ctx, &h, hh);kfree (hh);
checkpoint/ckpt_hdr.h renamed from checkpoint/ckpt_hdr.h~remove-unused-cksum +0 -1
@@ -43,7 +43,6 @@ struct cr_hdr_head {struct cr_hdr_tail {__u32 magic; -__u32 cksum[2 ]; };struct cr_hdr_task {
checkpoint/restart.c renamed from checkpoint/restart.c~remove-unused-cksum +1 -2
@@ -113,8 +113,7 @@ static int cr_read_tail(struct cr_ctx *cif (ret <0 )return ret; -if (hh->magic !=CR_HEADER_MAGIC || - hh->cksum[0 ] !=1 || hh->cksum[1 ] !=1 ) +if (hh->magic !=CR_HEADER_MAGIC )return -EINVAL ;kfree (hh);
_