Kernel-based checkpoint/restart
Subsystems (7)
cover Kernel-based checkpoint/restart
I'd like to see these merged into -mm and on the way to mainline. The entire freakin' world is cc'd. So sue me. :)
Why do we want it? It allows containers to be moved between physical machines' kernels in the same way that VMWare can move VMs between physical machines' hypervisors. There are currently at least two out-of-tree implementations of this in the commercial world (IBM's Metacluster and Parallels' OpenVZ/Virtuozzo) and several in the academic world like Zap.
Why do we need it in mainline now? Because we already have plenty of out-of-tree ones, and want to know what an in-tree one will be like. :) What *I* want right now is the extra review and scrutiny that comes with a mainline submission to make sure we're not going in a direction contrary to the community.
This only supports pretty simple apps. But, I trust Ingo when he says:
Quoted 5 lines
Generally, if something works for simple apps already (in a robust, compatible and supportable way) and users find it "very cool", then support for more complex apps is not far in the future. but if you want to support more complex apps straight away, it takes forever and gets ugly.
We're *certainly* going to be changing the ABI (which is the format of the checkpoint). I'd like to follow the model that we used for ext4-dev, which is to make it very clear that this is a development-only feature for now. Perhaps we do that by making the interface only available through debugfs or something similar for now. Or, reserving the syscall numbers but require some runtime switch to be thrown before they can be used. I'm open to suggestions here.
These patches are Oren Laadan's baby. Virtually all this code is his, but he's a bit busy at the moment finishing up his PhD.
There's a plethora of old history and some userspace tools below if you want some more detail, but please ignore them and look at the kernel code. :)
--
These patches implement basic checkpoint-restart [CR]. This version (v6) supports basic tasks with simple private memory, and open files (regular files and directories only). Changes mainly cleanups. See original announcements below.
--
Todo:
- Add support for x86-64 and improve ABI
- Refine or change syscall interface
- Extend to handle (multiple) tasks in a container
- Handle multiple namespaces in a container (e.g. save the filesystem namespaces state with the file descriptors)
- Security (without CAPS_SYS_ADMIN files restore may fail)
Changelog:
[2008-Oct-07] v6:
- Balance all calls to cr_hbuf_get() with matching cr_hbuf_put() (even though it's not really needed)
- Add assumptions and what's-missing to documentation
- Misc fixes and cleanups
[2008-Sep-11] v5:
- Config is now 'def_bool n' by default
- Improve memory dump/restore code (following Dave Hansen's comments)
- Change dump format (and code) to allow chunks of <vaddrs, pages> instead of one long list of each
- Fix use of follow_page() to avoid faulting in non-present pages
- Memory restore now maps user pages explicitly to copy data into them, instead of reading directly to user space; got rid of mprotect_fixup()
- Remove preempt_disable() when restoring debug registers
- Rename headers files s/ckpt/checkpoint/
- Fix misc bugs in files dump/restore
- Fixes and cleanups on some error paths
- Fix misc coding style
[2008-Sep-09] v4:
- Various fixes and clean-ups
- Fix calculation of hash table size
- Fix header structure alignment
- Use stand list_... for cr_pgarr
[2008-Aug-29] v3:
- Various fixes and clean-ups
- Use standard hlist_... for hash table
- Better use of standard kmalloc/kfree
[2008-Aug-20] v2:
- Added Dump and restore of open files (regular and directories)
- Added basic handling of shared objects, and improve handling of 'parent tag' concept
- Added documentation
- Improved ABI, 64bit padding for image data
- Improved locking when saving/restoring memory
- Added UTS information to header (release, version, machine)
- Cleanup extraction of filename from a file pointer
- Refactor to allow easier reviewing
- Remove requirement for CAPS_SYS_ADMIN until we come up with a security policy (this means that file restore may fail)
- Other cleanup and response to comments for v1
[2008-Jul-29] v1:
- Initial version: support a single task with address space of only private anonymous or file-mapped VMAs; syscalls ignore pid/crid argument and act on current process.
--
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 than 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. The open files may consist of only simple files and directories.
--
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
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). Note the use of "dup2" to create a copy of an open file and show how shared objects are treated. Execute like this (as a superuser):
orenl:~/test$ ./ckpt > out.1
<-- ctrl-c
orenl:~/test$ cat /tmp/cr-rest.out
hello, world!
world, hello!
(ret = 1)orenl:~/test$ ./ckpt > out.1
<-- ctrl-c
orenl:~/test$ cat /tmp/cr-rest.out
hello, world!
world, hello!
(ret = 2)<-- now change the contents of the file
orenl:~/test$ sed -i 's/world, hello!/xxxx/' /tmp/cr-rest.out orenl:~/test$ cat /tmp/cr-rest.out hello, world! xxxx (ret = 2)
<-- and do the restart
orenl:~/test$ ./rstr < out.1
<-- ctrl-c
orenl:~/test$ cat /tmp/cr-rest.out
hello, world!
world, hello!
(ret = 0)(if you check the output of ps, you'll see that "rstr" changed its name to "ckpt", as expected).
============================== ckpt.c ================================
#define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <sys/syscall.h>
#define OUTFILE "/tmp/cr-test.out"
int main(int argc, char *argv[])
{
pid_t pid = getpid();
FILE *file;
int ret;
close(0);
close(2);
unlink(OUTFILE);
file = fopen(OUTFILE, "w+");
if (!file) {
perror("open");
exit(1);
}
if (dup2(0,2) < 0) {
perror("dups");
exit(1);
}
fprintf(file, "hello, world!\n");
fflush(file);
ret = syscall(__NR_checkpoint, pid, STDOUT_FILENO, 0);
if (ret < 0) {
perror("checkpoint");
exit(2);
}
fprintf(file, "world, hello!\n");
fprintf(file, "(ret = %d)\n", ret);
fflush(file);
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.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;
}-- Dave
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/9 Create syscalls: sys_checkpoint, sys_restart
From: 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 descriptor.
The syscalls 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.
---
linux-2.6.git-dave/arch/x86/kernel/syscall_table_32.S | 2 linux-2.6.git-dave/checkpoint/Kconfig | 11 ++++ linux-2.6.git-dave/checkpoint/Makefile | 5 ++ linux-2.6.git-dave/checkpoint/sys.c | 41 ++++++++++++++++++ linux-2.6.git-dave/include/asm-x86/unistd_32.h | 2 linux-2.6.git-dave/include/linux/syscalls.h | 2 linux-2.6.git-dave/init/Kconfig | 2 linux-2.6.git-dave/kernel/sys_ni.c | 4 + 8 files changed, 69 insertions(+)
arch/x86/kernel/syscall_table_32.S renamed from arch/x86/kernel/syscall_table_32.S~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +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
checkpoint/Kconfig new file +11 -0
@@ -0,0 +1,11 @@ +config CHECKPOINT_RESTART + prompt "Enable checkpoint/restart (EXPERIMENTAL)" + def_bool n + depends on X86_32 && EXPERIMENTAL + help + Application checkpoint/restart is the ability to save the + state of a running application so that it can later resume + its execution from the time at which it was checkpointed. + + Turning this option on will enable checkpoint and restart + functionality in the kernel.
checkpoint/Makefile new file +5 -0
@@ -0,0 +1,5 @@ +# +# Makefile for linux checkpoint/restart. +# + +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o
checkpoint/sys.c new file +41 -0
41 lines not on this page · raw message
include/asm-x86/unistd_32.h renamed from include/asm-x86/unistd_32.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +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~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +2 -0
@@ -622,6 +622,8 @@ asmlinkage long sys_timerfd_gettime(intasmlinkage long sys_eventfd (unsigned int count);asmlinkage long sys_eventfd2 (unsigned int count,int flags);asmlinkage long sys_fallocate (int fd,int mode,loff_t offset,loff_t len); +asmlinkage long sys_checkpoint (pid_t pid,int fd,unsigned long flags); +asmlinkage long sys_restart (int crid,int fd,unsigned long flags);int kernel_execve (const char *filename,char *const argv[],char *const envp[]);
init/Kconfig renamed from init/Kconfig~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +2 -0
@@ -779,6 +779,8 @@ config MARKERS source "arch/Kconfig" +source "checkpoint/Kconfig" + endmenu # General setup config HAVE_GENERIC_DMA_COHERENT
kernel/sys_ni.c renamed from kernel/sys_ni.c~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +4 -0
@@ -169,3 +169,7 @@ cond_syscall(compat_sys_timerfd_settime)cond_syscall (compat_sys_timerfd_gettime);cond_syscall (sys_eventfd);cond_syscall (sys_eventfd2); + +/* checkpoint/restart */ +cond_syscall (sys_checkpoint); +cond_syscall (sys_restart);
_
Re: [PATCH 1/9] Create syscalls: sys_checkpoint, sys_restart
Hey Dave,
Please CC linux-api with new syscall patches.
Cheers,
Michael
Quoted 158 lines · Dave Hansen
From: Oren Laadan <[email protected]>
Create trivial
sys_checkpointandsys_restoresystem calls. They will enable to checkpoint and restart an entire container, to and from a checkpoint image file descriptor.The syscalls take a file descriptor (for the image file) and flags as arguments. For
sys_checkpointthe first argument identifies the target container; forsys_restartit will identify the checkpoint image.Signed-off-by Oren Laadan <[email protected]>Signed-off-by Dave Hansen <[email protected]>---
linux-2.6.git-dave/arch/x86/kernel/syscall_table_32.S | 2 linux-2.6.git-dave/checkpoint/Kconfig | 11 ++++ linux-2.6.git-dave/checkpoint/Makefile | 5 ++ linux-2.6.git-dave/checkpoint/sys.c | 41 ++++++++++++++++++ linux-2.6.git-dave/include/asm-x86/unistd_32.h | 2 linux-2.6.git-dave/include/linux/syscalls.h | 2 linux-2.6.git-dave/init/Kconfig | 2 linux-2.6.git-dave/kernel/sys_ni.c | 4 + 8 files changed, 69 insertions(+)diff -puN
arch/x86/kernel/syscall_table_32.S~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartarch/x86/kernel/syscall_table_32.Sarch/x86/kernel/syscall_table_32.S 2008-10-16 10:53:33.000000000 -0700 renamed from arch/x86/kernel/syscall_table_32.S~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +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_restartdiff -puN
/dev/nullcheckpoint/Kconfigcheckpoint/Kconfig 2008-10-16 10:53:33.000000000 -0700 renamed from dev/null 2008-09-02 09:40:19.000000000 -0700 +11
-0@@ -0,0 +1,11 @@ +config CHECKPOINT_RESTART + prompt "Enable checkpoint/restart (EXPERIMENTAL)" + def_bool n + depends on X86_32 && EXPERIMENTAL + help + Application checkpoint/restart is the ability to save the + state of a running application so that it can later resume + its execution from the time at which it was checkpointed. + + Turning this option on will enable checkpoint and restart + functionality in the kernel.diff -puN
/dev/nullcheckpoint/Makefilecheckpoint/Makefile 2008-10-16 10:53:33.000000000 -0700 renamed from dev/null 2008-09-02 09:40:19.000000000 -0700 +5
-0@@ -0,0 +1,5 @@ +# +# Makefile for linux checkpoint/restart. +# + +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.odiff -puN
/dev/nullcheckpoint/sys.ccheckpoint/sys.c 2008-10-16 10:53:33.000000000 -0700 renamed from dev/null 2008-09-02 09:40:19.000000000 -0700 +41
-0@@ -0,0 +1,41 @@ +/* + * 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/kernel.h> + +/** + * 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 + * + * Returns positive identifier on success, 0 when returning from restart + * or negative value on error + */ +asmlinkage long sys_checkpoint(pid_t pid, int fd, unsigned long flags) +{ + pr_debug("sys_checkpoint not implemented yet\n"); + return -ENOSYS; +} +/** + * sys_restart - restart a container + * @crid: checkpoint image identifier + * @fd: file from which read the checkpoint image + * @flags: restart operation flags + * + * Returns negative value on error, or otherwise returns in the realm + * of the original checkpoint + */ +asmlinkage long sys_restart(int crid, int fd, unsigned long flags) +{ + pr_debug("sys_restart not implemented yet\n"); + return -ENOSYS; +}diff -puN
include/asm-x86/unistd_32.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartinclude/asm-x86/unistd_32.hinclude/asm-x86/unistd_32.h 2008-10-16 10:53:33.000000000 -0700 renamed from include/asm-x86/unistd_32.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +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__diff -puN
include/linux/syscalls.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartinclude/linux/syscalls.hinclude/linux/syscalls.h 2008-10-16 10:53:33.000000000 -0700 renamed from include/linux/syscalls.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +2
-0@@ -622,6 +622,8 @@ asmlinkage long sys_timerfd_gettime(int asmlinkage long sys_eventfd(unsigned int count); asmlinkage long sys_eventfd2(unsigned int count, int flags); asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); +asmlinkage long sys_checkpoint(pid_t pid, int fd, unsigned long flags); +asmlinkage long sys_restart(int crid, int fd, unsigned long flags); int kernel_execve(const char *filename, char *const argv[], char *const envp[]);diff -puN
init/Kconfig~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartinit/Kconfiginit/Kconfig 2008-10-16 10:53:33.000000000 -0700 renamed from init/Kconfig~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +2
-0@@ -779,6 +779,8 @@ config MARKERS source "arch/Kconfig" +source "checkpoint/Kconfig" + endmenu # General setup config HAVE_GENERIC_DMA_COHERENTdiff -puN
kernel/sys_ni.c~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartkernel/sys_ni.ckernel/sys_ni.c 2008-10-16 10:53:33.000000000 -0700 renamed from kernel/sys_ni.c~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +4
-0@@ -169,3 +169,7 @@ cond_syscall(compat_sys_timerfd_settime) cond_syscall(compat_sys_timerfd_gettime); cond_syscall(sys_eventfd); cond_syscall(sys_eventfd2); + +/* checkpoint/restart */ +cond_syscall(sys_checkpoint); +cond_syscall(sys_restart);_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Signature · 7 lines
Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Found a documentation bug? http://www.kernel.org/doc/man-pages/reporting_bugs.html -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/9] Create syscalls: sys_checkpoint, sys_restart
In reply to Dave HansenHey Dave,
Please CC linux-api with new syscall patches.
Cheers,
Michael
Quoted 158 lines · Dave Hansen
From: Oren Laadan <[email protected]>
Create trivial
sys_checkpointandsys_restoresystem calls. They will enable to checkpoint and restart an entire container, to and from a checkpoint image file descriptor.The syscalls take a file descriptor (for the image file) and flags as arguments. For
sys_checkpointthe first argument identifies the target container; forsys_restartit will identify the checkpoint image.Signed-off-by Oren Laadan <[email protected]>Signed-off-by Dave Hansen <[email protected]>---
linux-2.6.git-dave/arch/x86/kernel/syscall_table_32.S | 2 linux-2.6.git-dave/checkpoint/Kconfig | 11 ++++ linux-2.6.git-dave/checkpoint/Makefile | 5 ++ linux-2.6.git-dave/checkpoint/sys.c | 41 ++++++++++++++++++ linux-2.6.git-dave/include/asm-x86/unistd_32.h | 2 linux-2.6.git-dave/include/linux/syscalls.h | 2 linux-2.6.git-dave/init/Kconfig | 2 linux-2.6.git-dave/kernel/sys_ni.c | 4 + 8 files changed, 69 insertions(+)diff -puN
arch/x86/kernel/syscall_table_32.S~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartarch/x86/kernel/syscall_table_32.Sarch/x86/kernel/syscall_table_32.S 2008-10-16 10:53:33.000000000 -0700 renamed from arch/x86/kernel/syscall_table_32.S~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +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_restartdiff -puN
/dev/nullcheckpoint/Kconfigcheckpoint/Kconfig 2008-10-16 10:53:33.000000000 -0700 renamed from dev/null 2008-09-02 09:40:19.000000000 -0700 +11
-0@@ -0,0 +1,11 @@ +config CHECKPOINT_RESTART + prompt "Enable checkpoint/restart (EXPERIMENTAL)" + def_bool n + depends on X86_32 && EXPERIMENTAL + help + Application checkpoint/restart is the ability to save the + state of a running application so that it can later resume + its execution from the time at which it was checkpointed. + + Turning this option on will enable checkpoint and restart + functionality in the kernel.diff -puN
/dev/nullcheckpoint/Makefilecheckpoint/Makefile 2008-10-16 10:53:33.000000000 -0700 renamed from dev/null 2008-09-02 09:40:19.000000000 -0700 +5
-0@@ -0,0 +1,5 @@ +# +# Makefile for linux checkpoint/restart. +# + +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.odiff -puN
/dev/nullcheckpoint/sys.ccheckpoint/sys.c 2008-10-16 10:53:33.000000000 -0700 renamed from dev/null 2008-09-02 09:40:19.000000000 -0700 +41
-0@@ -0,0 +1,41 @@ +/* + * 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/kernel.h> + +/** + * 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 + * + * Returns positive identifier on success, 0 when returning from restart + * or negative value on error + */ +asmlinkage long sys_checkpoint(pid_t pid, int fd, unsigned long flags) +{ + pr_debug("sys_checkpoint not implemented yet\n"); + return -ENOSYS; +} +/** + * sys_restart - restart a container + * @crid: checkpoint image identifier + * @fd: file from which read the checkpoint image + * @flags: restart operation flags + * + * Returns negative value on error, or otherwise returns in the realm + * of the original checkpoint + */ +asmlinkage long sys_restart(int crid, int fd, unsigned long flags) +{ + pr_debug("sys_restart not implemented yet\n"); + return -ENOSYS; +}diff -puN
include/asm-x86/unistd_32.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartinclude/asm-x86/unistd_32.hinclude/asm-x86/unistd_32.h 2008-10-16 10:53:33.000000000 -0700 renamed from include/asm-x86/unistd_32.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +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__diff -puN
include/linux/syscalls.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartinclude/linux/syscalls.hinclude/linux/syscalls.h 2008-10-16 10:53:33.000000000 -0700 renamed from include/linux/syscalls.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +2
-0@@ -622,6 +622,8 @@ asmlinkage long sys_timerfd_gettime(int asmlinkage long sys_eventfd(unsigned int count); asmlinkage long sys_eventfd2(unsigned int count, int flags); asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); +asmlinkage long sys_checkpoint(pid_t pid, int fd, unsigned long flags); +asmlinkage long sys_restart(int crid, int fd, unsigned long flags); int kernel_execve(const char *filename, char *const argv[], char *const envp[]);diff -puN
init/Kconfig~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartinit/Kconfiginit/Kconfig 2008-10-16 10:53:33.000000000 -0700 renamed from init/Kconfig~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +2
-0@@ -779,6 +779,8 @@ config MARKERS source "arch/Kconfig" +source "checkpoint/Kconfig" + endmenu # General setup config HAVE_GENERIC_DMA_COHERENTdiff -puN
kernel/sys_ni.c~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restartkernel/sys_ni.ckernel/sys_ni.c 2008-10-16 10:53:33.000000000 -0700 renamed from kernel/sys_ni.c~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart 2008-10-16 10:53:33.000000000 -0700 +4
-0@@ -169,3 +169,7 @@ cond_syscall(compat_sys_timerfd_settime) cond_syscall(compat_sys_timerfd_gettime); cond_syscall(sys_eventfd); cond_syscall(sys_eventfd2); + +/* checkpoint/restart */ +cond_syscall(sys_checkpoint); +cond_syscall(sys_restart);_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Signature · 3 lines
Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Found a documentation bug? http://www.kernel.org/doc/man-pages/reporting_bugs.html
PATCH 2/9 General infrastructure for checkpoint restart
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Add those interfaces, as well as helpers needed to easily manage the file format. The code is roughly broken out as follows:
checkpoint/sys.c - user/kernel data transfer, as well as setup of the checkpoint/restart context (a per-checkpoint data structure for housekeeping)
checkpoint/checkpoint.c - output wrappers and basic checkpoint handling
checkpoint/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.
---
linux-2.6.git-dave/Makefile | 2 linux-2.6.git-dave/checkpoint/Makefile | 2 linux-2.6.git-dave/checkpoint/checkpoint.c | 174 +++++++++++++++++ linux-2.6.git-dave/checkpoint/restart.c | 197 +++++++++++++++++++ linux-2.6.git-dave/checkpoint/sys.c | 219 +++++++++++++++++++++- linux-2.6.git-dave/fs/read_write.c | 4 linux-2.6.git-dave/include/linux/checkpoint.h | 60 ++++++ linux-2.6.git-dave/include/linux/checkpoint_hdr.h | 75 +++++++ linux-2.6.git-dave/include/linux/magic.h | 3 9 files changed, 728 insertions(+), 8 deletions(-)
checkpoint/checkpoint.c new file +174 -0
@@ -0,0 +1,174 @@ +/* +* 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/mount.h> +#include <linux/utsname.h> +#include <linux/magic.h> +#include <linux/checkpoint.h> +#include <linux/checkpoint_hdr.h> + +/** +* 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; + + ret =cr_kwrite (ctx, h,sizeof (*h)); +if (ret <0 ) +return ret; +return cr_kwrite (ctx, buf, h->len); +} + +/** +* cr_write_string - write a string +* @ctx: checkpoint context +* @str: string pointer +* @len: string length +*/ +int cr_write_string (struct cr_ctx *ctx,char *str,int len) +{ +struct cr_hdr h; + + h.type =CR_HDR_STRING ; + h.len = len; + h.parent =0 ; + +return cr_write_obj (ctx, &h, str); +} + +/* write the checkpoint header */ +static int cr_write_head (struct cr_ctx *ctx) +{ +struct cr_hdr h; +struct cr_hdr_head *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct new_utsname *uts; +struct timeval ktv; +int ret; + + h.type =CR_HDR_HEAD ; + h.len =sizeof (*hh); + h.parent =0 ; + +do_gettimeofday (&ktv); + + hh->magic =CHECKPOINT_MAGIC_HEAD ; + hh->major = (LINUX_VERSION_CODE >>16 ) &0xff ; + hh->minor = (LINUX_VERSION_CODE >>8 ) &0xff ; + hh->patch = (LINUX_VERSION_CODE ) &0xff ; + + hh->rev =CR_VERSION ; + + hh->flags = ctx->flags; + hh->time = ktv.tv_sec; + + uts =utsname (); +memcpy (hh->release, uts->release, __NEW_UTS_LEN); +memcpy (hh->version, uts->version, __NEW_UTS_LEN); +memcpy (hh->machine, uts->machine, __NEW_UTS_LEN); + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +} + +/* write the checkpoint trailer */ +static int cr_write_tail (struct cr_ctx *ctx) +{ +struct cr_hdr h; +struct cr_hdr_tail *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + h.type =CR_HDR_TAIL ; + h.len =sizeof (*hh); + h.parent =0 ; + + hh->magic =CHECKPOINT_MAGIC_TAIL ; + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*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 =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + h.type =CR_HDR_TASK ; + h.len =sizeof (*hh); + h.parent =0 ; + + hh->state = t->state; + hh->exit_state = t->exit_state; + hh->exit_code = t->exit_code; + hh->exit_signal = t->exit_signal; + + hh->task_comm_len =TASK_COMM_LEN ; + +/* FIXME: save remaining relevant task_struct fields */ + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) +return ret; + +return cr_write_string (ctx, t->comm,TASK_COMM_LEN ); +} + +/* dump the entire state of a given task */ +static int cr_write_task (struct cr_ctx *ctx,struct task_struct *t) +{ +int ret ; + +if (t->state ==TASK_DEAD ) { +pr_warning ("CR: task may not be in state TASK_DEAD\n" ); +return -EAGAIN ; + } + + ret =cr_write_task_struct (ctx, t); +cr_debug ("ret %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_head (ctx); +if (ret <0 ) + goto out; + ret =cr_write_task (ctx, current); +if (ret <0 ) + goto out; + ret =cr_write_tail (ctx); +if (ret <0 ) + goto out; + +/* on success, return (unique) checkpoint identifier */ + ret = ctx->crid; + + out: +return ret; +}
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_2_9_General_infrastructure_for_checkpoint_restart +1 -1
@@ -2,4 +2,4 @@ # Makefile for linux checkpoint/restart. # -obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o
checkpoint/restart.c new file +197 -0
197 lines not on this page · raw message
checkpoint/sys.c renamed from checkpoint/sys.c~v6_PATCH_2_9_General_infrastructure_for_checkpoint_restart +215 -4
236 lines not on this page · raw message
fs/read_write.c renamed from fs/read_write.c~v6_PATCH_2_9_General_infrastructure_for_checkpoint_restart +2 -2
@@ -324,12 +324,12 @@ ssize_t vfs_write(struct file *file, conEXPORT_SYMBOL (vfs_write); -static inline loff_t file_pos_read (struct file *file) +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) +inline void file_pos_write (struct file *file,loff_t pos) { file->f_pos = pos; }
include/linux/checkpoint.h new file +60 -0
60 lines not on this page · raw message
include/linux/checkpoint_hdr.h new file +75 -0
75 lines not on this page · raw message
include/linux/magic.h renamed from include/linux/magic.h~v6_PATCH_2_9_General_infrastructure_for_checkpoint_restart +3 -0
@@ -46,4 +46,7 @@#define FUTEXFS_SUPER_MAGIC 0xBAD1DEA#define INOTIFYFS_SUPER_MAGIC 0x2BAD1DEA +#define CHECKPOINT_MAGIC_HEAD 0x00feed0cc0a2d200LL +#define CHECKPOINT_MAGIC_TAIL 0x002d2a0cc0deef00LL +#endif /* __LINUX_MAGIC_H__ */
Makefile renamed from Makefile~v6_PATCH_2_9_General_infrastructure_for_checkpoint_restart +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) \
_
PATCH 3/9 x86 support for checkpoint/restart
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
(Following Dave Hansen's refactoring of the original post)
Add logic to save and restore architecture specific state, including thread-specific state, CPU registers and FPU state.
Currently only x86-32 is supported. Compiling on x86-64 will trigger an explicit error.
---
linux-2.6.git-dave/arch/x86/mm/Makefile | 2 linux-2.6.git-dave/arch/x86/mm/checkpoint.c | 198 ++++++++++++++++++++ linux-2.6.git-dave/arch/x86/mm/restart.c | 190 +++++++++++++++++++ linux-2.6.git-dave/checkpoint/checkpoint.c | 13 + linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 7 linux-2.6.git-dave/checkpoint/restart.c | 13 + linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 72 +++++++ linux-2.6.git-dave/include/linux/checkpoint_hdr.h | 1 8 files changed, 494 insertions(+), 2 deletions(-)
arch/x86/mm/checkpoint.c new file +198 -0
@@ -0,0 +1,198 @@ +/* +* Checkpoint/restart - architecture specific support for x86 +* +* 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 <asm/desc.h> +#include <asm/i387.h> + +#include <linux/checkpoint.h> +#include <linux/checkpoint_hdr.h> + +/* dump the thread_struct of a given task */ +int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_thread *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct thread_struct *thread; +struct desc_struct *desc; +int ntls =0 ; +int n, ret; + + h.type =CR_HDR_THREAD ; + h.len =sizeof (*hh); + h.parent =task_pid_vnr (t); + + thread = &t->thread; + +/* calculate no. of TLS entries that follow */ + desc = thread->tls_array; +for (n =GDT_ENTRY_TLS_ENTRIES ; n >0 ; n--, desc++) { +if (desc->a || desc->b) + ntls++; + } + + hh->gdt_entry_tls_entries =GDT_ENTRY_TLS_ENTRIES ; + hh->sizeof_tls_array =sizeof (thread->tls_array); + hh->ntls = ntls; + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) +return ret; + +/* for simplicity dump the entire array, cherry-pick upon restart */ + ret =cr_kwrite (ctx, thread->tls_array,sizeof (thread->tls_array)); + +cr_debug ("ntls %d\n" , ntls); + +/* IGNORE RESTART BLOCKS FOR NOW ... */ + +return ret; +} + +#ifdef CONFIG_X86_64 + +#error "CONFIG_X86_64 unsupported yet." + +#else /* !CONFIG_X86_64 */ + +void cr_write_cpu_regs (struct cr_hdr_cpu *hh,struct task_struct *t) +{ +struct thread_struct *thread = &t->thread; +struct pt_regs *regs =task_pt_regs (t); + + hh->bp = regs->bp; + hh->bx = regs->bx; + hh->ax = regs->ax; + hh->cx = regs->cx; + hh->dx = regs->dx; + hh->si = regs->si; + hh->di = regs->di; + hh->orig_ax = regs->orig_ax; + hh->ip = regs->ip; + hh->cs = regs->cs; + hh->flags = regs->flags; + hh->sp = regs->sp; + hh->ss = regs->ss; + + hh->ds = regs->ds; + hh->es = regs->es; + +/* +* for checkpoint in process context (from within a container) +* the GS and FS registers should be saved from the hardware; +* otherwise they are already sabed on the thread structure +*/ +if (t == current) { +savesegment (gs, hh->gs); +savesegment (fs, hh->fs); + }else { + hh->gs = thread->gs; + hh->fs = thread->fs; + } + +/* +* for checkpoint in process context (from within a container), +* the actual syscall is taking place at this very moment; so +* we (optimistically) subtitute the future return value (0) of +* this syscall into the orig_eax, so that upon restart it will +* succeed (or it will endlessly retry checkpoint...) +*/ +if (t == current) { +BUG_ON (hh->orig_ax <0 ); + hh->ax =0 ; + } +} + +void cr_write_cpu_debug (struct cr_hdr_cpu *hh,struct task_struct *t) +{ +struct thread_struct *thread = &t->thread; + +/* debug regs */ + +preempt_disable (); + +/* +* for checkpoint in process context (from within a container), +* get the actual registers; otherwise get the saved values. +*/ + +if (t == current) { +get_debugreg (hh->debugreg0,0 ); +get_debugreg (hh->debugreg1,1 ); +get_debugreg (hh->debugreg2,2 ); +get_debugreg (hh->debugreg3,3 ); +get_debugreg (hh->debugreg6,6 ); +get_debugreg (hh->debugreg7,7 ); + }else { + hh->debugreg0 = thread->debugreg0; + hh->debugreg1 = thread->debugreg1; + hh->debugreg2 = thread->debugreg2; + hh->debugreg3 = thread->debugreg3; + hh->debugreg6 = thread->debugreg6; + hh->debugreg7 = thread->debugreg7; + } + + hh->debugreg4 =0 ; + hh->debugreg5 =0 ; + + hh->uses_debug = !!(task_thread_info (t)->flags &TIF_DEBUG ); + +preempt_enable (); +} + +void cr_write_cpu_fpu (struct cr_hdr_cpu *hh,struct task_struct *t) +{ +struct thread_struct *thread = &t->thread; +struct thread_info *thread_info =task_thread_info (t); + +/* i387 + MMU + SSE logic */ + +preempt_disable (); + + hh->used_math =tsk_used_math (t) ?1 :0 ; +if (hh->used_math) { +/* +* normally, no need to unlazy_fpu(), since TS_USEDFPU flag +* have been cleared when task was conexted-switched out... +* except if we are in process context, in which case we do +*/ +if (thread_info->status &TS_USEDFPU ) +unlazy_fpu (current); + + hh->has_fxsr = cpu_has_fxsr; +memcpy (&hh->xstate, &thread->xstate,sizeof (thread->xstate)); + } + +preempt_enable (); +} + +#endif /* CONFIG_X86_64 */ + +/* dump the cpu state and registers of a given task */ +int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_cpu *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + h.type =CR_HDR_CPU ; + h.len =sizeof (*hh); + h.parent =task_pid_vnr (t); + +cr_write_cpu_regs (hh, t); +cr_write_cpu_debug (hh, t); +cr_write_cpu_fpu (hh, t); + +cr_debug ("math %d debug %d\n" , hh->used_math, hh->uses_debug); + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +}
arch/x86/mm/Makefile renamed from arch/x86/mm/Makefile~v6_PATCH_3_9_x86_support_for_checkpoint_restart +2 -0
@@ -18,3 +18,5 @@ obj-$(CONFIG_K8_NUMA) += k8topology_64. obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o obj-$(CONFIG_MEMTEST) += memtest.o + +obj-$(CONFIG_CHECKPOINT_RESTART) += checkpoint.o restart.o
arch/x86/mm/restart.c new file +190 -0
190 lines not on this page · raw message
checkpoint/checkpoint_arch.h new file +7 -0
@@ -0,0 +1,7 @@ +#include <linux/checkpoint.h> + +extern int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t); +extern int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t); + +extern int cr_read_thread (struct cr_ctx *ctx); +extern int cr_read_cpu (struct cr_ctx *ctx);
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~v6_PATCH_3_9_x86_support_for_checkpoint_restart +12 -1
@@ -20,6 +20,8 @@#include <linux/checkpoint.h> #include <linux/checkpoint_hdr.h> +#include "checkpoint_arch.h" +/** * cr_write_obj - write a record described by a cr_hdr * @ctx: checkpoint context
@@ -145,8 +147,17 @@ static int cr_write_task(struct cr_ctx * } ret =cr_write_task_struct (ctx, t); -cr_debug ("ret %d\n" , ret); +cr_debug ("task_struct: ret %d\n" , ret); +if (ret <0 ) + goto out; + ret =cr_write_thread (ctx, t); +cr_debug ("thread: ret %d\n" , ret); +if (ret <0 ) + goto out; + ret =cr_write_cpu (ctx, t); +cr_debug ("cpu: ret %d\n" , ret); + out:return ret; }
checkpoint/restart.c renamed from checkpoint/restart.c~v6_PATCH_3_9_x86_support_for_checkpoint_restart +12 -1
@@ -15,6 +15,8 @@#include <linux/checkpoint.h> #include <linux/checkpoint_hdr.h> +#include "checkpoint_arch.h" +/** * cr_read_obj - read a whole record (cr_hdr followed by payload) * @ctx: checkpoint context
@@ -172,8 +174,17 @@ static int cr_read_task(struct cr_ctx *cint ret; ret =cr_read_task_struct (ctx); -cr_debug ("ret %d\n" , ret); +cr_debug ("task_struct: ret %d\n" , ret); +if (ret <0 ) + goto out; + ret =cr_read_thread (ctx); +cr_debug ("thread: ret %d\n" , ret); +if (ret <0 ) + goto out; + ret =cr_read_cpu (ctx); +cr_debug ("cpu: ret %d\n" , ret); + out:return ret; }
include/asm-x86/checkpoint_hdr.h new file +72 -0
72 lines not on this page · raw message
include/linux/checkpoint_hdr.h renamed from include/linux/checkpoint_hdr.h~v6_PATCH_3_9_x86_support_for_checkpoint_restart +1 -0
@@ -12,6 +12,7 @@#include <linux/types.h> #include <linux/utsname.h> +#include <asm/checkpoint_hdr.h> /* * To maintain compatibility between 32-bit and 64-bit architecture flavors,
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 4/9 Dump memory address space
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
For each VMA, there is a 'struct cr_vma'; if the VMA is file-mapped, it will be followed by the file name. Then comes the actual contents, in one or more chunk: each chunk begins with a header that specifies how many pages it holds, then the virtual addresses of all the dumped pages in that chunk, followed by the actual contents of all dumped pages. A header with zero number of pages marks the end of the contents. Then comes the next VMA and so on.
---
linux-2.6.git-dave/arch/x86/mm/checkpoint.c | 31 + linux-2.6.git-dave/arch/x86/mm/restart.c | 1 linux-2.6.git-dave/checkpoint/Makefile | 3 linux-2.6.git-dave/checkpoint/checkpoint.c | 53 ++ linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 2 linux-2.6.git-dave/checkpoint/checkpoint_mem.h | 41 + linux-2.6.git-dave/checkpoint/ckpt_mem.c | 500 ++++++++++++++++++++ linux-2.6.git-dave/checkpoint/sys.c | 16 linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 5 linux-2.6.git-dave/include/linux/checkpoint.h | 12 linux-2.6.git-dave/include/linux/checkpoint_hdr.h | 32 + 11 files changed, 695 insertions(+), 1 deletion(-)
arch/x86/mm/checkpoint.c renamed from arch/x86/mm/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space +31 -0
@@ -196,3 +196,34 @@ int cr_write_cpu(struct cr_ctx *ctx, strcr_hbuf_put (ctx,sizeof (*hh));return ret; } + +/* dump the mm->context state */ +int cr_write_mm_context (struct cr_ctx *ctx,struct mm_struct *mm,int parent) +{ +struct cr_hdr h; +struct cr_hdr_mm_context *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + h.type =CR_HDR_MM_CONTEXT ; + h.len =sizeof (*hh); + h.parent = parent; + +mutex_lock (&mm->context.lock); + + hh->ldt_entry_size =LDT_ENTRY_SIZE ; + hh->nldt = mm->context.size; + +cr_debug ("nldt %d\n" , hh->nldt); + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) + goto out; + + ret =cr_kwrite (ctx, mm->context.ldt, + mm->context.size *LDT_ENTRY_SIZE ); + + out: +mutex_unlock (&mm->context.lock); +return ret; +}
arch/x86/mm/restart.c renamed from arch/x86/mm/restart.c~v6_PATCH_4_9_Dump_memory_address_space +1 -0
@@ -8,6 +8,7 @@* distribution for more details. */ +#include <linux/unistd.h> #include <asm/desc.h> #include <asm/i387.h>
checkpoint/checkpoint_arch.h renamed from checkpoint/checkpoint_arch.h~v6_PATCH_4_9_Dump_memory_address_space +2 -0
@@ -2,6 +2,8 @@extern int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t);extern int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t); +extern int cr_write_mm_context (struct cr_ctx *ctx, +struct mm_struct *mm,int parent);extern int cr_read_thread (struct cr_ctx *ctx);extern int cr_read_cpu (struct cr_ctx *ctx);
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space +53 -0
65 lines not on this page · raw message
checkpoint/checkpoint_mem.h new file +41 -0
41 lines not on this page · raw message
checkpoint/ckpt_mem.c new file +500 -0
500 lines not on this page · raw message
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_4_9_Dump_memory_address_space +2 -1
@@ -2,4 +2,5 @@ # Makefile for linux checkpoint/restart. # -obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ + ckpt_mem.o
checkpoint/sys.c renamed from checkpoint/sys.c~v6_PATCH_4_9_Dump_memory_address_space +16 -0
@@ -16,6 +16,8 @@#include <linux/capability.h> #include <linux/checkpoint.h> +#include "checkpoint_mem.h" +/* * helpers to write/read to/from the image file descriptor *
@@ -161,6 +163,11 @@ void cr_ctx_free(struct cr_ctx *ctx)kfree (ctx->hbuf); +if (ctx->vfsroot) +path_put (ctx->vfsroot); + +cr_pgarr_free (ctx); +kfree (ctx); }
@@ -184,6 +191,15 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, ireturn ERR_PTR (-ENOMEM ); } +/* +* assume checkpointer is in container's root vfs +* FIXME: this works for now, but will change with real containers +*/ + ctx->vfsroot = ¤t->fs->root; +path_get (ctx->vfsroot); + +INIT_LIST_HEAD (&ctx->pgarr_list); + ctx->pid = pid; ctx->flags = flags;
include/asm-x86/checkpoint_hdr.h renamed from include/asm-x86/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_space +5 -0
@@ -69,4 +69,9 @@ struct cr_hdr_cpu { } __attribute__((aligned(8))); +struct cr_hdr_mm_context { +__s16 ldt_entry_size; +__s16 nldt; +} __attribute__((aligned (8 ))); +#endif /* __ASM_X86_CKPT_HDR__H */
include/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_4_9_Dump_memory_address_space +12 -0
@@ -10,6 +10,9 @@* distribution for more details. */ +#include <linux/path.h> +#include <linux/fs.h> +#define CR_VERSION 1struct cr_ctx {
@@ -24,6 +27,10 @@ struct cr_ctx {void *hbuf;/* temporary buffer for headers */ int hpos;/* position in headers buffer */ + +struct list_head pgarr_list;/* page array to dump VMA contents */ + +struct path *vfsroot;/* container root (FIXME) */ };/* cr_ctx: flags */
@@ -42,11 +49,16 @@ struct cr_hdr;extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf);extern int cr_write_string (struct cr_ctx *ctx,char *str,int len); +extern int cr_write_fname (struct cr_ctx *ctx, +struct path *path,struct path *root);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_string (struct cr_ctx *ctx,void *str,int len); +extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t); +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);
include/linux/checkpoint_hdr.h renamed from include/linux/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_space +32 -0
@@ -32,6 +32,7 @@ struct cr_hdr {enum {CR_HDR_HEAD =1 ,CR_HDR_STRING , +CR_HDR_FNAME ,CR_HDR_TASK =101 ,CR_HDR_THREAD ,
@@ -39,6 +40,7 @@ enum {CR_HDR_MM =201 ,CR_HDR_VMA , +CR_HDR_PGARR ,CR_HDR_MM_CONTEXT ,CR_HDR_TAIL =5001
@@ -73,4 +75,34 @@ struct cr_hdr_task {__s32 task_comm_len; } __attribute__((aligned(8))); +struct cr_hdr_mm { +__u32 objref;/* identifier for shared objects */ +__u32 map_count; + +__u64 start_code, end_code, start_data, end_data; +__u64 start_brk, brk, start_stack; +__u64 arg_start, arg_end, env_start, env_end; +} __attribute__((aligned (8 ))); + +/* vma subtypes */ +enum vm_type { +CR_VMA_ANON =1 , +CR_VMA_FILE +}; + +struct cr_hdr_vma { +__u32 vma_type; +__u32 _padding; + +__u64 vm_start; +__u64 vm_end; +__u64 vm_page_prot; +__u64 vm_flags; +__u64 vm_pgoff; +} __attribute__((aligned (8 ))); + +struct cr_hdr_pgarr { +__u64 nr_pages;/* number of pages to saved */ +} __attribute__((aligned (8 ))); +#endif /* _CHECKPOINT_CKPT_HDR_H_ */
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/9] Dump memory address space
Quoted 470 lines · Dave Hansen
From: Oren Laadan <[email protected]>
For each VMA, there is a 'struct
cr_vma'; if the VMA is file-mapped, it will be followed by the file name. Then comes the actual contents, in one or more chunk: each chunk begins with a header that specifies how many pages it holds, then the virtual addresses of all the dumped pages in that chunk, followed by the actual contents of all dumped pages. A header with zero number of pages marks the end of the contents. Then comes the next VMA and so on.Signed-off-by Oren Laadan <[email protected]>Acked-by Serge Hallyn <[email protected]>Signed-off-by Dave Hansen <[email protected]>---
linux-2.6.git-dave/arch/x86/mm/checkpoint.c | 31 + linux-2.6.git-dave/arch/x86/mm/restart.c | 1 linux-2.6.git-dave/checkpoint/Makefile | 3 linux-2.6.git-dave/checkpoint/checkpoint.c | 53 ++ linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 2 linux-2.6.git-dave/checkpoint/checkpoint_mem.h | 41 + linux-2.6.git-dave/checkpoint/ckpt_mem.c | 500 ++++++++++++++++++++ linux-2.6.git-dave/checkpoint/sys.c | 16 linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 5 linux-2.6.git-dave/include/linux/checkpoint.h | 12 linux-2.6.git-dave/include/linux/checkpoint_hdr.h | 32 + 11 files changed, 695 insertions(+), 1 deletion(-)diff -puN
arch/x86/mm/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_spacearch/x86/mm/checkpoint.carch/x86/mm/checkpoint.c renamed from arch/x86/mm/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space +31
-0@@ -196,3 +196,34 @@ int cr_write_cpu(struct cr_ctx *ctx, strcr_hbuf_put (ctx,sizeof (*hh));return ret; } + +/* dump the mm->context state */ +int cr_write_mm_context (struct cr_ctx *ctx,struct mm_struct *mm,int parent) +{ +struct cr_hdr h; +struct cr_hdr_mm_context *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + h.type =CR_HDR_MM_CONTEXT ; + h.len =sizeof (*hh); + h.parent = parent; + +mutex_lock (&mm->context.lock); + + hh->ldt_entry_size =LDT_ENTRY_SIZE ; + hh->nldt = mm->context.size; + +cr_debug ("nldt %d\n" , hh->nldt); + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) + goto out; + + ret =cr_kwrite (ctx, mm->context.ldt, + mm->context.size *LDT_ENTRY_SIZE ); + + out: +mutex_unlock (&mm->context.lock); +return ret; +}diff -puN
arch/x86/mm/restart.c~v6_PATCH_4_9_Dump_memory_address_spacearch/x86/mm/restart.carch/x86/mm/restart.c renamed from arch/x86/mm/restart.c~v6_PATCH_4_9_Dump_memory_address_space +1
-0@@ -8,6 +8,7 @@* distribution for more details. */ +#include <linux/unistd.h> #include <asm/desc.h> #include <asm/i387.h> diff -puN checkpoint/checkpoint_arch.h~v6_PATCH_4_9_Dump_memory_address_space
checkpoint/checkpoint_arch.hcheckpoint/checkpoint_arch.h renamed from checkpoint/checkpoint_arch.h~v6_PATCH_4_9_Dump_memory_address_space +2
-0@@ -2,6 +2,8 @@extern int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t);extern int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t); +extern int cr_write_mm_context (struct cr_ctx *ctx, +struct mm_struct *mm,int parent);extern int cr_read_thread (struct cr_ctx *ctx);extern int cr_read_cpu (struct cr_ctx *ctx);diff -puN checkpoint/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space
checkpoint/checkpoint.ccheckpoint/checkpoint.c renamed from checkpoint/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space +53
-0@@ -55,6 +55,55 @@ int cr_write_string(struct cr_ctx *ctx,return cr_write_obj (ctx, &h, str); } +/** +* cr_fill_fname - return pathname of a given file +* @path: path name +* @root: relative root +* @buf: buffer for pathname +* @n: buffer length (in) and pathname length (out) +*/ +static char * +cr_fill_fname (struct path *path,struct path *root,char *buf,int *n) +{ +char *fname; + +BUG_ON (!buf); + fname =__d_path (path, root, buf, *n); +if (!IS_ERR (fname)) + *n = (buf + (*n) - fname); +return fname; +} + +/** +* cr_write_fname - write a file name +* @ctx: checkpoint context +* @path: path name +* @root: relative root +*/ +int cr_write_fname (struct cr_ctx *ctx,struct path *path,struct path *root) +{ +struct cr_hdr h; +char *buf, *fname; +int ret, flen; + + flen =PATH_MAX ; + buf =kmalloc (flen,GFP_KERNEL ); +if (!buf) +return -ENOMEM ; + + fname =cr_fill_fname (path, root, buf, &flen); +if (!IS_ERR (fname)) { + h.type =CR_HDR_FNAME ; + h.len = flen; + h.parent =0 ; + ret =cr_write_obj (ctx, &h, fname); + }else + ret =PTR_ERR (fname); + +kfree (buf); +return ret; +} +/* write the checkpoint header */ static int cr_write_head (struct cr_ctx *ctx) {@@ -150,6 +199,10 @@ static int cr_write_task(struct cr_ctx *cr_debug ("task_struct: ret %d\n" , ret);if (ret <0 ) goto out; + ret =cr_write_mm (ctx, t); +cr_debug ("memory: ret %d\n" , ret); +if (ret <0 ) + goto out; ret =cr_write_thread (ctx, t);cr_debug ("thread: ret %d\n" , ret);if (ret <0 )diff -puN
/dev/nullcheckpoint/checkpoint_mem.hcheckpoint/checkpoint_mem.h new file +41
-0@@ -0,0 +1,41 @@ +#ifndef _CHECKPOINT_CKPT_MEM_H_ +#define _CHECKPOINT_CKPT_MEM_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/mm_types.h> + +/* +* page-array chains: each cr_pgarr describes a set of <strcut page *,vaddr> +* tuples (where vaddr is the virtual address of a page in a particular mm). +* Specifically, we use separate arrays so that all vaddrs can be written +* and read at once. +*/ + +struct cr_pgarr { +unsigned long *vaddrs; +struct page **pages; +unsigned int nr_used; +struct list_head list; +}; + +#define CR_PGARR_TOTAL (PAGE_SIZE / sizeof(void *)) +#define CR_PGARR_CHUNK (4 * CR_PGARR_TOTAL) + +extern void cr_pgarr_free (struct cr_ctx *ctx); +extern struct cr_pgarr *cr_pgarr_current (struct cr_ctx *ctx); +extern void cr_pgarr_reset_all (struct cr_ctx *ctx); + +static inline int cr_pgarr_is_full (struct cr_pgarr *pgarr) +{ +return (pgarr->nr_used ==CR_PGARR_TOTAL ); +} + +#endif /* _CHECKPOINT_CKPT_MEM_H_ */ diff -puN
/dev/nullcheckpoint/ckpt_mem.ccheckpoint/ckpt_mem.c new file +262
-0@@ -0,0 +1,500 @@ +/* +* Checkpoint memory contents +* +* 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/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/file.h> +#include <linux/pagemap.h> +#include <linux/mm_types.h> +#include <linux/checkpoint.h> +#include <linux/checkpoint_hdr.h> + +#include "checkpoint_arch.h" +#include "checkpoint_mem.h" + +/* +* utilities to alloc, free, and handle 'struct cr_pgarr' (page-arrays) +* (common to ckpt_mem.c and rstr_mem.c). +* +* The checkpoint context structure has two members for page-arrays: +* ctx->pgarr_list: list head of the page-array chain +* +* During checkpoint (and restart) the chain tracks the dirty pages (page +* pointer and virtual address) of each MM. For a particular MM, these are +* always added to the head of the page-array chain (ctx->pgarr_list). +* This "current" page-array advances as necessary, and new page-array +* descriptors are allocated on-demand. Before the next chunk of pages, +* the chain is reset but not freed (that is, dereference page pointers). +*/ + +/* return first page-array in the chain */ +static inline struct cr_pgarr *cr_pgarr_first (struct cr_ctx *ctx) +{ +if (list_empty (&ctx->pgarr_list)) +return NULL ; + return list_first_entry(&ctx->pgarr_list, struct cr_pgarr, list); +} + +/* release pages referenced by a page-array */ +static void cr_pgarr_release_pages (struct cr_pgarr *pgarr) +{ +int i; + +cr_debug ("nr_used %d\n" , pgarr->nr_used); +/* +* although both checkpoint and restart use 'nr_used', we only +* collect pages during checkpoint; in restart we simply return +*/ +if (!pgarr->pages) +return ; +for (i = pgarr->nr_used; i--;/**/ ) +page_cache_release (pgarr->pages[i]); +} + +/* free a single page-array object */ +static void cr_pgarr_free_one (struct cr_pgarr *pgarr) +{ +cr_pgarr_release_pages (pgarr); +kfree (pgarr->pages); +kfree (pgarr->vaddrs); +kfree (pgarr); +} + +/* free a chain of page-arrays */ +void cr_pgarr_free (struct cr_ctx *ctx) +{ +struct cr_pgarr *pgarr, *tmp; + +list_for_each_entry_safe (pgarr, tmp, &ctx->pgarr_list, list) { +list_del (&pgarr->list); +cr_pgarr_free_one (pgarr); + } +} + +/* allocate a single page-array object */ +static struct cr_pgarr *cr_pgarr_alloc_one (unsigned long flags) +{ +struct cr_pgarr *pgarr; + + pgarr =kzalloc (sizeof (*pgarr),GFP_KERNEL ); +if (!pgarr) +return NULL ; + + pgarr->vaddrs =kmalloc (CR_PGARR_TOTAL *sizeof (unsigned long ), +GFP_KERNEL ); +if (!pgarr->vaddrs) + goto nomem; + +/* pgarr->pages is needed only for checkpoint */ +if (flags &CR_CTX_CKPT ) { + pgarr->pages =kmalloc (CR_PGARR_TOTAL *sizeof (struct page *), +GFP_KERNEL ); +if (!pgarr->pages) + goto nomem; + } + +return pgarr; + + nomem: +cr_pgarr_free_one (pgarr); +return NULL ; +} + +/* cr_pgarr_current - return the next available page-array in the chain +* @ctx: checkpoint context +* +* Returns the first page-array in the list that has space. Extends the +* list if none has space. +*/ +struct cr_pgarr *cr_pgarr_current (struct cr_ctx *ctx) +{ +struct cr_pgarr *pgarr; + + pgarr =cr_pgarr_first (ctx); +if (pgarr && !cr_pgarr_is_full (pgarr)) + goto out; + pgarr =cr_pgarr_alloc_one (ctx->flags); +if (!pgarr) + goto out; +list_add (&pgarr->list, &ctx->pgarr_list); + out: +return pgarr; +} + +/* reset the page-array chain (dropping page references if necessary) */ +void cr_pgarr_reset_all (struct cr_ctx *ctx) +{ +struct cr_pgarr *pgarr; + +list_for_each_entry (pgarr, &ctx->pgarr_list, list) { +cr_pgarr_release_pages (pgarr); + pgarr->nr_used =0 ; + } +} + +/* +* Checkpoint is outside the context of the checkpointee, so one cannot +* simply read pages from user-space. Instead, we scan the address space +* of the target to cherry-pick pages of interest. Selected pages are +* enlisted in a page-array chain (attached to the checkpoint context). +* To save their contents, each page is mapped to kernel memory and then +* dumped to the file descriptor. +*/ + + +/** +* cr_private_follow_page - return page pointer for dirty pages +* @vma - target vma +* @addr - page address +* +* Looks up the page that correspond to the address in the vma, and +* returns the page if it was modified (and grabs a reference to it), +* or otherwise returns NULL (or error). +* +* This function should _only_ called for private vma's. +*/ +static struct page * +cr_private_follow_page (struct vm_area_struct *vma,unsigned long addr) +{ +struct page *page; + +BUG_ON (vma->vm_flags & (VM_SHARED |VM_MAYSHARE )); + +/* +* simplified version of get_user_pages(): already have vma, +* only need FOLL_ANON, and (for now) ignore fault stats. +* +* follow_page() will return NULL if the page is not present +* (swapped), ZERO_PAGE(0) if the pte wasn't allocated, and +* the actual page pointer otherwise. +* +* FIXME: consolidate with get_user_pages() +*/ + +cond_resched (); +while (!(page =follow_page (vma, addr,FOLL_ANON |FOLL_GET ))) { +int ret; + +/* the page is swapped out - bring it in (optimize ?) */ + ret =handle_mm_fault (vma->vm_mm, vma, addr,0 ); +if (ret &VM_FAULT_ERROR ) { +if (ret &VM_FAULT_OOM ) +return ERR_PTR (-ENOMEM ); +else if (ret &VM_FAULT_SIGBUS ) +return ERR_PTR (-EFAULT ); +else +BUG (); +break ; + } +cond_resched (); + } + +if (IS_ERR (page)) +return page; + +/* +* We only care about dirty pages: either non-zero page, or +* file-backed (copy-on-write) that were touched. For the latter, +* the page_mapping() will be unset because it will no longer be +* mapped to the original file after having been modified. +*/ +if (page ==ZERO_PAGE (0 )) { +/* this is the zero page: ignore */ +page_cache_release (page); + page =NULL ; + }else if (vma->vm_file && (page_mapping (page) !=NULL )) { +/* file backed clean cow: ignore */ +page_cache_release (page); + page =NULL ; + } + +return page; +} + +/** +* cr_private_vma_fill_pgarr - fill a page-array with addr/page tuples +* @ctx - checkpoint context +* @pgarr - page-array to fill +* @vma - vma to scan +* @start - start address (updated) +* +* Returns the number of pages collected +*/ +static int +cr_private_vma_fill_pgarr (struct cr_ctx *ctx,struct cr_pgarr *pgarr, +struct vm_area_struct *vma,unsigned long *start) +{ +unsigned long end = vma->vm_end; +unsigned long addr = *start; +int orig_used = pgarr->nr_used; + +/* this function is only for private memory (anon or file-mapped) */ +BUG_ON (vma->vm_flags & (VM_SHARED |VM_MAYSHARE )); + +while (addr < end) { +struct page *page; + + page =cr_private_follow_page (vma, addr); +if (IS_ERR (page)) +return PTR_ERR (page); + +if (page) { + pgarr->pages[pgarr->nr_used] = page; + pgarr->vaddrs[pgarr->nr_used] = addr; + pgarr->nr_used++; + } + + addr +=PAGE_SIZE ; + +if (cr_pgarr_is_full (pgarr)) +break ; + } + + *start = addr; +return pgarr->nr_used - orig_used;
checkpoint/ckpt_mem.c line 272
Quoted 10 lines
checkpoint/ckpt_mem.c new file +10
-0+} + +/* dump contents of a pages: use kmap_atomic() to avoid TLB flush */ +static int cr_page_write (struct cr_ctx *ctx,struct page *page,char *buf) +{ +void *ptr; + + ptr =kmap_atomic (page,KM_USER1 ); +memcpy (buf, ptr,PAGE_SIZE ); +kunmap_atomic (page,KM_USER1 );
Shouldn't this be changed to kunmap_atomic(ptr, KM_USER1); It fixes a BUG_ON() I fall in when running Oren's example code if CONFIG_HIGHMEM is set. This occurs since 2nd call to cr_page_write():
Oct 16 17:41:35 akt kernel: kernel BUG at /home/lkernel/containers/lxc/linux-2.6.27-lxc2-cr/arch/x86/mm/highmem_32.c:87! Oct 16 17:41:35 akt kernel: invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Oct 16 17:41:35 akt kernel: Modules linked in: Oct 16 17:41:35 akt kernel: Oct 16 17:41:35 akt kernel: Pid: 4117, comm: ckpt Not tainted
(2.6.27-lxc2-cr #3)
Regards,
Nadia
Quoted 392 lines
checkpoint/ckpt_mem.c new file +228
-0+ +return cr_kwrite (ctx, buf,PAGE_SIZE ); +} + +/** +* cr_vma_dump_pages - dump pages listed in the ctx page-array chain +* @ctx - checkpoint context +* @total - total number of pages +* +* First dump all virtual addresses, followed by the contents of all pages +*/ +static int cr_vma_dump_pages (struct cr_ctx *ctx,int total) +{ +struct cr_pgarr *pgarr; +char *buf; +int i, ret =0 ; + +if (!total) +return 0 ; + +list_for_each_entry_reverse (pgarr, &ctx->pgarr_list, list) { + ret =cr_kwrite (ctx, pgarr->vaddrs, + pgarr->nr_used *sizeof (*pgarr->vaddrs)); +if (ret <0 ) +return ret; + } + + buf =kmalloc (PAGE_SIZE ,GFP_KERNEL ); +if (!buf) +return -ENOMEM ; + +list_for_each_entry_reverse (pgarr, &ctx->pgarr_list, list) { +for (i =0 ; i < pgarr->nr_used; i++) { + ret =cr_page_write (ctx, pgarr->pages[i], buf); +if (ret <0 ) + goto out; + } + } + + out: +kfree (buf); +return ret; +} + +/** +* cr_write_private_vma_contents - dump contents of a VMA with private memory +* @ctx - checkpoint context +* @vma - vma to scan +* +* Collect lists of pages that needs to be dumped, and corresponding +* virtual addresses into ctx->pgarr_list page-array chain. Then dump +* the addresses, followed by the page contents. +*/ +static int +cr_write_private_vma_contents (struct cr_ctx *ctx,struct vm_area_struct *vma) +{ +struct cr_hdr h; +struct cr_hdr_pgarr *hh; +unsigned long addr = vma->vm_start; +struct cr_pgarr *pgarr; +unsigned long cnt =0 ; +int ret; + +/* +* Work iteratively, collecting and dumping at most CR_PGARR_CHUNK +* in each round. Each iterations is divided into two steps: +* +* (1) scan: scan through the PTEs of the vma to collect the pages +* to dump (later we'll also make them COW), while keeping a list +* of pages and their corresponding addresses on ctx->pgarr_list. +* +* (2) dump: write out a header specifying how many pages, followed +* by the addresses of all pages in ctx->pgarr_list, followed by +* the actual contents of all pages. (Then, release the references +* to the pages and reset the page-array chain). +* +* (This split makes the logic simpler by first counting the pages +* that need saving. More importantly, it allows for a future +* optimization that will reduce application downtime by deferring +* the actual write-out of the data to after the application is +* allowed to resume execution). +* +* After dumpting the entire contents, conclude with a header that +* specifies 0 pages to mark the end of the contents. +*/ + + h.type =CR_HDR_PGARR ; + h.len =sizeof (*hh); + h.parent =0 ; + +while (addr < vma->vm_end) { + pgarr =cr_pgarr_current (ctx); +if (!pgarr) +return -ENOMEM ; + ret =cr_private_vma_fill_pgarr (ctx, pgarr, vma, &addr); +if (ret <0 ) +return ret; + cnt += ret; + +/* did we complete a chunk, or is this the last chunk ? */ +if (cnt >=CR_PGARR_CHUNK || (cnt && addr == vma->vm_end)) { + hh =cr_hbuf_get (ctx,sizeof (*hh)); + hh->nr_pages = cnt; + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) +return ret; + + ret =cr_vma_dump_pages (ctx, cnt); +if (ret <0 ) +return ret; + +cr_pgarr_reset_all (ctx); + } + } + +/* mark end of contents with header saying "0" pages */ + hh =cr_hbuf_get (ctx,sizeof (*hh)); + hh->nr_pages =0 ; + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); + +return ret; +} + +static int cr_write_vma (struct cr_ctx *ctx,struct vm_area_struct *vma) +{ +struct cr_hdr h; +struct cr_hdr_vma *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int vma_type, ret; + + h.type =CR_HDR_VMA ; + h.len =sizeof (*hh); + h.parent =0 ; + + hh->vm_start = vma->vm_start; + hh->vm_end = vma->vm_end; + hh->vm_page_prot = vma->vm_page_prot.pgprot; + hh->vm_flags = vma->vm_flags; + hh->vm_pgoff = vma->vm_pgoff; + +if (vma->vm_flags & (VM_SHARED |VM_IO |VM_HUGETLB |VM_NONLINEAR )) { +pr_warning ("CR: unsupported VMA %#lx\n" , vma->vm_flags); +cr_hbuf_put (ctx,sizeof (*hh)); +return -ENOSYS ; + } + +/* by default assume anon memory */ + vma_type =CR_VMA_ANON ; + +/* +* if there is a backing file, assume private-mapped +* (FIXME: check if the file is unlinked) +*/ +if (vma->vm_file) + vma_type =CR_VMA_FILE ; + + hh->vma_type = vma_type; + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) +return ret; + +/* save the file name, if relevant */ +if (vma->vm_file) { + ret =cr_write_fname (ctx, &vma->vm_file->f_path, ctx->vfsroot); +if (ret <0 ) +return ret; + } + +return cr_write_private_vma_contents (ctx, vma); +} + +int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_mm *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct mm_struct *mm; +struct vm_area_struct *vma; +int objref, ret; + + h.type =CR_HDR_MM ; + h.len =sizeof (*hh); + h.parent =task_pid_vnr (t); + + mm =get_task_mm (t); + + objref =0 ;/* will be meaningful with multiple processes */ + hh->objref = objref; + +down_read (&mm->mmap_sem); + + hh->start_code = mm->start_code; + hh->end_code = mm->end_code; + hh->start_data = mm->start_data; + hh->end_data = mm->end_data; + hh->start_brk = mm->start_brk; + hh->brk = mm->brk; + hh->start_stack = mm->start_stack; + hh->arg_start = mm->arg_start; + hh->arg_end = mm->arg_end; + hh->env_start = mm->env_start; + hh->env_end = mm->env_end; + + hh->map_count = mm->map_count; + +/* FIX: need also mm->flags */ + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) + goto out; + +/* write the vma's */ +for (vma = mm->mmap; vma; vma = vma->vm_next) { + ret =cr_write_vma (ctx, vma); +if (ret <0 ) + goto out; + } + + ret =cr_write_mm_context (ctx, mm, objref); + + out: +up_read (&mm->mmap_sem); +mmput (mm); +return ret; +}diff -puN checkpoint/Makefile~v6_PATCH_4_9_Dump_memory_address_space checkpoint/Makefile
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_4_9_Dump_memory_address_space +2
-1@@ -2,4 +2,5 @@ # Makefile for linux checkpoint/restart. # -obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ + ckpt_mem.odiff -puN checkpoint/sys.c~v6_PATCH_4_9_Dump_memory_address_space
checkpoint/sys.ccheckpoint/sys.c renamed from checkpoint/sys.c~v6_PATCH_4_9_Dump_memory_address_space +16
-0@@ -16,6 +16,8 @@#include <linux/capability.h> #include <linux/checkpoint.h> +#include "checkpoint_mem.h" +/* * helpers to write/read to/from the image file descriptor * @@ -161,6 +163,11 @@ void cr_ctx_free(struct cr_ctx *ctx)kfree (ctx->hbuf); +if (ctx->vfsroot) +path_put (ctx->vfsroot); + +cr_pgarr_free (ctx); +kfree (ctx); }@@ -184,6 +191,15 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, ireturn ERR_PTR (-ENOMEM ); } +/* +* assume checkpointer is in container's root vfs +* FIXME: this works for now, but will change with real containers +*/ + ctx->vfsroot = ¤t->fs->root; +path_get (ctx->vfsroot); + +INIT_LIST_HEAD (&ctx->pgarr_list); + ctx->pid = pid; ctx->flags = flags;diff -puN
include/asm-x86/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_spaceinclude/asm-x86/checkpoint_hdr.hinclude/asm-x86/checkpoint_hdr.h renamed from include/asm-x86/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_space +5
-0@@ -69,4 +69,9 @@ struct cr_hdr_cpu { } __attribute__((aligned(8))); +struct cr_hdr_mm_context { +__s16 ldt_entry_size; +__s16 nldt; +} __attribute__((aligned (8 ))); +#endif /* __ASM_X86_CKPT_HDR__H */ diff -puN
include/linux/checkpoint.h~v6_PATCH_4_9_Dump_memory_address_spaceinclude/linux/checkpoint.hinclude/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_4_9_Dump_memory_address_space +12
-0@@ -10,6 +10,9 @@* distribution for more details. */ +#include <linux/path.h> +#include <linux/fs.h> +#define CR_VERSION 1struct cr_ctx {@@ -24,6 +27,10 @@ struct cr_ctx {void *hbuf;/* temporary buffer for headers */ int hpos;/* position in headers buffer */ + +struct list_head pgarr_list;/* page array to dump VMA contents */ + +struct path *vfsroot;/* container root (FIXME) */ };/* cr_ctx: flags */ @@ -42,11 +49,16 @@ struct cr_hdr;extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf);extern int cr_write_string (struct cr_ctx *ctx,char *str,int len); +extern int cr_write_fname (struct cr_ctx *ctx, +struct path *path,struct path *root);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_string (struct cr_ctx *ctx,void *str,int len); +extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t); +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);diff -puN
include/linux/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_spaceinclude/linux/checkpoint_hdr.hinclude/linux/checkpoint_hdr.h renamed from include/linux/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_space +32
-0@@ -32,6 +32,7 @@ struct cr_hdr {enum {CR_HDR_HEAD =1 ,CR_HDR_STRING , +CR_HDR_FNAME ,CR_HDR_TASK =101 ,CR_HDR_THREAD ,@@ -39,6 +40,7 @@ enum {CR_HDR_MM =201 ,CR_HDR_VMA , +CR_HDR_PGARR ,CR_HDR_MM_CONTEXT ,CR_HDR_TAIL =5001 @@ -73,4 +75,34 @@ struct cr_hdr_task {__s32 task_comm_len; } __attribute__((aligned(8))); +struct cr_hdr_mm { +__u32 objref;/* identifier for shared objects */ +__u32 map_count; + +__u64 start_code, end_code, start_data, end_data; +__u64 start_brk, brk, start_stack; +__u64 arg_start, arg_end, env_start, env_end; +} __attribute__((aligned (8 ))); + +/* vma subtypes */ +enum vm_type { +CR_VMA_ANON =1 , +CR_VMA_FILE +}; + +struct cr_hdr_vma { +__u32 vma_type; +__u32 _padding; + +__u64 vm_start; +__u64 vm_end; +__u64 vm_page_prot; +__u64 vm_flags; +__u64 vm_pgoff; +} __attribute__((aligned (8 ))); + +struct cr_hdr_pgarr { +__u64 nr_pages;/* number of pages to saved */ +} __attribute__((aligned (8 ))); +#endif /* _CHECKPOINT_CKPT_HDR_H_ */ _
_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers
Signature · 7 lines
Nadia Derbey <[email protected]> -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/9] Dump memory address space
In reply to Dave HansenQuoted 470 lines · Dave Hansen
From: Oren Laadan <[email protected]>
For each VMA, there is a 'struct
cr_vma'; if the VMA is file-mapped, it will be followed by the file name. Then comes the actual contents, in one or more chunk: each chunk begins with a header that specifies how many pages it holds, then the virtual addresses of all the dumped pages in that chunk, followed by the actual contents of all dumped pages. A header with zero number of pages marks the end of the contents. Then comes the next VMA and so on.Signed-off-by Oren Laadan <[email protected]>Signed-off-by Dave Hansen <[email protected]>---
linux-2.6.git-dave/arch/x86/mm/checkpoint.c | 31 + linux-2.6.git-dave/arch/x86/mm/restart.c | 1 linux-2.6.git-dave/checkpoint/Makefile | 3 linux-2.6.git-dave/checkpoint/checkpoint.c | 53 ++ linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 2 linux-2.6.git-dave/checkpoint/checkpoint_mem.h | 41 + linux-2.6.git-dave/checkpoint/ckpt_mem.c | 500 ++++++++++++++++++++ linux-2.6.git-dave/checkpoint/sys.c | 16 linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 5 linux-2.6.git-dave/include/linux/checkpoint.h | 12 linux-2.6.git-dave/include/linux/checkpoint_hdr.h | 32 + 11 files changed, 695 insertions(+), 1 deletion(-)diff -puN
arch/x86/mm/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_spacearch/x86/mm/checkpoint.carch/x86/mm/checkpoint.c renamed from arch/x86/mm/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space +31
-0@@ -196,3 +196,34 @@ int cr_write_cpu(struct cr_ctx *ctx, strcr_hbuf_put (ctx,sizeof (*hh));return ret; } + +/* dump the mm->context state */ +int cr_write_mm_context (struct cr_ctx *ctx,struct mm_struct *mm,int parent) +{ +struct cr_hdr h; +struct cr_hdr_mm_context *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + h.type =CR_HDR_MM_CONTEXT ; + h.len =sizeof (*hh); + h.parent = parent; + +mutex_lock (&mm->context.lock); + + hh->ldt_entry_size =LDT_ENTRY_SIZE ; + hh->nldt = mm->context.size; + +cr_debug ("nldt %d\n" , hh->nldt); + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) + goto out; + + ret =cr_kwrite (ctx, mm->context.ldt, + mm->context.size *LDT_ENTRY_SIZE ); + + out: +mutex_unlock (&mm->context.lock); +return ret; +}diff -puN
arch/x86/mm/restart.c~v6_PATCH_4_9_Dump_memory_address_spacearch/x86/mm/restart.carch/x86/mm/restart.c renamed from arch/x86/mm/restart.c~v6_PATCH_4_9_Dump_memory_address_space +1
-0@@ -8,6 +8,7 @@* distribution for more details. */ +#include <linux/unistd.h> #include <asm/desc.h> #include <asm/i387.h> diff -puN checkpoint/checkpoint_arch.h~v6_PATCH_4_9_Dump_memory_address_space
checkpoint/checkpoint_arch.hcheckpoint/checkpoint_arch.h renamed from checkpoint/checkpoint_arch.h~v6_PATCH_4_9_Dump_memory_address_space +2
-0@@ -2,6 +2,8 @@extern int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t);extern int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t); +extern int cr_write_mm_context (struct cr_ctx *ctx, +struct mm_struct *mm,int parent);extern int cr_read_thread (struct cr_ctx *ctx);extern int cr_read_cpu (struct cr_ctx *ctx);diff -puN checkpoint/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space
checkpoint/checkpoint.ccheckpoint/checkpoint.c renamed from checkpoint/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space +53
-0@@ -55,6 +55,55 @@ int cr_write_string(struct cr_ctx *ctx,return cr_write_obj (ctx, &h, str); } +/** +* cr_fill_fname - return pathname of a given file +* @path: path name +* @root: relative root +* @buf: buffer for pathname +* @n: buffer length (in) and pathname length (out) +*/ +static char * +cr_fill_fname (struct path *path,struct path *root,char *buf,int *n) +{ +char *fname; + +BUG_ON (!buf); + fname =__d_path (path, root, buf, *n); +if (!IS_ERR (fname)) + *n = (buf + (*n) - fname); +return fname; +} + +/** +* cr_write_fname - write a file name +* @ctx: checkpoint context +* @path: path name +* @root: relative root +*/ +int cr_write_fname (struct cr_ctx *ctx,struct path *path,struct path *root) +{ +struct cr_hdr h; +char *buf, *fname; +int ret, flen; + + flen =PATH_MAX ; + buf =kmalloc (flen,GFP_KERNEL ); +if (!buf) +return -ENOMEM ; + + fname =cr_fill_fname (path, root, buf, &flen); +if (!IS_ERR (fname)) { + h.type =CR_HDR_FNAME ; + h.len = flen; + h.parent =0 ; + ret =cr_write_obj (ctx, &h, fname); + }else + ret =PTR_ERR (fname); + +kfree (buf); +return ret; +} +/* write the checkpoint header */ static int cr_write_head (struct cr_ctx *ctx) {@@ -150,6 +199,10 @@ static int cr_write_task(struct cr_ctx *cr_debug ("task_struct: ret %d\n" , ret);if (ret <0 ) goto out; + ret =cr_write_mm (ctx, t); +cr_debug ("memory: ret %d\n" , ret); +if (ret <0 ) + goto out; ret =cr_write_thread (ctx, t);cr_debug ("thread: ret %d\n" , ret);if (ret <0 )diff -puN
/dev/nullcheckpoint/checkpoint_mem.hcheckpoint/checkpoint_mem.h new file +41
-0@@ -0,0 +1,41 @@ +#ifndef _CHECKPOINT_CKPT_MEM_H_ +#define _CHECKPOINT_CKPT_MEM_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/mm_types.h> + +/* +* page-array chains: each cr_pgarr describes a set of <strcut page *,vaddr> +* tuples (where vaddr is the virtual address of a page in a particular mm). +* Specifically, we use separate arrays so that all vaddrs can be written +* and read at once. +*/ + +struct cr_pgarr { +unsigned long *vaddrs; +struct page **pages; +unsigned int nr_used; +struct list_head list; +}; + +#define CR_PGARR_TOTAL (PAGE_SIZE / sizeof(void *)) +#define CR_PGARR_CHUNK (4 * CR_PGARR_TOTAL) + +extern void cr_pgarr_free (struct cr_ctx *ctx); +extern struct cr_pgarr *cr_pgarr_current (struct cr_ctx *ctx); +extern void cr_pgarr_reset_all (struct cr_ctx *ctx); + +static inline int cr_pgarr_is_full (struct cr_pgarr *pgarr) +{ +return (pgarr->nr_used ==CR_PGARR_TOTAL ); +} + +#endif /* _CHECKPOINT_CKPT_MEM_H_ */ diff -puN
/dev/nullcheckpoint/ckpt_mem.ccheckpoint/ckpt_mem.c new file +262
-0@@ -0,0 +1,500 @@ +/* +* Checkpoint memory contents +* +* 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/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/file.h> +#include <linux/pagemap.h> +#include <linux/mm_types.h> +#include <linux/checkpoint.h> +#include <linux/checkpoint_hdr.h> + +#include "checkpoint_arch.h" +#include "checkpoint_mem.h" + +/* +* utilities to alloc, free, and handle 'struct cr_pgarr' (page-arrays) +* (common to ckpt_mem.c and rstr_mem.c). +* +* The checkpoint context structure has two members for page-arrays: +* ctx->pgarr_list: list head of the page-array chain +* +* During checkpoint (and restart) the chain tracks the dirty pages (page +* pointer and virtual address) of each MM. For a particular MM, these are +* always added to the head of the page-array chain (ctx->pgarr_list). +* This "current" page-array advances as necessary, and new page-array +* descriptors are allocated on-demand. Before the next chunk of pages, +* the chain is reset but not freed (that is, dereference page pointers). +*/ + +/* return first page-array in the chain */ +static inline struct cr_pgarr *cr_pgarr_first (struct cr_ctx *ctx) +{ +if (list_empty (&ctx->pgarr_list)) +return NULL ; + return list_first_entry(&ctx->pgarr_list, struct cr_pgarr, list); +} + +/* release pages referenced by a page-array */ +static void cr_pgarr_release_pages (struct cr_pgarr *pgarr) +{ +int i; + +cr_debug ("nr_used %d\n" , pgarr->nr_used); +/* +* although both checkpoint and restart use 'nr_used', we only +* collect pages during checkpoint; in restart we simply return +*/ +if (!pgarr->pages) +return ; +for (i = pgarr->nr_used; i--;/**/ ) +page_cache_release (pgarr->pages[i]); +} + +/* free a single page-array object */ +static void cr_pgarr_free_one (struct cr_pgarr *pgarr) +{ +cr_pgarr_release_pages (pgarr); +kfree (pgarr->pages); +kfree (pgarr->vaddrs); +kfree (pgarr); +} + +/* free a chain of page-arrays */ +void cr_pgarr_free (struct cr_ctx *ctx) +{ +struct cr_pgarr *pgarr, *tmp; + +list_for_each_entry_safe (pgarr, tmp, &ctx->pgarr_list, list) { +list_del (&pgarr->list); +cr_pgarr_free_one (pgarr); + } +} + +/* allocate a single page-array object */ +static struct cr_pgarr *cr_pgarr_alloc_one (unsigned long flags) +{ +struct cr_pgarr *pgarr; + + pgarr =kzalloc (sizeof (*pgarr),GFP_KERNEL ); +if (!pgarr) +return NULL ; + + pgarr->vaddrs =kmalloc (CR_PGARR_TOTAL *sizeof (unsigned long ), +GFP_KERNEL ); +if (!pgarr->vaddrs) + goto nomem; + +/* pgarr->pages is needed only for checkpoint */ +if (flags &CR_CTX_CKPT ) { + pgarr->pages =kmalloc (CR_PGARR_TOTAL *sizeof (struct page *), +GFP_KERNEL ); +if (!pgarr->pages) + goto nomem; + } + +return pgarr; + + nomem: +cr_pgarr_free_one (pgarr); +return NULL ; +} + +/* cr_pgarr_current - return the next available page-array in the chain +* @ctx: checkpoint context +* +* Returns the first page-array in the list that has space. Extends the +* list if none has space. +*/ +struct cr_pgarr *cr_pgarr_current (struct cr_ctx *ctx) +{ +struct cr_pgarr *pgarr; + + pgarr =cr_pgarr_first (ctx); +if (pgarr && !cr_pgarr_is_full (pgarr)) + goto out; + pgarr =cr_pgarr_alloc_one (ctx->flags); +if (!pgarr) + goto out; +list_add (&pgarr->list, &ctx->pgarr_list); + out: +return pgarr; +} + +/* reset the page-array chain (dropping page references if necessary) */ +void cr_pgarr_reset_all (struct cr_ctx *ctx) +{ +struct cr_pgarr *pgarr; + +list_for_each_entry (pgarr, &ctx->pgarr_list, list) { +cr_pgarr_release_pages (pgarr); + pgarr->nr_used =0 ; + } +} + +/* +* Checkpoint is outside the context of the checkpointee, so one cannot +* simply read pages from user-space. Instead, we scan the address space +* of the target to cherry-pick pages of interest. Selected pages are +* enlisted in a page-array chain (attached to the checkpoint context). +* To save their contents, each page is mapped to kernel memory and then +* dumped to the file descriptor. +*/ + + +/** +* cr_private_follow_page - return page pointer for dirty pages +* @vma - target vma +* @addr - page address +* +* Looks up the page that correspond to the address in the vma, and +* returns the page if it was modified (and grabs a reference to it), +* or otherwise returns NULL (or error). +* +* This function should _only_ called for private vma's. +*/ +static struct page * +cr_private_follow_page (struct vm_area_struct *vma,unsigned long addr) +{ +struct page *page; + +BUG_ON (vma->vm_flags & (VM_SHARED |VM_MAYSHARE )); + +/* +* simplified version of get_user_pages(): already have vma, +* only need FOLL_ANON, and (for now) ignore fault stats. +* +* follow_page() will return NULL if the page is not present +* (swapped), ZERO_PAGE(0) if the pte wasn't allocated, and +* the actual page pointer otherwise. +* +* FIXME: consolidate with get_user_pages() +*/ + +cond_resched (); +while (!(page =follow_page (vma, addr,FOLL_ANON |FOLL_GET ))) { +int ret; + +/* the page is swapped out - bring it in (optimize ?) */ + ret =handle_mm_fault (vma->vm_mm, vma, addr,0 ); +if (ret &VM_FAULT_ERROR ) { +if (ret &VM_FAULT_OOM ) +return ERR_PTR (-ENOMEM ); +else if (ret &VM_FAULT_SIGBUS ) +return ERR_PTR (-EFAULT ); +else +BUG (); +break ; + } +cond_resched (); + } + +if (IS_ERR (page)) +return page; + +/* +* We only care about dirty pages: either non-zero page, or +* file-backed (copy-on-write) that were touched. For the latter, +* the page_mapping() will be unset because it will no longer be +* mapped to the original file after having been modified. +*/ +if (page ==ZERO_PAGE (0 )) { +/* this is the zero page: ignore */ +page_cache_release (page); + page =NULL ; + }else if (vma->vm_file && (page_mapping (page) !=NULL )) { +/* file backed clean cow: ignore */ +page_cache_release (page); + page =NULL ; + } + +return page; +} + +/** +* cr_private_vma_fill_pgarr - fill a page-array with addr/page tuples +* @ctx - checkpoint context +* @pgarr - page-array to fill +* @vma - vma to scan +* @start - start address (updated) +* +* Returns the number of pages collected +*/ +static int +cr_private_vma_fill_pgarr (struct cr_ctx *ctx,struct cr_pgarr *pgarr, +struct vm_area_struct *vma,unsigned long *start) +{ +unsigned long end = vma->vm_end; +unsigned long addr = *start; +int orig_used = pgarr->nr_used; + +/* this function is only for private memory (anon or file-mapped) */ +BUG_ON (vma->vm_flags & (VM_SHARED |VM_MAYSHARE )); + +while (addr < end) { +struct page *page; + + page =cr_private_follow_page (vma, addr); +if (IS_ERR (page)) +return PTR_ERR (page); + +if (page) { + pgarr->pages[pgarr->nr_used] = page; + pgarr->vaddrs[pgarr->nr_used] = addr; + pgarr->nr_used++; + } + + addr +=PAGE_SIZE ; + +if (cr_pgarr_is_full (pgarr)) +break ; + } + + *start = addr; +return pgarr->nr_used - orig_used;
checkpoint/ckpt_mem.c line 272
Quoted 10 lines
checkpoint/ckpt_mem.c new file +10
-0+} + +/* dump contents of a pages: use kmap_atomic() to avoid TLB flush */ +static int cr_page_write (struct cr_ctx *ctx,struct page *page,char *buf) +{ +void *ptr; + + ptr =kmap_atomic (page,KM_USER1 ); +memcpy (buf, ptr,PAGE_SIZE ); +kunmap_atomic (page,KM_USER1 );
Shouldn't this be changed to kunmap_atomic(ptr, KM_USER1); It fixes a BUG_ON() I fall in when running Oren's example code if CONFIG_HIGHMEM is set. This occurs since 2nd call to cr_page_write():
Oct 16 17:41:35 akt kernel: kernel BUG at /home/lkernel/containers/lxc/linux-2.6.27-lxc2-cr/arch/x86/mm/highmem_32.c:87! Oct 16 17:41:35 akt kernel: invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Oct 16 17:41:35 akt kernel: Modules linked in: Oct 16 17:41:35 akt kernel: Oct 16 17:41:35 akt kernel: Pid: 4117, comm: ckpt Not tainted
(2.6.27-lxc2-cr #3)
Regards,
Nadia
Quoted 392 lines
checkpoint/ckpt_mem.c new file +228
-0+ +return cr_kwrite (ctx, buf,PAGE_SIZE ); +} + +/** +* cr_vma_dump_pages - dump pages listed in the ctx page-array chain +* @ctx - checkpoint context +* @total - total number of pages +* +* First dump all virtual addresses, followed by the contents of all pages +*/ +static int cr_vma_dump_pages (struct cr_ctx *ctx,int total) +{ +struct cr_pgarr *pgarr; +char *buf; +int i, ret =0 ; + +if (!total) +return 0 ; + +list_for_each_entry_reverse (pgarr, &ctx->pgarr_list, list) { + ret =cr_kwrite (ctx, pgarr->vaddrs, + pgarr->nr_used *sizeof (*pgarr->vaddrs)); +if (ret <0 ) +return ret; + } + + buf =kmalloc (PAGE_SIZE ,GFP_KERNEL ); +if (!buf) +return -ENOMEM ; + +list_for_each_entry_reverse (pgarr, &ctx->pgarr_list, list) { +for (i =0 ; i < pgarr->nr_used; i++) { + ret =cr_page_write (ctx, pgarr->pages[i], buf); +if (ret <0 ) + goto out; + } + } + + out: +kfree (buf); +return ret; +} + +/** +* cr_write_private_vma_contents - dump contents of a VMA with private memory +* @ctx - checkpoint context +* @vma - vma to scan +* +* Collect lists of pages that needs to be dumped, and corresponding +* virtual addresses into ctx->pgarr_list page-array chain. Then dump +* the addresses, followed by the page contents. +*/ +static int +cr_write_private_vma_contents (struct cr_ctx *ctx,struct vm_area_struct *vma) +{ +struct cr_hdr h; +struct cr_hdr_pgarr *hh; +unsigned long addr = vma->vm_start; +struct cr_pgarr *pgarr; +unsigned long cnt =0 ; +int ret; + +/* +* Work iteratively, collecting and dumping at most CR_PGARR_CHUNK +* in each round. Each iterations is divided into two steps: +* +* (1) scan: scan through the PTEs of the vma to collect the pages +* to dump (later we'll also make them COW), while keeping a list +* of pages and their corresponding addresses on ctx->pgarr_list. +* +* (2) dump: write out a header specifying how many pages, followed +* by the addresses of all pages in ctx->pgarr_list, followed by +* the actual contents of all pages. (Then, release the references +* to the pages and reset the page-array chain). +* +* (This split makes the logic simpler by first counting the pages +* that need saving. More importantly, it allows for a future +* optimization that will reduce application downtime by deferring +* the actual write-out of the data to after the application is +* allowed to resume execution). +* +* After dumpting the entire contents, conclude with a header that +* specifies 0 pages to mark the end of the contents. +*/ + + h.type =CR_HDR_PGARR ; + h.len =sizeof (*hh); + h.parent =0 ; + +while (addr < vma->vm_end) { + pgarr =cr_pgarr_current (ctx); +if (!pgarr) +return -ENOMEM ; + ret =cr_private_vma_fill_pgarr (ctx, pgarr, vma, &addr); +if (ret <0 ) +return ret; + cnt += ret; + +/* did we complete a chunk, or is this the last chunk ? */ +if (cnt >=CR_PGARR_CHUNK || (cnt && addr == vma->vm_end)) { + hh =cr_hbuf_get (ctx,sizeof (*hh)); + hh->nr_pages = cnt; + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) +return ret; + + ret =cr_vma_dump_pages (ctx, cnt); +if (ret <0 ) +return ret; + +cr_pgarr_reset_all (ctx); + } + } + +/* mark end of contents with header saying "0" pages */ + hh =cr_hbuf_get (ctx,sizeof (*hh)); + hh->nr_pages =0 ; + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); + +return ret; +} + +static int cr_write_vma (struct cr_ctx *ctx,struct vm_area_struct *vma) +{ +struct cr_hdr h; +struct cr_hdr_vma *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int vma_type, ret; + + h.type =CR_HDR_VMA ; + h.len =sizeof (*hh); + h.parent =0 ; + + hh->vm_start = vma->vm_start; + hh->vm_end = vma->vm_end; + hh->vm_page_prot = vma->vm_page_prot.pgprot; + hh->vm_flags = vma->vm_flags; + hh->vm_pgoff = vma->vm_pgoff; + +if (vma->vm_flags & (VM_SHARED |VM_IO |VM_HUGETLB |VM_NONLINEAR )) { +pr_warning ("CR: unsupported VMA %#lx\n" , vma->vm_flags); +cr_hbuf_put (ctx,sizeof (*hh)); +return -ENOSYS ; + } + +/* by default assume anon memory */ + vma_type =CR_VMA_ANON ; + +/* +* if there is a backing file, assume private-mapped +* (FIXME: check if the file is unlinked) +*/ +if (vma->vm_file) + vma_type =CR_VMA_FILE ; + + hh->vma_type = vma_type; + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) +return ret; + +/* save the file name, if relevant */ +if (vma->vm_file) { + ret =cr_write_fname (ctx, &vma->vm_file->f_path, ctx->vfsroot); +if (ret <0 ) +return ret; + } + +return cr_write_private_vma_contents (ctx, vma); +} + +int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_mm *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct mm_struct *mm; +struct vm_area_struct *vma; +int objref, ret; + + h.type =CR_HDR_MM ; + h.len =sizeof (*hh); + h.parent =task_pid_vnr (t); + + mm =get_task_mm (t); + + objref =0 ;/* will be meaningful with multiple processes */ + hh->objref = objref; + +down_read (&mm->mmap_sem); + + hh->start_code = mm->start_code; + hh->end_code = mm->end_code; + hh->start_data = mm->start_data; + hh->end_data = mm->end_data; + hh->start_brk = mm->start_brk; + hh->brk = mm->brk; + hh->start_stack = mm->start_stack; + hh->arg_start = mm->arg_start; + hh->arg_end = mm->arg_end; + hh->env_start = mm->env_start; + hh->env_end = mm->env_end; + + hh->map_count = mm->map_count; + +/* FIX: need also mm->flags */ + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) + goto out; + +/* write the vma's */ +for (vma = mm->mmap; vma; vma = vma->vm_next) { + ret =cr_write_vma (ctx, vma); +if (ret <0 ) + goto out; + } + + ret =cr_write_mm_context (ctx, mm, objref); + + out: +up_read (&mm->mmap_sem); +mmput (mm); +return ret; +}diff -puN checkpoint/Makefile~v6_PATCH_4_9_Dump_memory_address_space checkpoint/Makefile
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_4_9_Dump_memory_address_space +2
-1@@ -2,4 +2,5 @@ # Makefile for linux checkpoint/restart. # -obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ + ckpt_mem.odiff -puN checkpoint/sys.c~v6_PATCH_4_9_Dump_memory_address_space
checkpoint/sys.ccheckpoint/sys.c renamed from checkpoint/sys.c~v6_PATCH_4_9_Dump_memory_address_space +16
-0@@ -16,6 +16,8 @@#include <linux/capability.h> #include <linux/checkpoint.h> +#include "checkpoint_mem.h" +/* * helpers to write/read to/from the image file descriptor * @@ -161,6 +163,11 @@ void cr_ctx_free(struct cr_ctx *ctx)kfree (ctx->hbuf); +if (ctx->vfsroot) +path_put (ctx->vfsroot); + +cr_pgarr_free (ctx); +kfree (ctx); }@@ -184,6 +191,15 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, ireturn ERR_PTR (-ENOMEM ); } +/* +* assume checkpointer is in container's root vfs +* FIXME: this works for now, but will change with real containers +*/ + ctx->vfsroot = ¤t->fs->root; +path_get (ctx->vfsroot); + +INIT_LIST_HEAD (&ctx->pgarr_list); + ctx->pid = pid; ctx->flags = flags;diff -puN
include/asm-x86/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_spaceinclude/asm-x86/checkpoint_hdr.hinclude/asm-x86/checkpoint_hdr.h renamed from include/asm-x86/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_space +5
-0@@ -69,4 +69,9 @@ struct cr_hdr_cpu { } __attribute__((aligned(8))); +struct cr_hdr_mm_context { +__s16 ldt_entry_size; +__s16 nldt; +} __attribute__((aligned (8 ))); +#endif /* __ASM_X86_CKPT_HDR__H */ diff -puN
include/linux/checkpoint.h~v6_PATCH_4_9_Dump_memory_address_spaceinclude/linux/checkpoint.hinclude/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_4_9_Dump_memory_address_space +12
-0@@ -10,6 +10,9 @@* distribution for more details. */ +#include <linux/path.h> +#include <linux/fs.h> +#define CR_VERSION 1struct cr_ctx {@@ -24,6 +27,10 @@ struct cr_ctx {void *hbuf;/* temporary buffer for headers */ int hpos;/* position in headers buffer */ + +struct list_head pgarr_list;/* page array to dump VMA contents */ + +struct path *vfsroot;/* container root (FIXME) */ };/* cr_ctx: flags */ @@ -42,11 +49,16 @@ struct cr_hdr;extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf);extern int cr_write_string (struct cr_ctx *ctx,char *str,int len); +extern int cr_write_fname (struct cr_ctx *ctx, +struct path *path,struct path *root);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_string (struct cr_ctx *ctx,void *str,int len); +extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t); +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);diff -puN
include/linux/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_spaceinclude/linux/checkpoint_hdr.hinclude/linux/checkpoint_hdr.h renamed from include/linux/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_space +32
-0@@ -32,6 +32,7 @@ struct cr_hdr {enum {CR_HDR_HEAD =1 ,CR_HDR_STRING , +CR_HDR_FNAME ,CR_HDR_TASK =101 ,CR_HDR_THREAD ,@@ -39,6 +40,7 @@ enum {CR_HDR_MM =201 ,CR_HDR_VMA , +CR_HDR_PGARR ,CR_HDR_MM_CONTEXT ,CR_HDR_TAIL =5001 @@ -73,4 +75,34 @@ struct cr_hdr_task {__s32 task_comm_len; } __attribute__((aligned(8))); +struct cr_hdr_mm { +__u32 objref;/* identifier for shared objects */ +__u32 map_count; + +__u64 start_code, end_code, start_data, end_data; +__u64 start_brk, brk, start_stack; +__u64 arg_start, arg_end, env_start, env_end; +} __attribute__((aligned (8 ))); + +/* vma subtypes */ +enum vm_type { +CR_VMA_ANON =1 , +CR_VMA_FILE +}; + +struct cr_hdr_vma { +__u32 vma_type; +__u32 _padding; + +__u64 vm_start; +__u64 vm_end; +__u64 vm_page_prot; +__u64 vm_flags; +__u64 vm_pgoff; +} __attribute__((aligned (8 ))); + +struct cr_hdr_pgarr { +__u64 nr_pages;/* number of pages to saved */ +} __attribute__((aligned (8 ))); +#endif /* _CHECKPOINT_CKPT_HDR_H_ */ _
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linux-foundation.org/mailman/listinfo/containers
Signature · 1 line
Nadia Derbey <Nadia.Derbey-6ktuUTfB/[email protected]>
PATCH 1/9 Create syscalls: sys_checkpoint, sys_restart
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 descriptor.
The syscalls 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.
---
linux-2.6.git-dave/arch/x86/kernel/syscall_table_32.S | 2 linux-2.6.git-dave/checkpoint/Kconfig | 11 ++++ linux-2.6.git-dave/checkpoint/Makefile | 5 ++ linux-2.6.git-dave/checkpoint/sys.c | 41 ++++++++++++++++++ linux-2.6.git-dave/include/asm-x86/unistd_32.h | 2 linux-2.6.git-dave/include/linux/syscalls.h | 2 linux-2.6.git-dave/init/Kconfig | 2 linux-2.6.git-dave/kernel/sys_ni.c | 4 + 8 files changed, 69 insertions(+)
arch/x86/kernel/syscall_table_32.S renamed from arch/x86/kernel/syscall_table_32.S~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +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
checkpoint/Kconfig new file +11 -0
@@ -0,0 +1,11 @@ +config CHECKPOINT_RESTART + prompt "Enable checkpoint/restart (EXPERIMENTAL)" + def_bool n + depends on X86_32 && EXPERIMENTAL + help + Application checkpoint/restart is the ability to save the + state of a running application so that it can later resume + its execution from the time at which it was checkpointed. + + Turning this option on will enable checkpoint and restart + functionality in the kernel.
checkpoint/Makefile new file +5 -0
@@ -0,0 +1,5 @@ +# +# Makefile for linux checkpoint/restart. +# + +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o
checkpoint/sys.c new file +41 -0
41 lines not on this page · raw message
include/asm-x86/unistd_32.h renamed from include/asm-x86/unistd_32.h~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +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~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +2 -0
@@ -622,6 +622,8 @@ asmlinkage long sys_timerfd_gettime(intasmlinkage long sys_eventfd (unsigned int count);asmlinkage long sys_eventfd2 (unsigned int count,int flags);asmlinkage long sys_fallocate (int fd,int mode,loff_t offset,loff_t len); +asmlinkage long sys_checkpoint (pid_t pid,int fd,unsigned long flags); +asmlinkage long sys_restart (int crid,int fd,unsigned long flags);int kernel_execve (const char *filename,char *const argv[],char *const envp[]);
init/Kconfig renamed from init/Kconfig~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +2 -0
@@ -779,6 +779,8 @@ config MARKERS source "arch/Kconfig" +source "checkpoint/Kconfig" + endmenu # General setup config HAVE_GENERIC_DMA_COHERENT
kernel/sys_ni.c renamed from kernel/sys_ni.c~v6_PATCH_1_9_Create_syscalls-_sys_checkpoint_sys_restart +4 -0
@@ -169,3 +169,7 @@ cond_syscall(compat_sys_timerfd_settime)cond_syscall (compat_sys_timerfd_gettime);cond_syscall (sys_eventfd);cond_syscall (sys_eventfd2); + +/* checkpoint/restart */ +cond_syscall (sys_checkpoint); +cond_syscall (sys_restart);
_
PATCH 5/9 Restore memory address space
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Restoring the memory address space begins with nuking the existing one of the current process, and then reading the VMA state and contents. Call do_mmap_pgoffset() for each VMA and then read in the data.
---
linux-2.6.git-dave/arch/x86/mm/restart.c | 64 +++ linux-2.6.git-dave/checkpoint/Makefile | 2 linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 2 linux-2.6.git-dave/checkpoint/checkpoint_mem.h | 5 linux-2.6.git-dave/checkpoint/restart.c | 42 ++ linux-2.6.git-dave/checkpoint/rstr_mem.c | 384 ++++++++++++++++++++ linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 4 linux-2.6.git-dave/include/linux/checkpoint.h | 3 8 files changed, 503 insertions(+), 3 deletions(-)
arch/x86/mm/restart.c renamed from arch/x86/mm/restart.c~v6_PATCH_5_9_Restore_memory_address_space +62 -2
@@ -53,8 +53,10 @@ int cr_read_thread(struct cr_ctx *ctx) size =sizeof (*desc) *GDT_ENTRY_TLS_ENTRIES ; desc =kmalloc (size,GFP_KERNEL ); -if (!desc) -return -ENOMEM ; +if (!desc) { + ret = -ENOMEM ; + goto out; + } ret =cr_kread (ctx, desc, size);if (ret >=0 ) {
@@ -189,3 +191,61 @@ int cr_read_cpu(struct cr_ctx *ctx)cr_hbuf_put (ctx,sizeof (*hh));return ret; } + +int cr_read_mm_context (struct cr_ctx *ctx,struct mm_struct *mm,int parent) +{ +struct cr_hdr_mm_context *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int n, rparent, ret = -EINVAL ; + + rparent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_MM_CONTEXT ); +cr_debug ("parent %d rparent %d nldt %d\n" , parent, rparent, hh->nldt); +if (rparent <0 ) { + ret = rparent; + goto out; + } +if (rparent != parent) + goto out; + +if (hh->nldt <0 || hh->ldt_entry_size !=LDT_ENTRY_SIZE ) + goto out; + +/* +* to utilize the syscall modify_ldt() we first convert the data +* in the checkpoint image from 'struct desc_struct' to 'struct +* user_desc' with reverse logic of include/asm/desc.h:fill_ldt() +*/ + +for (n =0 ; n < hh->nldt; n++) { +struct user_desc info; +struct desc_struct desc; +mm_segment_t old_fs; + + ret =cr_kread (ctx, &desc,LDT_ENTRY_SIZE ); +if (ret <0 ) + goto out; + + info.entry_number = n; + info.base_addr = desc.base0 | (desc.base1 <<16 ); + info.limit = desc.limit0; + info.seg_32bit = desc.d; + info.contents = desc.type >>2 ; + info.read_exec_only = (desc.type >>1 ) ^1 ; + info.limit_in_pages = desc.g; + info.seg_not_present = desc.p ^1 ; + info.useable = desc.avl; + + old_fs =get_fs (); +set_fs (get_ds ()); + ret =sys_modify_ldt (1 , (struct user_desc __user *) &info, +sizeof (info)); +set_fs (old_fs); + +if (ret <0 ) + goto out; + } + + ret =0 ; + out: +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +}
checkpoint/checkpoint_arch.h renamed from checkpoint/checkpoint_arch.h~v6_PATCH_5_9_Restore_memory_address_space +2 -0
@@ -7,3 +7,5 @@ extern int cr_write_mm_context(struct crextern int cr_read_thread (struct cr_ctx *ctx);extern int cr_read_cpu (struct cr_ctx *ctx); +extern int cr_read_mm_context (struct cr_ctx *ctx, +struct mm_struct *mm,int parent);
checkpoint/checkpoint_mem.h renamed from checkpoint/checkpoint_mem.h~v6_PATCH_5_9_Restore_memory_address_space +5 -0
@@ -38,4 +38,9 @@ static inline int cr_pgarr_is_full(struc return (pgarr->nr_used == CR_PGARR_TOTAL); } +static inline int cr_pgarr_nr_free (struct cr_pgarr *pgarr) +{ +return CR_PGARR_TOTAL - pgarr->nr_used; +} +#endif /* _CHECKPOINT_CKPT_MEM_H_ */
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_5_9_Restore_memory_address_space +1 -1
@@ -3,4 +3,4 @@ # obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ - ckpt_mem.o + ckpt_mem.o rstr_mem.o
checkpoint/restart.c renamed from checkpoint/restart.c~v6_PATCH_5_9_Restore_memory_address_space +42 -0
54 lines not on this page · raw message
checkpoint/rstr_mem.c new file +384 -0
384 lines not on this page · raw message
include/asm-x86/checkpoint_hdr.h renamed from include/asm-x86/checkpoint_hdr.h~v6_PATCH_5_9_Restore_memory_address_space +4 -0
@@ -74,4 +74,8 @@ struct cr_hdr_mm_context {__s16 nldt; } __attribute__((aligned(8))); + +/* misc prototypes from kernel (not defined elsewhere) */ +asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount); +#endif /* __ASM_X86_CKPT_HDR__H */
include/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_5_9_Restore_memory_address_space +3 -0
@@ -55,6 +55,9 @@ extern int cr_write_fname(struct cr_ctxextern 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_string (struct cr_ctx *ctx,void *str,int len); +extern int cr_read_fname (struct cr_ctx *ctx,void *fname,int n); +extern struct file *cr_read_open_fname (struct cr_ctx *ctx, +int flags,int mode);extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t);extern int cr_read_mm (struct cr_ctx *ctx);
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 5/9] Restore memory address space
Quoted 256 lines · Dave Hansen
From: Oren Laadan <[email protected]>
Restoring the memory address space begins with nuking the existing one of the current process, and then reading the VMA state and contents. Call
do_mmap_pgoffset()for each VMA and then read in the data.Signed-off-by Oren Laadan <[email protected]>Acked-by Serge Hallyn <[email protected]>Signed-off-by Dave Hansen <[email protected]>---
linux-2.6.git-dave/arch/x86/mm/restart.c | 64 +++ linux-2.6.git-dave/checkpoint/Makefile | 2 linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 2 linux-2.6.git-dave/checkpoint/checkpoint_mem.h | 5 linux-2.6.git-dave/checkpoint/restart.c | 42 ++ linux-2.6.git-dave/checkpoint/rstr_mem.c | 384 ++++++++++++++++++++ linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 4 linux-2.6.git-dave/include/linux/checkpoint.h | 3 8 files changed, 503 insertions(+), 3 deletions(-)diff -puN
arch/x86/mm/restart.c~v6_PATCH_5_9_Restore_memory_address_spacearch/x86/mm/restart.carch/x86/mm/restart.c renamed from arch/x86/mm/restart.c~v6_PATCH_5_9_Restore_memory_address_space +62
-2@@ -53,8 +53,10 @@ int cr_read_thread(struct cr_ctx *ctx) size =sizeof (*desc) *GDT_ENTRY_TLS_ENTRIES ; desc =kmalloc (size,GFP_KERNEL ); -if (!desc) -return -ENOMEM ; +if (!desc) { + ret = -ENOMEM ; + goto out; + } ret =cr_kread (ctx, desc, size);if (ret >=0 ) {@@ -189,3 +191,61 @@ int cr_read_cpu(struct cr_ctx *ctx)cr_hbuf_put (ctx,sizeof (*hh));return ret; } + +int cr_read_mm_context (struct cr_ctx *ctx,struct mm_struct *mm,int parent) +{ +struct cr_hdr_mm_context *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int n, rparent, ret = -EINVAL ; + + rparent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_MM_CONTEXT ); +cr_debug ("parent %d rparent %d nldt %d\n" , parent, rparent, hh->nldt); +if (rparent <0 ) { + ret = rparent; + goto out; + } +if (rparent != parent) + goto out; + +if (hh->nldt <0 || hh->ldt_entry_size !=LDT_ENTRY_SIZE ) + goto out; + +/* +* to utilize the syscall modify_ldt() we first convert the data +* in the checkpoint image from 'struct desc_struct' to 'struct +* user_desc' with reverse logic of include/asm/desc.h:fill_ldt() +*/ + +for (n =0 ; n < hh->nldt; n++) { +struct user_desc info; +struct desc_struct desc; +mm_segment_t old_fs; + + ret =cr_kread (ctx, &desc,LDT_ENTRY_SIZE ); +if (ret <0 ) + goto out; + + info.entry_number = n; + info.base_addr = desc.base0 | (desc.base1 <<16 ); + info.limit = desc.limit0; + info.seg_32bit = desc.d; + info.contents = desc.type >>2 ; + info.read_exec_only = (desc.type >>1 ) ^1 ; + info.limit_in_pages = desc.g; + info.seg_not_present = desc.p ^1 ; + info.useable = desc.avl; + + old_fs =get_fs (); +set_fs (get_ds ()); + ret =sys_modify_ldt (1 , (struct user_desc __user *) &info, +sizeof (info)); +set_fs (old_fs); + +if (ret <0 ) + goto out; + } + + ret =0 ; + out: +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +}diff -puN checkpoint/checkpoint_arch.h~v6_PATCH_5_9_Restore_memory_address_space
checkpoint/checkpoint_arch.hcheckpoint/checkpoint_arch.h renamed from checkpoint/checkpoint_arch.h~v6_PATCH_5_9_Restore_memory_address_space +2
-0@@ -7,3 +7,5 @@ extern int cr_write_mm_context(struct crextern int cr_read_thread (struct cr_ctx *ctx);extern int cr_read_cpu (struct cr_ctx *ctx); +extern int cr_read_mm_context (struct cr_ctx *ctx, +struct mm_struct *mm,int parent);diff -puN checkpoint/checkpoint_mem.h~v6_PATCH_5_9_Restore_memory_address_space
checkpoint/checkpoint_mem.hcheckpoint/checkpoint_mem.h renamed from checkpoint/checkpoint_mem.h~v6_PATCH_5_9_Restore_memory_address_space +5
-0@@ -38,4 +38,9 @@ static inline int cr_pgarr_is_full(struc return (pgarr->nr_used == CR_PGARR_TOTAL); } +static inline int cr_pgarr_nr_free (struct cr_pgarr *pgarr) +{ +return CR_PGARR_TOTAL - pgarr->nr_used; +} +#endif /* _CHECKPOINT_CKPT_MEM_H_ */ diff -puN checkpoint/Makefile~v6_PATCH_5_9_Restore_memory_address_space checkpoint/Makefile
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_5_9_Restore_memory_address_space +1
-1@@ -3,4 +3,4 @@ # obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ - ckpt_mem.o + ckpt_mem.o rstr_mem.odiff -puN checkpoint/restart.c~v6_PATCH_5_9_Restore_memory_address_space
checkpoint/restart.ccheckpoint/restart.c renamed from checkpoint/restart.c~v6_PATCH_5_9_Restore_memory_address_space +42
-0@@ -78,6 +78,44 @@ int cr_read_string(struct cr_ctx *ctx, vreturn cr_read_obj_type (ctx, str, len,CR_HDR_STRING ); } +/** +* cr_read_fname - read a file name +* @ctx: checkpoint context +* @fname: buffer +* @n: buffer length +*/ +int cr_read_fname (struct cr_ctx *ctx,void *fname,int flen) +{ +return cr_read_obj_type (ctx, fname, flen,CR_HDR_FNAME ); +} + +/** +* cr_read_open_fname - read a file name and open a file +* @ctx: checkpoint context +* @flags: file flags +* @mode: file mode +*/ +struct file *cr_read_open_fname (struct cr_ctx *ctx,int flags,int mode) +{ +struct file *file; +char *fname; +int ret; + + fname =kmalloc (PATH_MAX ,GFP_KERNEL ); +if (!fname) +return ERR_PTR (-ENOMEM ); + + ret =cr_read_fname (ctx, fname,PATH_MAX ); +cr_debug ("fname '%s' flags %#x mode %#x\n" , fname, flags, mode); +if (ret >=0 ) + file =filp_open (fname, flags, mode); +else + file =ERR_PTR (ret); + +kfree (fname); +return file; +} +/* read the checkpoint header */ static int cr_read_head (struct cr_ctx *ctx) {@@ -177,6 +215,10 @@ static int cr_read_task(struct cr_ctx *ccr_debug ("task_struct: ret %d\n" , ret);if (ret <0 ) goto out; + ret =cr_read_mm (ctx); +cr_debug ("memory: ret %d\n" , ret); +if (ret <0 ) + goto out; ret =cr_read_thread (ctx);cr_debug ("thread: ret %d\n" , ret);if (ret <0 )diff -puN
/dev/nullcheckpoint/rstr_mem.ccheckpoint/rstr_mem.c new file +63
-0@@ -0,0 +1,384 @@ +/* +* Restart memory contents +* +* 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/kernel.h> +#include <linux/sched.h> +#include <linux/fcntl.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/pagemap.h> +#include <linux/mm_types.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/err.h> +#include <linux/checkpoint.h> +#include <linux/checkpoint_hdr.h> + +#include "checkpoint_arch.h" +#include "checkpoint_mem.h" + +/* +* Unlike checkpoint, restart is executed in the context of each restarting +* process: vma regions are restored via a call to mmap(), and the data is +* read into the address space of the current process. +*/ + + +/** +* cr_read_pages_vaddrs - read addresses of pages to page-array chain +* @ctx - restart context +* @nr_pages - number of address to read +*/ +static int cr_read_pages_vaddrs (struct cr_ctx *ctx,unsigned long nr_pages) +{ +struct cr_pgarr *pgarr; +unsigned long *vaddrp; +int nr, ret; + +while (nr_pages) { + pgarr =cr_pgarr_current (ctx); +if (!pgarr) +return -ENOMEM ; + nr =cr_pgarr_nr_free (pgarr); +if (nr > nr_pages) + nr = nr_pages; + vaddrp = &pgarr->vaddrs[pgarr->nr_used]; + ret =cr_kread (ctx, vaddrp, nr *sizeof (unsigned long )); +if (ret <0 ) +return ret; + pgarr->nr_used += nr; + nr_pages -= nr; + } +return 0 ; +} + +static int cr_page_read (struct cr_ctx *ctx,struct page *page,char *buf) +{
checkpoint/rstr_mem.c line 73
Quoted 10 lines
checkpoint/rstr_mem.c new file +10
-0+void *ptr; +int ret; + + ret =cr_kread (ctx, buf,PAGE_SIZE ); +if (ret <0 ) +return ret; + + ptr =kmap_atomic (page,KM_USER1 ); +memcpy (ptr, buf,PAGE_SIZE ); +kunmap_atomic (page,KM_USER1 );
Here too, I think this should be changed tokunmap_atomic(ptr, KM_USER1);
Regards,
Nadia
Quoted 342 lines
checkpoint/rstr_mem.c new file +311
-0+ +return 0 ; +} + +/** +* cr_read_pages_contents - read in data of pages in page-array chain +* @ctx - restart context +*/ +static int cr_read_pages_contents (struct cr_ctx *ctx) +{ +struct mm_struct *mm = current->mm; +struct cr_pgarr *pgarr; +unsigned long *vaddrs; +char *buf; +int i, ret =0 ; + + buf =kmalloc (PAGE_SIZE ,GFP_KERNEL ); +if (!buf) +return -ENOMEM ; + +down_read (&mm->mmap_sem); +list_for_each_entry_reverse (pgarr, &ctx->pgarr_list, list) { + vaddrs = pgarr->vaddrs; +for (i =0 ; i < pgarr->nr_used; i++) { +struct page *page; + + ret =get_user_pages (current, mm, vaddrs[i], +1 ,1 ,1 , &page,NULL ); +if (ret <0 ) + goto out; + + ret =cr_page_read (ctx, page, buf); +page_cache_release (page); + +if (ret <0 ) + goto out; + } + } + + out: +up_read (&mm->mmap_sem); +kfree (buf); +return 0 ; +} + +/** +* cr_read_private_vma_contents - restore contents of a VMA with private memory +* @ctx - restart context +* +* Reads a header that specifies how many pages will follow, then reads +* a list of virtual addresses into ctx->pgarr_list page-array chain, +* followed by the actual contents of the corresponding pages. Iterates +* these steps until reaching a header specifying "0" pages, which marks +* the end of the contents. +*/ +static int cr_read_private_vma_contents (struct cr_ctx *ctx) +{ +struct cr_hdr_pgarr *hh; +unsigned long nr_pages; +int parent, ret =0 ; + +while (1 ) { + hh =cr_hbuf_get (ctx,sizeof (*hh)); + parent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_PGARR ); +if (parent !=0 ) { +if (parent <0 ) + ret = parent; +else + ret = -EINVAL ; +cr_hbuf_put (ctx,sizeof (*hh)); +break ; + } + +cr_debug ("nr_pages %ld\n" , (unsigned long ) hh->nr_pages); + + nr_pages = hh->nr_pages; +cr_hbuf_put (ctx,sizeof (*hh)); + +if (!nr_pages) +break ; + + ret =cr_read_pages_vaddrs (ctx, nr_pages); +if (ret <0 ) +break ; + ret =cr_read_pages_contents (ctx); +if (ret <0 ) +break ; +cr_pgarr_reset_all (ctx); + } + +return ret; +} + +/** +* cr_calc_map_prot_bits - convert vm_flags to mmap protection +* orig_vm_flags: source vm_flags +*/ +static unsigned long cr_calc_map_prot_bits (unsigned long orig_vm_flags) +{ +unsigned long vm_prot =0 ; + +if (orig_vm_flags &VM_READ ) + vm_prot |=PROT_READ ; +if (orig_vm_flags &VM_WRITE ) + vm_prot |=PROT_WRITE ; +if (orig_vm_flags &VM_EXEC ) + vm_prot |=PROT_EXEC ; +if (orig_vm_flags &PROT_SEM )/* only (?) with IPC-SHM */ + vm_prot |=PROT_SEM ; + +return vm_prot; +} + +/** +* cr_calc_map_flags_bits - convert vm_flags to mmap flags +* orig_vm_flags: source vm_flags +*/ +static unsigned long cr_calc_map_flags_bits (unsigned long orig_vm_flags) +{ +unsigned long vm_flags =0 ; + + vm_flags =MAP_FIXED ; +if (orig_vm_flags &VM_GROWSDOWN ) + vm_flags |=MAP_GROWSDOWN ; +if (orig_vm_flags &VM_DENYWRITE ) + vm_flags |=MAP_DENYWRITE ; +if (orig_vm_flags &VM_EXECUTABLE ) + vm_flags |=MAP_EXECUTABLE ; +if (orig_vm_flags &VM_MAYSHARE ) + vm_flags |=MAP_SHARED ; +else + vm_flags |=MAP_PRIVATE ; + +return vm_flags; +} + +static int cr_read_vma (struct cr_ctx *ctx,struct mm_struct *mm) +{ +struct cr_hdr_vma *hh =cr_hbuf_get (ctx,sizeof (*hh)); +unsigned long vm_size, vm_start, vm_flags, vm_prot, vm_pgoff; +unsigned long addr; +struct file *file =NULL ; +int parent, ret = -EINVAL ; + + parent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_VMA ); +if (parent <0 ) { + ret = parent; + goto err; + }else if (parent !=0 ) + goto err; + +cr_debug ("vma %#lx-%#lx type %d\n" , (unsigned long ) hh->vm_start, + (unsigned long ) hh->vm_end, (int ) hh->vma_type); + +if (hh->vm_end < hh->vm_start) + goto err; + + vm_start = hh->vm_start; + vm_pgoff = hh->vm_pgoff; + vm_size = hh->vm_end - hh->vm_start; + vm_prot =cr_calc_map_prot_bits (hh->vm_flags); + vm_flags =cr_calc_map_flags_bits (hh->vm_flags); + +switch (hh->vma_type) { + +case CR_VMA_ANON :/* anonymous private mapping */ +if (vm_flags &VM_SHARED ) + goto err; +/* +* vm_pgoff for anonymous mapping is the "global" page +* offset (namely from addr 0x0), so we force a zero +*/ + vm_pgoff =0 ; +break ; + +case CR_VMA_FILE :/* private mapping from a file */ +if (vm_flags &VM_SHARED ) + goto err; +/* +* for private mapping using 'read-only' is sufficient +*/ + file =cr_read_open_fname (ctx,O_RDONLY ,0 ); +if (IS_ERR (file)) { + ret =PTR_ERR (file); + goto err; + } +break ; + +default : + goto err; + + } + +cr_hbuf_put (ctx,sizeof (*hh)); + +down_write (&mm->mmap_sem); + addr =do_mmap_pgoff (file, vm_start, vm_size, + vm_prot, vm_flags, vm_pgoff); +up_write (&mm->mmap_sem); +cr_debug ("size %#lx prot %#lx flag %#lx pgoff %#lx => %#lx\n" , + vm_size, vm_prot, vm_flags, vm_pgoff, addr); + +/* the file (if opened) is now referenced by the vma */ +if (file) +filp_close (file,NULL ); + +if (IS_ERR ((void *) addr)) +return PTR_ERR ((void *) addr); + +/* +* CR_VMA_ANON: read in memory as is +* CR_VMA_FILE: read in memory as is +* (more to follow ...) +*/ + +switch (hh->vma_type) { +case CR_VMA_ANON : +case CR_VMA_FILE : +/* standard case: read the data into the memory */ + ret =cr_read_private_vma_contents (ctx); +break ; + } + +if (ret <0 ) +return ret; + +cr_debug ("vma retval %d\n" , ret); +return 0 ; + + err: +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +} + +static int cr_destroy_mm (struct mm_struct *mm) +{ +struct vm_area_struct *vmnext = mm->mmap; +struct vm_area_struct *vma; +int ret; + +while (vmnext) { + vma = vmnext; + vmnext = vmnext->vm_next; + ret =do_munmap (mm, vma->vm_start, vma->vm_end-vma->vm_start); +if (ret <0 ) { +pr_debug ("CR: restart failed do_munmap (%d)\n" , ret); +return ret; + } + } +return 0 ; +} + +int cr_read_mm (struct cr_ctx *ctx) +{ +struct cr_hdr_mm *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct mm_struct *mm; +int nr, parent, ret; + + parent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_MM ); +if (parent <0 ) { + ret = parent; + goto out; + } + + ret = -EINVAL ; +#if 0 /* activate when containers are used */ +if (parent !=task_pid_vnr (current)) + goto out; +#endif +cr_debug ("map_count %d\n" , hh->map_count); + +/* XXX need more sanity checks */ +if (hh->start_code > hh->end_code || + hh->start_data > hh->end_data || hh->map_count <0 ) + goto out; + + mm = current->mm; + +/* point of no return -- destruct current mm */ +down_write (&mm->mmap_sem); + ret =cr_destroy_mm (mm); +if (ret <0 ) { +up_write (&mm->mmap_sem); + goto out; + } + mm->start_code = hh->start_code; + mm->end_code = hh->end_code; + mm->start_data = hh->start_data; + mm->end_data = hh->end_data; + mm->start_brk = hh->start_brk; + mm->brk = hh->brk; + mm->start_stack = hh->start_stack; + mm->arg_start = hh->arg_start; + mm->arg_end = hh->arg_end; + mm->env_start = hh->env_start; + mm->env_end = hh->env_end; +up_write (&mm->mmap_sem); + +/* FIX: need also mm->flags */ + +for (nr = hh->map_count; nr; nr--) { + ret =cr_read_vma (ctx, mm); +if (ret <0 ) + goto out; + } + + ret =cr_read_mm_context (ctx, mm, hh->objref); + out: +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +}diff -puN
include/asm-x86/checkpoint_hdr.h~v6_PATCH_5_9_Restore_memory_address_spaceinclude/asm-x86/checkpoint_hdr.hinclude/asm-x86/checkpoint_hdr.h renamed from include/asm-x86/checkpoint_hdr.h~v6_PATCH_5_9_Restore_memory_address_space +4
-0@@ -74,4 +74,8 @@ struct cr_hdr_mm_context {__s16 nldt; } __attribute__((aligned(8))); + +/* misc prototypes from kernel (not defined elsewhere) */ +asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount); +#endif /* __ASM_X86_CKPT_HDR__H */ diff -puN
include/linux/checkpoint.h~v6_PATCH_5_9_Restore_memory_address_spaceinclude/linux/checkpoint.hinclude/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_5_9_Restore_memory_address_space +3
-0@@ -55,6 +55,9 @@ extern int cr_write_fname(struct cr_ctxextern 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_string (struct cr_ctx *ctx,void *str,int len); +extern int cr_read_fname (struct cr_ctx *ctx,void *fname,int n); +extern struct file *cr_read_open_fname (struct cr_ctx *ctx, +int flags,int mode);extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t);extern int cr_read_mm (struct cr_ctx *ctx);_
_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers
Signature · 7 lines
Nadia Derbey <[email protected]> -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
A message that is not in the archive (sent off-list or not yet received): 1224233070.2634.114.camel-okVqAf2pJUFftS2PfwdgCzWMkbuR3peG@public.gmane.org
Re: [PATCH 5/9] Restore memory address space
Quoted 16 lines · Nadia Derbey
checkpoint/rstr_mem.c line 73
Quoted 12 lines · Dave Hansen
checkpoint/rstr_mem.c new file +12
-0+static int cr_page_read (struct cr_ctx *ctx,struct page *page,char *buf) +{ +void *ptr; +int ret; + + ret =cr_kread (ctx, buf,PAGE_SIZE ); +if (ret <0 ) +return ret; + + ptr =kmap_atomic (page,KM_USER1 ); +memcpy (ptr, buf,PAGE_SIZE ); +kunmap_atomic (page,KM_USER1 );Here too, I think this should be changed to
kunmap_atomic(ptr, KM_USER1);
Thanks, Nadia.
These fixes will show up in the git tree shortly:
http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/daveh/linux-2.6-cr.git;a=summary
I just created it, so it may take a few moments for the gitweb script to find it.
-- Dave
Re: [PATCH 5/9] Restore memory address space
In reply to Nadia DerbeyQuoted 16 lines · Nadia Derbey
checkpoint/rstr_mem.c line 73
Quoted 12 lines · Dave Hansen
checkpoint/rstr_mem.c new file +12
-0+static int cr_page_read (struct cr_ctx *ctx,struct page *page,char *buf) +{ +void *ptr; +int ret; + + ret =cr_kread (ctx, buf,PAGE_SIZE ); +if (ret <0 ) +return ret; + + ptr =kmap_atomic (page,KM_USER1 ); +memcpy (ptr, buf,PAGE_SIZE ); +kunmap_atomic (page,KM_USER1 );Here too, I think this should be changed to
kunmap_atomic(ptr, KM_USER1);
Thanks, Nadia.
These fixes will show up in the git tree shortly:
http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/daveh/linux-2.6-cr.git;a=summary
I just created it, so it may take a few moments for the gitweb script to find it.
-- Dave
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 5/9] Restore memory address space
In reply to Nadia DerbeyNadia, please don't quote the whole diff, and then comment on just a very small part.
It's actually really hard to even _see_ your comments. I almost gave up, until I found the three lines you had written, with the 550 lines of quoted material..
Linus
Re: [PATCH 5/9] Restore memory address space
In reply to Dave HansenQuoted 256 lines · Dave Hansen
From: Oren Laadan <[email protected]>
Restoring the memory address space begins with nuking the existing one of the current process, and then reading the VMA state and contents. Call
do_mmap_pgoffset()for each VMA and then read in the data.Signed-off-by Oren Laadan <[email protected]>Signed-off-by Dave Hansen <[email protected]>---
linux-2.6.git-dave/arch/x86/mm/restart.c | 64 +++ linux-2.6.git-dave/checkpoint/Makefile | 2 linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 2 linux-2.6.git-dave/checkpoint/checkpoint_mem.h | 5 linux-2.6.git-dave/checkpoint/restart.c | 42 ++ linux-2.6.git-dave/checkpoint/rstr_mem.c | 384 ++++++++++++++++++++ linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 4 linux-2.6.git-dave/include/linux/checkpoint.h | 3 8 files changed, 503 insertions(+), 3 deletions(-)diff -puN
arch/x86/mm/restart.c~v6_PATCH_5_9_Restore_memory_address_spacearch/x86/mm/restart.carch/x86/mm/restart.c renamed from arch/x86/mm/restart.c~v6_PATCH_5_9_Restore_memory_address_space +62
-2@@ -53,8 +53,10 @@ int cr_read_thread(struct cr_ctx *ctx) size =sizeof (*desc) *GDT_ENTRY_TLS_ENTRIES ; desc =kmalloc (size,GFP_KERNEL ); -if (!desc) -return -ENOMEM ; +if (!desc) { + ret = -ENOMEM ; + goto out; + } ret =cr_kread (ctx, desc, size);if (ret >=0 ) {@@ -189,3 +191,61 @@ int cr_read_cpu(struct cr_ctx *ctx)cr_hbuf_put (ctx,sizeof (*hh));return ret; } + +int cr_read_mm_context (struct cr_ctx *ctx,struct mm_struct *mm,int parent) +{ +struct cr_hdr_mm_context *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int n, rparent, ret = -EINVAL ; + + rparent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_MM_CONTEXT ); +cr_debug ("parent %d rparent %d nldt %d\n" , parent, rparent, hh->nldt); +if (rparent <0 ) { + ret = rparent; + goto out; + } +if (rparent != parent) + goto out; + +if (hh->nldt <0 || hh->ldt_entry_size !=LDT_ENTRY_SIZE ) + goto out; + +/* +* to utilize the syscall modify_ldt() we first convert the data +* in the checkpoint image from 'struct desc_struct' to 'struct +* user_desc' with reverse logic of include/asm/desc.h:fill_ldt() +*/ + +for (n =0 ; n < hh->nldt; n++) { +struct user_desc info; +struct desc_struct desc; +mm_segment_t old_fs; + + ret =cr_kread (ctx, &desc,LDT_ENTRY_SIZE ); +if (ret <0 ) + goto out; + + info.entry_number = n; + info.base_addr = desc.base0 | (desc.base1 <<16 ); + info.limit = desc.limit0; + info.seg_32bit = desc.d; + info.contents = desc.type >>2 ; + info.read_exec_only = (desc.type >>1 ) ^1 ; + info.limit_in_pages = desc.g; + info.seg_not_present = desc.p ^1 ; + info.useable = desc.avl; + + old_fs =get_fs (); +set_fs (get_ds ()); + ret =sys_modify_ldt (1 , (struct user_desc __user *) &info, +sizeof (info)); +set_fs (old_fs); + +if (ret <0 ) + goto out; + } + + ret =0 ; + out: +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +}diff -puN checkpoint/checkpoint_arch.h~v6_PATCH_5_9_Restore_memory_address_space
checkpoint/checkpoint_arch.hcheckpoint/checkpoint_arch.h renamed from checkpoint/checkpoint_arch.h~v6_PATCH_5_9_Restore_memory_address_space +2
-0@@ -7,3 +7,5 @@ extern int cr_write_mm_context(struct crextern int cr_read_thread (struct cr_ctx *ctx);extern int cr_read_cpu (struct cr_ctx *ctx); +extern int cr_read_mm_context (struct cr_ctx *ctx, +struct mm_struct *mm,int parent);diff -puN checkpoint/checkpoint_mem.h~v6_PATCH_5_9_Restore_memory_address_space
checkpoint/checkpoint_mem.hcheckpoint/checkpoint_mem.h renamed from checkpoint/checkpoint_mem.h~v6_PATCH_5_9_Restore_memory_address_space +5
-0@@ -38,4 +38,9 @@ static inline int cr_pgarr_is_full(struc return (pgarr->nr_used == CR_PGARR_TOTAL); } +static inline int cr_pgarr_nr_free (struct cr_pgarr *pgarr) +{ +return CR_PGARR_TOTAL - pgarr->nr_used; +} +#endif /* _CHECKPOINT_CKPT_MEM_H_ */ diff -puN checkpoint/Makefile~v6_PATCH_5_9_Restore_memory_address_space checkpoint/Makefile
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_5_9_Restore_memory_address_space +1
-1@@ -3,4 +3,4 @@ # obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ - ckpt_mem.o + ckpt_mem.o rstr_mem.odiff -puN checkpoint/restart.c~v6_PATCH_5_9_Restore_memory_address_space
checkpoint/restart.ccheckpoint/restart.c renamed from checkpoint/restart.c~v6_PATCH_5_9_Restore_memory_address_space +42
-0@@ -78,6 +78,44 @@ int cr_read_string(struct cr_ctx *ctx, vreturn cr_read_obj_type (ctx, str, len,CR_HDR_STRING ); } +/** +* cr_read_fname - read a file name +* @ctx: checkpoint context +* @fname: buffer +* @n: buffer length +*/ +int cr_read_fname (struct cr_ctx *ctx,void *fname,int flen) +{ +return cr_read_obj_type (ctx, fname, flen,CR_HDR_FNAME ); +} + +/** +* cr_read_open_fname - read a file name and open a file +* @ctx: checkpoint context +* @flags: file flags +* @mode: file mode +*/ +struct file *cr_read_open_fname (struct cr_ctx *ctx,int flags,int mode) +{ +struct file *file; +char *fname; +int ret; + + fname =kmalloc (PATH_MAX ,GFP_KERNEL ); +if (!fname) +return ERR_PTR (-ENOMEM ); + + ret =cr_read_fname (ctx, fname,PATH_MAX ); +cr_debug ("fname '%s' flags %#x mode %#x\n" , fname, flags, mode); +if (ret >=0 ) + file =filp_open (fname, flags, mode); +else + file =ERR_PTR (ret); + +kfree (fname); +return file; +} +/* read the checkpoint header */ static int cr_read_head (struct cr_ctx *ctx) {@@ -177,6 +215,10 @@ static int cr_read_task(struct cr_ctx *ccr_debug ("task_struct: ret %d\n" , ret);if (ret <0 ) goto out; + ret =cr_read_mm (ctx); +cr_debug ("memory: ret %d\n" , ret); +if (ret <0 ) + goto out; ret =cr_read_thread (ctx);cr_debug ("thread: ret %d\n" , ret);if (ret <0 )diff -puN
/dev/nullcheckpoint/rstr_mem.ccheckpoint/rstr_mem.c new file +63
-0@@ -0,0 +1,384 @@ +/* +* Restart memory contents +* +* 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/kernel.h> +#include <linux/sched.h> +#include <linux/fcntl.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/pagemap.h> +#include <linux/mm_types.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/err.h> +#include <linux/checkpoint.h> +#include <linux/checkpoint_hdr.h> + +#include "checkpoint_arch.h" +#include "checkpoint_mem.h" + +/* +* Unlike checkpoint, restart is executed in the context of each restarting +* process: vma regions are restored via a call to mmap(), and the data is +* read into the address space of the current process. +*/ + + +/** +* cr_read_pages_vaddrs - read addresses of pages to page-array chain +* @ctx - restart context +* @nr_pages - number of address to read +*/ +static int cr_read_pages_vaddrs (struct cr_ctx *ctx,unsigned long nr_pages) +{ +struct cr_pgarr *pgarr; +unsigned long *vaddrp; +int nr, ret; + +while (nr_pages) { + pgarr =cr_pgarr_current (ctx); +if (!pgarr) +return -ENOMEM ; + nr =cr_pgarr_nr_free (pgarr); +if (nr > nr_pages) + nr = nr_pages; + vaddrp = &pgarr->vaddrs[pgarr->nr_used]; + ret =cr_kread (ctx, vaddrp, nr *sizeof (unsigned long )); +if (ret <0 ) +return ret; + pgarr->nr_used += nr; + nr_pages -= nr; + } +return 0 ; +} + +static int cr_page_read (struct cr_ctx *ctx,struct page *page,char *buf) +{
checkpoint/rstr_mem.c line 73
Quoted 10 lines
checkpoint/rstr_mem.c new file +10
-0+void *ptr; +int ret; + + ret =cr_kread (ctx, buf,PAGE_SIZE ); +if (ret <0 ) +return ret; + + ptr =kmap_atomic (page,KM_USER1 ); +memcpy (ptr, buf,PAGE_SIZE ); +kunmap_atomic (page,KM_USER1 );
Here too, I think this should be changed tokunmap_atomic(ptr, KM_USER1);
Regards,
Nadia
Quoted 342 lines
checkpoint/rstr_mem.c new file +311
-0+ +return 0 ; +} + +/** +* cr_read_pages_contents - read in data of pages in page-array chain +* @ctx - restart context +*/ +static int cr_read_pages_contents (struct cr_ctx *ctx) +{ +struct mm_struct *mm = current->mm; +struct cr_pgarr *pgarr; +unsigned long *vaddrs; +char *buf; +int i, ret =0 ; + + buf =kmalloc (PAGE_SIZE ,GFP_KERNEL ); +if (!buf) +return -ENOMEM ; + +down_read (&mm->mmap_sem); +list_for_each_entry_reverse (pgarr, &ctx->pgarr_list, list) { + vaddrs = pgarr->vaddrs; +for (i =0 ; i < pgarr->nr_used; i++) { +struct page *page; + + ret =get_user_pages (current, mm, vaddrs[i], +1 ,1 ,1 , &page,NULL ); +if (ret <0 ) + goto out; + + ret =cr_page_read (ctx, page, buf); +page_cache_release (page); + +if (ret <0 ) + goto out; + } + } + + out: +up_read (&mm->mmap_sem); +kfree (buf); +return 0 ; +} + +/** +* cr_read_private_vma_contents - restore contents of a VMA with private memory +* @ctx - restart context +* +* Reads a header that specifies how many pages will follow, then reads +* a list of virtual addresses into ctx->pgarr_list page-array chain, +* followed by the actual contents of the corresponding pages. Iterates +* these steps until reaching a header specifying "0" pages, which marks +* the end of the contents. +*/ +static int cr_read_private_vma_contents (struct cr_ctx *ctx) +{ +struct cr_hdr_pgarr *hh; +unsigned long nr_pages; +int parent, ret =0 ; + +while (1 ) { + hh =cr_hbuf_get (ctx,sizeof (*hh)); + parent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_PGARR ); +if (parent !=0 ) { +if (parent <0 ) + ret = parent; +else + ret = -EINVAL ; +cr_hbuf_put (ctx,sizeof (*hh)); +break ; + } + +cr_debug ("nr_pages %ld\n" , (unsigned long ) hh->nr_pages); + + nr_pages = hh->nr_pages; +cr_hbuf_put (ctx,sizeof (*hh)); + +if (!nr_pages) +break ; + + ret =cr_read_pages_vaddrs (ctx, nr_pages); +if (ret <0 ) +break ; + ret =cr_read_pages_contents (ctx); +if (ret <0 ) +break ; +cr_pgarr_reset_all (ctx); + } + +return ret; +} + +/** +* cr_calc_map_prot_bits - convert vm_flags to mmap protection +* orig_vm_flags: source vm_flags +*/ +static unsigned long cr_calc_map_prot_bits (unsigned long orig_vm_flags) +{ +unsigned long vm_prot =0 ; + +if (orig_vm_flags &VM_READ ) + vm_prot |=PROT_READ ; +if (orig_vm_flags &VM_WRITE ) + vm_prot |=PROT_WRITE ; +if (orig_vm_flags &VM_EXEC ) + vm_prot |=PROT_EXEC ; +if (orig_vm_flags &PROT_SEM )/* only (?) with IPC-SHM */ + vm_prot |=PROT_SEM ; + +return vm_prot; +} + +/** +* cr_calc_map_flags_bits - convert vm_flags to mmap flags +* orig_vm_flags: source vm_flags +*/ +static unsigned long cr_calc_map_flags_bits (unsigned long orig_vm_flags) +{ +unsigned long vm_flags =0 ; + + vm_flags =MAP_FIXED ; +if (orig_vm_flags &VM_GROWSDOWN ) + vm_flags |=MAP_GROWSDOWN ; +if (orig_vm_flags &VM_DENYWRITE ) + vm_flags |=MAP_DENYWRITE ; +if (orig_vm_flags &VM_EXECUTABLE ) + vm_flags |=MAP_EXECUTABLE ; +if (orig_vm_flags &VM_MAYSHARE ) + vm_flags |=MAP_SHARED ; +else + vm_flags |=MAP_PRIVATE ; + +return vm_flags; +} + +static int cr_read_vma (struct cr_ctx *ctx,struct mm_struct *mm) +{ +struct cr_hdr_vma *hh =cr_hbuf_get (ctx,sizeof (*hh)); +unsigned long vm_size, vm_start, vm_flags, vm_prot, vm_pgoff; +unsigned long addr; +struct file *file =NULL ; +int parent, ret = -EINVAL ; + + parent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_VMA ); +if (parent <0 ) { + ret = parent; + goto err; + }else if (parent !=0 ) + goto err; + +cr_debug ("vma %#lx-%#lx type %d\n" , (unsigned long ) hh->vm_start, + (unsigned long ) hh->vm_end, (int ) hh->vma_type); + +if (hh->vm_end < hh->vm_start) + goto err; + + vm_start = hh->vm_start; + vm_pgoff = hh->vm_pgoff; + vm_size = hh->vm_end - hh->vm_start; + vm_prot =cr_calc_map_prot_bits (hh->vm_flags); + vm_flags =cr_calc_map_flags_bits (hh->vm_flags); + +switch (hh->vma_type) { + +case CR_VMA_ANON :/* anonymous private mapping */ +if (vm_flags &VM_SHARED ) + goto err; +/* +* vm_pgoff for anonymous mapping is the "global" page +* offset (namely from addr 0x0), so we force a zero +*/ + vm_pgoff =0 ; +break ; + +case CR_VMA_FILE :/* private mapping from a file */ +if (vm_flags &VM_SHARED ) + goto err; +/* +* for private mapping using 'read-only' is sufficient +*/ + file =cr_read_open_fname (ctx,O_RDONLY ,0 ); +if (IS_ERR (file)) { + ret =PTR_ERR (file); + goto err; + } +break ; + +default : + goto err; + + } + +cr_hbuf_put (ctx,sizeof (*hh)); + +down_write (&mm->mmap_sem); + addr =do_mmap_pgoff (file, vm_start, vm_size, + vm_prot, vm_flags, vm_pgoff); +up_write (&mm->mmap_sem); +cr_debug ("size %#lx prot %#lx flag %#lx pgoff %#lx => %#lx\n" , + vm_size, vm_prot, vm_flags, vm_pgoff, addr); + +/* the file (if opened) is now referenced by the vma */ +if (file) +filp_close (file,NULL ); + +if (IS_ERR ((void *) addr)) +return PTR_ERR ((void *) addr); + +/* +* CR_VMA_ANON: read in memory as is +* CR_VMA_FILE: read in memory as is +* (more to follow ...) +*/ + +switch (hh->vma_type) { +case CR_VMA_ANON : +case CR_VMA_FILE : +/* standard case: read the data into the memory */ + ret =cr_read_private_vma_contents (ctx); +break ; + } + +if (ret <0 ) +return ret; + +cr_debug ("vma retval %d\n" , ret); +return 0 ; + + err: +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +} + +static int cr_destroy_mm (struct mm_struct *mm) +{ +struct vm_area_struct *vmnext = mm->mmap; +struct vm_area_struct *vma; +int ret; + +while (vmnext) { + vma = vmnext; + vmnext = vmnext->vm_next; + ret =do_munmap (mm, vma->vm_start, vma->vm_end-vma->vm_start); +if (ret <0 ) { +pr_debug ("CR: restart failed do_munmap (%d)\n" , ret); +return ret; + } + } +return 0 ; +} + +int cr_read_mm (struct cr_ctx *ctx) +{ +struct cr_hdr_mm *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct mm_struct *mm; +int nr, parent, ret; + + parent =cr_read_obj_type (ctx, hh,sizeof (*hh),CR_HDR_MM ); +if (parent <0 ) { + ret = parent; + goto out; + } + + ret = -EINVAL ; +#if 0 /* activate when containers are used */ +if (parent !=task_pid_vnr (current)) + goto out; +#endif +cr_debug ("map_count %d\n" , hh->map_count); + +/* XXX need more sanity checks */ +if (hh->start_code > hh->end_code || + hh->start_data > hh->end_data || hh->map_count <0 ) + goto out; + + mm = current->mm; + +/* point of no return -- destruct current mm */ +down_write (&mm->mmap_sem); + ret =cr_destroy_mm (mm); +if (ret <0 ) { +up_write (&mm->mmap_sem); + goto out; + } + mm->start_code = hh->start_code; + mm->end_code = hh->end_code; + mm->start_data = hh->start_data; + mm->end_data = hh->end_data; + mm->start_brk = hh->start_brk; + mm->brk = hh->brk; + mm->start_stack = hh->start_stack; + mm->arg_start = hh->arg_start; + mm->arg_end = hh->arg_end; + mm->env_start = hh->env_start; + mm->env_end = hh->env_end; +up_write (&mm->mmap_sem); + +/* FIX: need also mm->flags */ + +for (nr = hh->map_count; nr; nr--) { + ret =cr_read_vma (ctx, mm); +if (ret <0 ) + goto out; + } + + ret =cr_read_mm_context (ctx, mm, hh->objref); + out: +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +}diff -puN
include/asm-x86/checkpoint_hdr.h~v6_PATCH_5_9_Restore_memory_address_spaceinclude/asm-x86/checkpoint_hdr.hinclude/asm-x86/checkpoint_hdr.h renamed from include/asm-x86/checkpoint_hdr.h~v6_PATCH_5_9_Restore_memory_address_space +4
-0@@ -74,4 +74,8 @@ struct cr_hdr_mm_context {__s16 nldt; } __attribute__((aligned(8))); + +/* misc prototypes from kernel (not defined elsewhere) */ +asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount); +#endif /* __ASM_X86_CKPT_HDR__H */ diff -puN
include/linux/checkpoint.h~v6_PATCH_5_9_Restore_memory_address_spaceinclude/linux/checkpoint.hinclude/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_5_9_Restore_memory_address_space +3
-0@@ -55,6 +55,9 @@ extern int cr_write_fname(struct cr_ctxextern 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_string (struct cr_ctx *ctx,void *str,int len); +extern int cr_read_fname (struct cr_ctx *ctx,void *fname,int n); +extern struct file *cr_read_open_fname (struct cr_ctx *ctx, +int flags,int mode);extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t);extern int cr_read_mm (struct cr_ctx *ctx);_
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linux-foundation.org/mailman/listinfo/containers
Signature · 1 line
Nadia Derbey <Nadia.Derbey-6ktuUTfB/[email protected]>
PATCH 3/9 x86 support for checkpoint/restart
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
(Following Dave Hansen's refactoring of the original post)
Add logic to save and restore architecture specific state, including thread-specific state, CPU registers and FPU state.
Currently only x86-32 is supported. Compiling on x86-64 will trigger an explicit error.
---
linux-2.6.git-dave/arch/x86/mm/Makefile | 2 linux-2.6.git-dave/arch/x86/mm/checkpoint.c | 198 ++++++++++++++++++++ linux-2.6.git-dave/arch/x86/mm/restart.c | 190 +++++++++++++++++++ linux-2.6.git-dave/checkpoint/checkpoint.c | 13 + linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 7 linux-2.6.git-dave/checkpoint/restart.c | 13 + linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 72 +++++++ linux-2.6.git-dave/include/linux/checkpoint_hdr.h | 1 8 files changed, 494 insertions(+), 2 deletions(-)
arch/x86/mm/checkpoint.c new file +198 -0
@@ -0,0 +1,198 @@ +/* +* Checkpoint/restart - architecture specific support for x86 +* +* 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 <asm/desc.h> +#include <asm/i387.h> + +#include <linux/checkpoint.h> +#include <linux/checkpoint_hdr.h> + +/* dump the thread_struct of a given task */ +int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_thread *hh =cr_hbuf_get (ctx,sizeof (*hh)); +struct thread_struct *thread; +struct desc_struct *desc; +int ntls =0 ; +int n, ret; + + h.type =CR_HDR_THREAD ; + h.len =sizeof (*hh); + h.parent =task_pid_vnr (t); + + thread = &t->thread; + +/* calculate no. of TLS entries that follow */ + desc = thread->tls_array; +for (n =GDT_ENTRY_TLS_ENTRIES ; n >0 ; n--, desc++) { +if (desc->a || desc->b) + ntls++; + } + + hh->gdt_entry_tls_entries =GDT_ENTRY_TLS_ENTRIES ; + hh->sizeof_tls_array =sizeof (thread->tls_array); + hh->ntls = ntls; + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) +return ret; + +/* for simplicity dump the entire array, cherry-pick upon restart */ + ret =cr_kwrite (ctx, thread->tls_array,sizeof (thread->tls_array)); + +cr_debug ("ntls %d\n" , ntls); + +/* IGNORE RESTART BLOCKS FOR NOW ... */ + +return ret; +} + +#ifdef CONFIG_X86_64 + +#error "CONFIG_X86_64 unsupported yet." + +#else /* !CONFIG_X86_64 */ + +void cr_write_cpu_regs (struct cr_hdr_cpu *hh,struct task_struct *t) +{ +struct thread_struct *thread = &t->thread; +struct pt_regs *regs =task_pt_regs (t); + + hh->bp = regs->bp; + hh->bx = regs->bx; + hh->ax = regs->ax; + hh->cx = regs->cx; + hh->dx = regs->dx; + hh->si = regs->si; + hh->di = regs->di; + hh->orig_ax = regs->orig_ax; + hh->ip = regs->ip; + hh->cs = regs->cs; + hh->flags = regs->flags; + hh->sp = regs->sp; + hh->ss = regs->ss; + + hh->ds = regs->ds; + hh->es = regs->es; + +/* +* for checkpoint in process context (from within a container) +* the GS and FS registers should be saved from the hardware; +* otherwise they are already sabed on the thread structure +*/ +if (t == current) { +savesegment (gs, hh->gs); +savesegment (fs, hh->fs); + }else { + hh->gs = thread->gs; + hh->fs = thread->fs; + } + +/* +* for checkpoint in process context (from within a container), +* the actual syscall is taking place at this very moment; so +* we (optimistically) subtitute the future return value (0) of +* this syscall into the orig_eax, so that upon restart it will +* succeed (or it will endlessly retry checkpoint...) +*/ +if (t == current) { +BUG_ON (hh->orig_ax <0 ); + hh->ax =0 ; + } +} + +void cr_write_cpu_debug (struct cr_hdr_cpu *hh,struct task_struct *t) +{ +struct thread_struct *thread = &t->thread; + +/* debug regs */ + +preempt_disable (); + +/* +* for checkpoint in process context (from within a container), +* get the actual registers; otherwise get the saved values. +*/ + +if (t == current) { +get_debugreg (hh->debugreg0,0 ); +get_debugreg (hh->debugreg1,1 ); +get_debugreg (hh->debugreg2,2 ); +get_debugreg (hh->debugreg3,3 ); +get_debugreg (hh->debugreg6,6 ); +get_debugreg (hh->debugreg7,7 ); + }else { + hh->debugreg0 = thread->debugreg0; + hh->debugreg1 = thread->debugreg1; + hh->debugreg2 = thread->debugreg2; + hh->debugreg3 = thread->debugreg3; + hh->debugreg6 = thread->debugreg6; + hh->debugreg7 = thread->debugreg7; + } + + hh->debugreg4 =0 ; + hh->debugreg5 =0 ; + + hh->uses_debug = !!(task_thread_info (t)->flags &TIF_DEBUG ); + +preempt_enable (); +} + +void cr_write_cpu_fpu (struct cr_hdr_cpu *hh,struct task_struct *t) +{ +struct thread_struct *thread = &t->thread; +struct thread_info *thread_info =task_thread_info (t); + +/* i387 + MMU + SSE logic */ + +preempt_disable (); + + hh->used_math =tsk_used_math (t) ?1 :0 ; +if (hh->used_math) { +/* +* normally, no need to unlazy_fpu(), since TS_USEDFPU flag +* have been cleared when task was conexted-switched out... +* except if we are in process context, in which case we do +*/ +if (thread_info->status &TS_USEDFPU ) +unlazy_fpu (current); + + hh->has_fxsr = cpu_has_fxsr; +memcpy (&hh->xstate, &thread->xstate,sizeof (thread->xstate)); + } + +preempt_enable (); +} + +#endif /* CONFIG_X86_64 */ + +/* dump the cpu state and registers of a given task */ +int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t) +{ +struct cr_hdr h; +struct cr_hdr_cpu *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + h.type =CR_HDR_CPU ; + h.len =sizeof (*hh); + h.parent =task_pid_vnr (t); + +cr_write_cpu_regs (hh, t); +cr_write_cpu_debug (hh, t); +cr_write_cpu_fpu (hh, t); + +cr_debug ("math %d debug %d\n" , hh->used_math, hh->uses_debug); + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +return ret; +}
arch/x86/mm/Makefile renamed from arch/x86/mm/Makefile~v6_PATCH_3_9_x86_support_for_checkpoint_restart +2 -0
@@ -18,3 +18,5 @@ obj-$(CONFIG_K8_NUMA) += k8topology_64. obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o obj-$(CONFIG_MEMTEST) += memtest.o + +obj-$(CONFIG_CHECKPOINT_RESTART) += checkpoint.o restart.o
arch/x86/mm/restart.c new file +190 -0
190 lines not on this page · raw message
checkpoint/checkpoint_arch.h new file +7 -0
@@ -0,0 +1,7 @@ +#include <linux/checkpoint.h> + +extern int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t); +extern int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t); + +extern int cr_read_thread (struct cr_ctx *ctx); +extern int cr_read_cpu (struct cr_ctx *ctx);
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~v6_PATCH_3_9_x86_support_for_checkpoint_restart +12 -1
@@ -20,6 +20,8 @@#include <linux/checkpoint.h> #include <linux/checkpoint_hdr.h> +#include "checkpoint_arch.h" +/** * cr_write_obj - write a record described by a cr_hdr * @ctx: checkpoint context
@@ -145,8 +147,17 @@ static int cr_write_task(struct cr_ctx * } ret =cr_write_task_struct (ctx, t); -cr_debug ("ret %d\n" , ret); +cr_debug ("task_struct: ret %d\n" , ret); +if (ret <0 ) + goto out; + ret =cr_write_thread (ctx, t); +cr_debug ("thread: ret %d\n" , ret); +if (ret <0 ) + goto out; + ret =cr_write_cpu (ctx, t); +cr_debug ("cpu: ret %d\n" , ret); + out:return ret; }
checkpoint/restart.c renamed from checkpoint/restart.c~v6_PATCH_3_9_x86_support_for_checkpoint_restart +12 -1
@@ -15,6 +15,8 @@#include <linux/checkpoint.h> #include <linux/checkpoint_hdr.h> +#include "checkpoint_arch.h" +/** * cr_read_obj - read a whole record (cr_hdr followed by payload) * @ctx: checkpoint context
@@ -172,8 +174,17 @@ static int cr_read_task(struct cr_ctx *cint ret; ret =cr_read_task_struct (ctx); -cr_debug ("ret %d\n" , ret); +cr_debug ("task_struct: ret %d\n" , ret); +if (ret <0 ) + goto out; + ret =cr_read_thread (ctx); +cr_debug ("thread: ret %d\n" , ret); +if (ret <0 ) + goto out; + ret =cr_read_cpu (ctx); +cr_debug ("cpu: ret %d\n" , ret); + out:return ret; }
include/asm-x86/checkpoint_hdr.h new file +72 -0
72 lines not on this page · raw message
include/linux/checkpoint_hdr.h renamed from include/linux/checkpoint_hdr.h~v6_PATCH_3_9_x86_support_for_checkpoint_restart +1 -0
@@ -12,6 +12,7 @@#include <linux/types.h> #include <linux/utsname.h> +#include <asm/checkpoint_hdr.h> /* * To maintain compatibility between 32-bit and 64-bit architecture flavors,
_
PATCH 4/9 Dump memory address space
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
For each VMA, there is a 'struct cr_vma'; if the VMA is file-mapped, it will be followed by the file name. Then comes the actual contents, in one or more chunk: each chunk begins with a header that specifies how many pages it holds, then the virtual addresses of all the dumped pages in that chunk, followed by the actual contents of all dumped pages. A header with zero number of pages marks the end of the contents. Then comes the next VMA and so on.
---
linux-2.6.git-dave/arch/x86/mm/checkpoint.c | 31 + linux-2.6.git-dave/arch/x86/mm/restart.c | 1 linux-2.6.git-dave/checkpoint/Makefile | 3 linux-2.6.git-dave/checkpoint/checkpoint.c | 53 ++ linux-2.6.git-dave/checkpoint/checkpoint_arch.h | 2 linux-2.6.git-dave/checkpoint/checkpoint_mem.h | 41 + linux-2.6.git-dave/checkpoint/ckpt_mem.c | 500 ++++++++++++++++++++ linux-2.6.git-dave/checkpoint/sys.c | 16 linux-2.6.git-dave/include/asm-x86/checkpoint_hdr.h | 5 linux-2.6.git-dave/include/linux/checkpoint.h | 12 linux-2.6.git-dave/include/linux/checkpoint_hdr.h | 32 + 11 files changed, 695 insertions(+), 1 deletion(-)
arch/x86/mm/checkpoint.c renamed from arch/x86/mm/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space +31 -0
@@ -196,3 +196,34 @@ int cr_write_cpu(struct cr_ctx *ctx, strcr_hbuf_put (ctx,sizeof (*hh));return ret; } + +/* dump the mm->context state */ +int cr_write_mm_context (struct cr_ctx *ctx,struct mm_struct *mm,int parent) +{ +struct cr_hdr h; +struct cr_hdr_mm_context *hh =cr_hbuf_get (ctx,sizeof (*hh)); +int ret; + + h.type =CR_HDR_MM_CONTEXT ; + h.len =sizeof (*hh); + h.parent = parent; + +mutex_lock (&mm->context.lock); + + hh->ldt_entry_size =LDT_ENTRY_SIZE ; + hh->nldt = mm->context.size; + +cr_debug ("nldt %d\n" , hh->nldt); + + ret =cr_write_obj (ctx, &h, hh); +cr_hbuf_put (ctx,sizeof (*hh)); +if (ret <0 ) + goto out; + + ret =cr_kwrite (ctx, mm->context.ldt, + mm->context.size *LDT_ENTRY_SIZE ); + + out: +mutex_unlock (&mm->context.lock); +return ret; +}
arch/x86/mm/restart.c renamed from arch/x86/mm/restart.c~v6_PATCH_4_9_Dump_memory_address_space +1 -0
@@ -8,6 +8,7 @@* distribution for more details. */ +#include <linux/unistd.h> #include <asm/desc.h> #include <asm/i387.h>
checkpoint/checkpoint_arch.h renamed from checkpoint/checkpoint_arch.h~v6_PATCH_4_9_Dump_memory_address_space +2 -0
@@ -2,6 +2,8 @@extern int cr_write_thread (struct cr_ctx *ctx,struct task_struct *t);extern int cr_write_cpu (struct cr_ctx *ctx,struct task_struct *t); +extern int cr_write_mm_context (struct cr_ctx *ctx, +struct mm_struct *mm,int parent);extern int cr_read_thread (struct cr_ctx *ctx);extern int cr_read_cpu (struct cr_ctx *ctx);
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~v6_PATCH_4_9_Dump_memory_address_space +53 -0
65 lines not on this page · raw message
checkpoint/checkpoint_mem.h new file +41 -0
41 lines not on this page · raw message
checkpoint/ckpt_mem.c new file +500 -0
500 lines not on this page · raw message
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_4_9_Dump_memory_address_space +2 -1
@@ -2,4 +2,5 @@ # Makefile for linux checkpoint/restart. # -obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ + ckpt_mem.o
checkpoint/sys.c renamed from checkpoint/sys.c~v6_PATCH_4_9_Dump_memory_address_space +16 -0
@@ -16,6 +16,8 @@#include <linux/capability.h> #include <linux/checkpoint.h> +#include "checkpoint_mem.h" +/* * helpers to write/read to/from the image file descriptor *
@@ -161,6 +163,11 @@ void cr_ctx_free(struct cr_ctx *ctx)kfree (ctx->hbuf); +if (ctx->vfsroot) +path_put (ctx->vfsroot); + +cr_pgarr_free (ctx); +kfree (ctx); }
@@ -184,6 +191,15 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, ireturn ERR_PTR (-ENOMEM ); } +/* +* assume checkpointer is in container's root vfs +* FIXME: this works for now, but will change with real containers +*/ + ctx->vfsroot = ¤t->fs->root; +path_get (ctx->vfsroot); + +INIT_LIST_HEAD (&ctx->pgarr_list); + ctx->pid = pid; ctx->flags = flags;
include/asm-x86/checkpoint_hdr.h renamed from include/asm-x86/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_space +5 -0
@@ -69,4 +69,9 @@ struct cr_hdr_cpu { } __attribute__((aligned(8))); +struct cr_hdr_mm_context { +__s16 ldt_entry_size; +__s16 nldt; +} __attribute__((aligned (8 ))); +#endif /* __ASM_X86_CKPT_HDR__H */
include/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_4_9_Dump_memory_address_space +12 -0
@@ -10,6 +10,9 @@* distribution for more details. */ +#include <linux/path.h> +#include <linux/fs.h> +#define CR_VERSION 1struct cr_ctx {
@@ -24,6 +27,10 @@ struct cr_ctx {void *hbuf;/* temporary buffer for headers */ int hpos;/* position in headers buffer */ + +struct list_head pgarr_list;/* page array to dump VMA contents */ + +struct path *vfsroot;/* container root (FIXME) */ };/* cr_ctx: flags */
@@ -42,11 +49,16 @@ struct cr_hdr;extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf);extern int cr_write_string (struct cr_ctx *ctx,char *str,int len); +extern int cr_write_fname (struct cr_ctx *ctx, +struct path *path,struct path *root);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_string (struct cr_ctx *ctx,void *str,int len); +extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t); +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);
include/linux/checkpoint_hdr.h renamed from include/linux/checkpoint_hdr.h~v6_PATCH_4_9_Dump_memory_address_space +32 -0
@@ -32,6 +32,7 @@ struct cr_hdr {enum {CR_HDR_HEAD =1 ,CR_HDR_STRING , +CR_HDR_FNAME ,CR_HDR_TASK =101 ,CR_HDR_THREAD ,
@@ -39,6 +40,7 @@ enum {CR_HDR_MM =201 ,CR_HDR_VMA , +CR_HDR_PGARR ,CR_HDR_MM_CONTEXT ,CR_HDR_TAIL =5001
@@ -73,4 +75,34 @@ struct cr_hdr_task {__s32 task_comm_len; } __attribute__((aligned(8))); +struct cr_hdr_mm { +__u32 objref;/* identifier for shared objects */ +__u32 map_count; + +__u64 start_code, end_code, start_data, end_data; +__u64 start_brk, brk, start_stack; +__u64 arg_start, arg_end, env_start, env_end; +} __attribute__((aligned (8 ))); + +/* vma subtypes */ +enum vm_type { +CR_VMA_ANON =1 , +CR_VMA_FILE +}; + +struct cr_hdr_vma { +__u32 vma_type; +__u32 _padding; + +__u64 vm_start; +__u64 vm_end; +__u64 vm_page_prot; +__u64 vm_flags; +__u64 vm_pgoff; +} __attribute__((aligned (8 ))); + +struct cr_hdr_pgarr { +__u64 nr_pages;/* number of pages to saved */ +} __attribute__((aligned (8 ))); +#endif /* _CHECKPOINT_CKPT_HDR_H_ */
_
PATCH 6/9 Checkpoint/restart: initial documentation
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Covers application checkpoint/restart, overall design, interfaces and checkpoint image format.
---
linux-2.6.git-dave/Documentation/checkpoint.txt | 370 ++++++++++++++++++++++++ 1 file changed, 370 insertions(+)
Documentation/checkpoint.txt new file +370 -0
@@ -0,0 +1,370 @@ + + === Checkpoint-Restart support in the Linux kernel === + +Copyright (C) 2008 Oren Laadan + +Author: Oren Laadan <[email protected]> + +License: The GNU Free Documentation License, Version 1.2 + (dual licensed under the GPL v2) +Reviewers: + +Application checkpoint/restart [CR] is the ability to save the state +of a running application so that it can later resume its execution +from the time at which it was checkpointed. An application can be +migrated by checkpointing it on one machine and restarting it on +another. CR can provide many potential benefits: + +* Failure recovery: by rolling back an to a previous checkpoint + +* Improved response time: by restarting applications from checkpoints + instead of from scratch. + +* Improved system utilization: by suspending long running CPU + intensive jobs and resuming them when load decreases. + +* Fault resilience: by migrating applications off of faulty hosts. + +* Dynamic load balancing: by migrating applications to less loaded + hosts. + +* Improved service availability and administration: by migrating + applications before host maintenance so that they continue to run + with minimal downtime + +* Time-travel: by taking periodic checkpoints and restarting from + any previous checkpoint. + + +=== Overall design + +Checkpoint and restart is done in the kernel as much as possible. The +kernel exports a relative opaque 'blob' of data to userspace which can +then be handed to the new kernel at restore time. The 'blob' contains +data and state of select portions of kernel structures such as VMAs +and mm_structs, as well as copies of the actual memory that the tasks +use. Any changes in this blob's format between kernel revisions can be +handled by an in-userspace conversion program. The approach is similar +to virtually all of the commercial CR products out there, as well as +the research project Zap. + +Two new system calls are introduced to provide CR: sys_checkpoint and +sys_restart. The checkpoint code basically serializes internal kernel +state and writes it out to a file descriptor, and the resulting image +is stream-able. More specifically, it consists of 5 steps: + 1. Pre-dump + 2. Freeze the container + 3. Dump + 4. Thaw (or kill) the container + 5. Post-dump +Steps 1 and 5 are an optimization to reduce application downtime: +"pre-dump" works before freezing the container, e.g. the pre-copy for +live migration, and "post-dump" works after the container resumes +execution, e.g. write-back the data to secondary storage. + +The restart code basically reads the saved kernel state and from a +file descriptor, and re-creates the tasks and the resources they need +to resume execution. The restart code is executed by each task that +is restored in a new container to reconstruct its own state. + + +=== Interfaces + +int sys_checkpoint(pid_t pid, int fd, unsigned long flag); + Checkpoint a container whose init task is identified by pid, to the + file designated by fd. Flags will have future meaning (should be 0 + for now). + Returns: a positive integer that identifies the checkpoint image + (for future reference in case it is kept in memory) upon success, + 0 if it returns from a restart, and -1 if an error occurs. + +int sys_restart(int crid, int fd, unsigned long flags); + Restart a container from a checkpoint image identified by crid, or + from the blob stored in the file designated by fd. Flags will have + future meaning (should be 0 for now). + Returns: 0 on success and -1 if an error occurs. + +Thus, if checkpoint is initiated by a process in the container, one +can use logic similar to fork(): + ... + crid = checkpoint(...); + switch (crid) { + case -1: + perror("checkpoint failed"); + break; + default: + fprintf(stderr, "checkpoint succeeded, CRID=%d\n", ret); + /* proceed with execution after checkpoint */ + ... + break; + case 0: + fprintf(stderr, "returned after restart\n"); + /* proceed with action required following a restart */ + ... + break; + } + ... +And to initiate a restart, the process in an empty container can use +logic similar to execve(): + ... + if (restart(crid, ...) < 0) + perror("restart failed"); + /* only get here if restart failed */ + ... + +See below a complete example in C. + + +=== Order of state dump + +The order of operations, both save and restore, is as following: + +* Header section: header, container information, etc. +* Global section: [TBD] global resources such as IPC, UTS, etc. +* Process forest: [TBD] tasks and their relationships +* Per task data (for each task): + -> task state: elements of task_struct + -> thread state: elements of thread_struct and thread_info + -> CPU state: registers etc, including FPU + -> memory state: memory address space layout and contents + -> filesystem state: [TBD] filesystem namespace state, chroot, cwd, etc + -> files state: open file descriptors and their state + -> signals state: [TBD] pending signals and signal handling state + -> credentials state: [TBD] user and group state, statistics + + +=== Checkpoint image format + +The checkpoint image format is composed of records consistings of a +pre-header that identifies its contents, followed by a payload. (The +idea here is to enable parallel checkpointing in the future in which +multiple threads interleave data from multiple processes into a single +stream). + +The pre-header is defined by "struct cr_hdr" as follows: + +struct cr_hdr { + __s16 type; + __s16 len; + __u32 parent; +}; + +Here, 'type' field identifies the type of the payload, 'len' tells its +length in bytes. The 'parent' identifies the owner object instance. The +meaning of the 'parent field varies depending on the type. For example, +for type CR_HDR_MM, the 'parent identifies the task to which this MM +belongs. The payload also varies depending on the type, for instance, +the data describing a task_struct is given by a 'struct cr_hdr_task' +(type CR_HDR_TASK) and so on. + +The format of the memory dump is as follows: for each VMA, there is a +'struct cr_vma'; if the VMA is file-mapped, it is followed by the file +name. Following comes the actual contents, in one or more chunk: each +chunk begins with a header that specifies how many pages it holds, +then a the virtual addresses of all the dumped pages in that chunk, +followed by the actual contents of all the dumped pages. A header with +zero number of pages marks the end of the contents for a particular +VMA. Then comes the next VMA and so on. + +To illustrate this, consider a single simple task with two VMAs: one +is file mapped with two dumped pages, and the other is anonymous with +three dumped pages. The checkpoint image will look like this: + +cr_hdr + cr_hdr_head +cr_hdr + cr_hdr_task + cr_hdr + cr_hdr_mm + cr_hdr + cr_hdr_vma + cr_hdr + string + cr_hdr_pgarr (nr_pages = 2) + addr1, addr2 + page1, page2 + cr_hdr_pgarr (nr_pages = 0) + cr_hdr + cr_hdr_vma + cr_hdr_pgarr (nr_pages = 3) + addr3, addr4, addr5 + page3, page4, page5 + cr_hdr_pgarr (nr_pages = 0) + cr_hdr + cr_mm_context + cr_hdr + cr_hdr_thread + cr_hdr + cr_hdr_cpu +cr_hdr + cr_hdr_tail + + +=== Current Implementation + +[2008-Oct-07] +There are several assumptions in the current implementation; they will +be gradually relaxed in future versions. The main ones are: +* A task can only checkpoint itself (missing "restart-block" logic). +* Namespaces are not saved or restored; They will be treated as a type + of shared object. +* In particular, it is assumed that the task's file system namespace + is the "root" for the entire container. +* It is assumed that the same file system view is available for the + restart task(s). Otherwise, a file system snapshot is required. + + +=== Sample code + +Two example programs: one uses checkpoint (called ckpt) to checkpoint +itself, and another uses restart (called rstr) to restart from that +checkpoint. Note the use of "dup2" to create a copy of an open file +and show how shared objects are treated. Execute like this: + +orenl:~/test$ ./ckpt > out.1 + <-- ctrl-c +orenl:~/test$ cat /tmp/cr-rest.out +hello, world! +world, hello! +(ret = 1) + +orenl:~/test$ ./ckpt > out.1 + <-- ctrl-c +orenl:~/test$ cat /tmp/cr-rest.out +hello, world! +world, hello! +(ret = 2) + + <-- now change the contents of the file +orenl:~/test$ sed -i 's/world, hello!/xxxx/' /tmp/cr-rest.out +orenl:~/test$ cat /tmp/cr-rest.out +hello, world! +xxxx +(ret = 2) + + <-- and do the restart +orenl:~/test$ ./rstr < out.1 + <-- ctrl-c +orenl:~/test$ cat /tmp/cr-rest.out +hello, world! +world, hello! +(ret = 0) + +(if you check the output of ps, you'll see that "rstr" changed its +name to "ckpt", as expected). + +============================== ckpt.c ================================ + +#define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <asm/unistd.h> +#include <sys/syscall.h> + +#define OUTFILE "/tmp/cr-test.out" + +int main(int argc, char *argv[]) +{ + pid_t pid = getpid(); + FILE *file; + int ret; + + close(0); + close(2); + + unlink(OUTFILE); + file = fopen(OUTFILE, "w+"); + if (!file) { + perror("open"); + exit(1); + } + + if (dup2(0,2) < 0) { + perror("dups"); + exit(1); + } + + fprintf(file, "hello, world!\n"); + fflush(file); + + ret = syscall(__NR_checkpoint, pid, STDOUT_FILENO, 0); + if (ret < 0) { + perror("checkpoint"); + exit(2); + } + + fprintf(file, "world, hello!\n"); + fprintf(file, "(ret = %d)\n", ret); + fflush(file); + + 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.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; +} +====================================================================== + + +=== Changelog + +[2008-Oct-07] v6: + - Balance all calls to cr_hbuf_get() with matching cr_hbuf_put() + (even though it's not really needed) + - Add 'current implementation' to docs to describe assumptions + - Misc fixes and cleanups + +[2008-Sep-11] v5: + - Config is 'def_bool n' by default + - Improve memory dump/restore code (following Dave Hansen's comments) + - Change dump format (and code) to allow chunks of <vaddrs, pages> + instead of one long list of each + - Fix use of follow_page() to avoid faulting in non-present pages + - Memory restore now maps user pages explicitly to copy data into them, + instead of reading directly to user space; got rid of mprotect_fixup() + - Remove preempt_disable() when restoring debug registers + - Rename headers files s/ckpt/checkpoint/ + - Fix misc bugs in files dump/restore + - Fix cleanup on some error paths + - Fix misc coding style + +[2008-Sep-04] v4: + - Fix calculation of hash table size + - Fix header structure alignment + - Use stand list_... for cr_pgarr + +[2008-Aug-20] v3: + - Various fixes and clean-ups + - Use standard hlist_... for hash table + - Better use of standard kmalloc/kfree + +[2008-Aug-09] v2: + - Added utsname->{release,version,machine} to checkpoint header + - Pad header structures to 64 bits to ensure compatibility + - Address comments from LKML and linux-containers mailing list + +[2008-Jul-29] v1: +In this incarnation, CR only works on single task. The address space +may consist of only private, simple VMAs - anonymous or file-mapped. +Both checkpoint and restart will ignore the first argument (pid/crid) +and instead act on themselves.
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 6/9 Checkpoint/restart: initial documentation
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Covers application checkpoint/restart, overall design, interfaces and checkpoint image format.
---
linux-2.6.git-dave/Documentation/checkpoint.txt | 370 ++++++++++++++++++++++++ 1 file changed, 370 insertions(+)
Documentation/checkpoint.txt new file +370 -0
@@ -0,0 +1,370 @@ + + === Checkpoint-Restart support in the Linux kernel === + +Copyright (C) 2008 Oren Laadan + +Author: Oren Laadan <[email protected]> + +License: The GNU Free Documentation License, Version 1.2 + (dual licensed under the GPL v2) +Reviewers: + +Application checkpoint/restart [CR] is the ability to save the state +of a running application so that it can later resume its execution +from the time at which it was checkpointed. An application can be +migrated by checkpointing it on one machine and restarting it on +another. CR can provide many potential benefits: + +* Failure recovery: by rolling back an to a previous checkpoint + +* Improved response time: by restarting applications from checkpoints + instead of from scratch. + +* Improved system utilization: by suspending long running CPU + intensive jobs and resuming them when load decreases. + +* Fault resilience: by migrating applications off of faulty hosts. + +* Dynamic load balancing: by migrating applications to less loaded + hosts. + +* Improved service availability and administration: by migrating + applications before host maintenance so that they continue to run + with minimal downtime + +* Time-travel: by taking periodic checkpoints and restarting from + any previous checkpoint. + + +=== Overall design + +Checkpoint and restart is done in the kernel as much as possible. The +kernel exports a relative opaque 'blob' of data to userspace which can +then be handed to the new kernel at restore time. The 'blob' contains +data and state of select portions of kernel structures such as VMAs +and mm_structs, as well as copies of the actual memory that the tasks +use. Any changes in this blob's format between kernel revisions can be +handled by an in-userspace conversion program. The approach is similar +to virtually all of the commercial CR products out there, as well as +the research project Zap. + +Two new system calls are introduced to provide CR: sys_checkpoint and +sys_restart. The checkpoint code basically serializes internal kernel +state and writes it out to a file descriptor, and the resulting image +is stream-able. More specifically, it consists of 5 steps: + 1. Pre-dump + 2. Freeze the container + 3. Dump + 4. Thaw (or kill) the container + 5. Post-dump +Steps 1 and 5 are an optimization to reduce application downtime: +"pre-dump" works before freezing the container, e.g. the pre-copy for +live migration, and "post-dump" works after the container resumes +execution, e.g. write-back the data to secondary storage. + +The restart code basically reads the saved kernel state and from a +file descriptor, and re-creates the tasks and the resources they need +to resume execution. The restart code is executed by each task that +is restored in a new container to reconstruct its own state. + + +=== Interfaces + +int sys_checkpoint(pid_t pid, int fd, unsigned long flag); + Checkpoint a container whose init task is identified by pid, to the + file designated by fd. Flags will have future meaning (should be 0 + for now). + Returns: a positive integer that identifies the checkpoint image + (for future reference in case it is kept in memory) upon success, + 0 if it returns from a restart, and -1 if an error occurs. + +int sys_restart(int crid, int fd, unsigned long flags); + Restart a container from a checkpoint image identified by crid, or + from the blob stored in the file designated by fd. Flags will have + future meaning (should be 0 for now). + Returns: 0 on success and -1 if an error occurs. + +Thus, if checkpoint is initiated by a process in the container, one +can use logic similar to fork(): + ... + crid = checkpoint(...); + switch (crid) { + case -1: + perror("checkpoint failed"); + break; + default: + fprintf(stderr, "checkpoint succeeded, CRID=%d\n", ret); + /* proceed with execution after checkpoint */ + ... + break; + case 0: + fprintf(stderr, "returned after restart\n"); + /* proceed with action required following a restart */ + ... + break; + } + ... +And to initiate a restart, the process in an empty container can use +logic similar to execve(): + ... + if (restart(crid, ...) < 0) + perror("restart failed"); + /* only get here if restart failed */ + ... + +See below a complete example in C. + + +=== Order of state dump + +The order of operations, both save and restore, is as following: + +* Header section: header, container information, etc. +* Global section: [TBD] global resources such as IPC, UTS, etc. +* Process forest: [TBD] tasks and their relationships +* Per task data (for each task): + -> task state: elements of task_struct + -> thread state: elements of thread_struct and thread_info + -> CPU state: registers etc, including FPU + -> memory state: memory address space layout and contents + -> filesystem state: [TBD] filesystem namespace state, chroot, cwd, etc + -> files state: open file descriptors and their state + -> signals state: [TBD] pending signals and signal handling state + -> credentials state: [TBD] user and group state, statistics + + +=== Checkpoint image format + +The checkpoint image format is composed of records consistings of a +pre-header that identifies its contents, followed by a payload. (The +idea here is to enable parallel checkpointing in the future in which +multiple threads interleave data from multiple processes into a single +stream). + +The pre-header is defined by "struct cr_hdr" as follows: + +struct cr_hdr { + __s16 type; + __s16 len; + __u32 parent; +}; + +Here, 'type' field identifies the type of the payload, 'len' tells its +length in bytes. The 'parent' identifies the owner object instance. The +meaning of the 'parent field varies depending on the type. For example, +for type CR_HDR_MM, the 'parent identifies the task to which this MM +belongs. The payload also varies depending on the type, for instance, +the data describing a task_struct is given by a 'struct cr_hdr_task' +(type CR_HDR_TASK) and so on. + +The format of the memory dump is as follows: for each VMA, there is a +'struct cr_vma'; if the VMA is file-mapped, it is followed by the file +name. Following comes the actual contents, in one or more chunk: each +chunk begins with a header that specifies how many pages it holds, +then a the virtual addresses of all the dumped pages in that chunk, +followed by the actual contents of all the dumped pages. A header with +zero number of pages marks the end of the contents for a particular +VMA. Then comes the next VMA and so on. + +To illustrate this, consider a single simple task with two VMAs: one +is file mapped with two dumped pages, and the other is anonymous with +three dumped pages. The checkpoint image will look like this: + +cr_hdr + cr_hdr_head +cr_hdr + cr_hdr_task + cr_hdr + cr_hdr_mm + cr_hdr + cr_hdr_vma + cr_hdr + string + cr_hdr_pgarr (nr_pages = 2) + addr1, addr2 + page1, page2 + cr_hdr_pgarr (nr_pages = 0) + cr_hdr + cr_hdr_vma + cr_hdr_pgarr (nr_pages = 3) + addr3, addr4, addr5 + page3, page4, page5 + cr_hdr_pgarr (nr_pages = 0) + cr_hdr + cr_mm_context + cr_hdr + cr_hdr_thread + cr_hdr + cr_hdr_cpu +cr_hdr + cr_hdr_tail + + +=== Current Implementation + +[2008-Oct-07] +There are several assumptions in the current implementation; they will +be gradually relaxed in future versions. The main ones are: +* A task can only checkpoint itself (missing "restart-block" logic). +* Namespaces are not saved or restored; They will be treated as a type + of shared object. +* In particular, it is assumed that the task's file system namespace + is the "root" for the entire container. +* It is assumed that the same file system view is available for the + restart task(s). Otherwise, a file system snapshot is required. + + +=== Sample code + +Two example programs: one uses checkpoint (called ckpt) to checkpoint +itself, and another uses restart (called rstr) to restart from that +checkpoint. Note the use of "dup2" to create a copy of an open file +and show how shared objects are treated. Execute like this: + +orenl:~/test$ ./ckpt > out.1 + <-- ctrl-c +orenl:~/test$ cat /tmp/cr-rest.out +hello, world! +world, hello! +(ret = 1) + +orenl:~/test$ ./ckpt > out.1 + <-- ctrl-c +orenl:~/test$ cat /tmp/cr-rest.out +hello, world! +world, hello! +(ret = 2) + + <-- now change the contents of the file +orenl:~/test$ sed -i 's/world, hello!/xxxx/' /tmp/cr-rest.out +orenl:~/test$ cat /tmp/cr-rest.out +hello, world! +xxxx +(ret = 2) + + <-- and do the restart +orenl:~/test$ ./rstr < out.1 + <-- ctrl-c +orenl:~/test$ cat /tmp/cr-rest.out +hello, world! +world, hello! +(ret = 0) + +(if you check the output of ps, you'll see that "rstr" changed its +name to "ckpt", as expected). + +============================== ckpt.c ================================ + +#define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <asm/unistd.h> +#include <sys/syscall.h> + +#define OUTFILE "/tmp/cr-test.out" + +int main(int argc, char *argv[]) +{ + pid_t pid = getpid(); + FILE *file; + int ret; + + close(0); + close(2); + + unlink(OUTFILE); + file = fopen(OUTFILE, "w+"); + if (!file) { + perror("open"); + exit(1); + } + + if (dup2(0,2) < 0) { + perror("dups"); + exit(1); + } + + fprintf(file, "hello, world!\n"); + fflush(file); + + ret = syscall(__NR_checkpoint, pid, STDOUT_FILENO, 0); + if (ret < 0) { + perror("checkpoint"); + exit(2); + } + + fprintf(file, "world, hello!\n"); + fprintf(file, "(ret = %d)\n", ret); + fflush(file); + + 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.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; +} +====================================================================== + + +=== Changelog + +[2008-Oct-07] v6: + - Balance all calls to cr_hbuf_get() with matching cr_hbuf_put() + (even though it's not really needed) + - Add 'current implementation' to docs to describe assumptions + - Misc fixes and cleanups + +[2008-Sep-11] v5: + - Config is 'def_bool n' by default + - Improve memory dump/restore code (following Dave Hansen's comments) + - Change dump format (and code) to allow chunks of <vaddrs, pages> + instead of one long list of each + - Fix use of follow_page() to avoid faulting in non-present pages + - Memory restore now maps user pages explicitly to copy data into them, + instead of reading directly to user space; got rid of mprotect_fixup() + - Remove preempt_disable() when restoring debug registers + - Rename headers files s/ckpt/checkpoint/ + - Fix misc bugs in files dump/restore + - Fix cleanup on some error paths + - Fix misc coding style + +[2008-Sep-04] v4: + - Fix calculation of hash table size + - Fix header structure alignment + - Use stand list_... for cr_pgarr + +[2008-Aug-20] v3: + - Various fixes and clean-ups + - Use standard hlist_... for hash table + - Better use of standard kmalloc/kfree + +[2008-Aug-09] v2: + - Added utsname->{release,version,machine} to checkpoint header + - Pad header structures to 64 bits to ensure compatibility + - Address comments from LKML and linux-containers mailing list + +[2008-Jul-29] v1: +In this incarnation, CR only works on single task. The address space +may consist of only private, simple VMAs - anonymous or file-mapped. +Both checkpoint and restart will ignore the first argument (pid/crid) +and instead act on themselves.
_
PATCH 7/9 Infrastructure for shared objects
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Infrastructure to handle objects that may be shared and referenced by multiple tasks or other objects, e..g open files, memory address space etc.
The state of shared objects is saved once. On the first encounter, the state is dumped and the object is assigned a unique identifier (objref) and also stored in a hash table (indexed by its physical kenrel address). From then on the object will be found in the hash and only its identifier is saved.
On restart the identifier is looked up in the hash table; if not found then the state is read, the object is created, and added to the hash table (this time indexed by its identifier). Otherwise, the object in the hash table is used.
---
linux-2.6.git-dave/Documentation/checkpoint.txt | 46 ++++ linux-2.6.git-dave/checkpoint/Makefile | 2 linux-2.6.git-dave/checkpoint/objhash.c | 268 ++++++++++++++++++++++++ linux-2.6.git-dave/checkpoint/sys.c | 6 linux-2.6.git-dave/include/linux/checkpoint.h | 20 + 5 files changed, 341 insertions(+), 1 deletion(-)
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_7_9_Infrastructure_for_shared_objects +1 -1
@@ -2,5 +2,5 @@ # Makefile for linux checkpoint/restart. # -obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o objhash.o \ ckpt_mem.o rstr_mem.o
checkpoint/objhash.c new file +268 -0
268 lines not on this page · raw message
checkpoint/sys.c renamed from checkpoint/sys.c~v6_PATCH_7_9_Infrastructure_for_shared_objects +6 -0
@@ -167,6 +167,7 @@ void cr_ctx_free(struct cr_ctx *ctx)path_put (ctx->vfsroot);cr_pgarr_free (ctx); +cr_objhash_free (ctx);kfree (ctx); }
@@ -191,6 +192,11 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, ireturn ERR_PTR (-ENOMEM ); } +if (cr_objhash_alloc (ctx) <0 ) { +cr_ctx_free (ctx); +return ERR_PTR (-ENOMEM ); + } +/* * assume checkpointer is in container's root vfs * FIXME: this works for now, but will change with real containers
Documentation/checkpoint.txt renamed from Documentation/checkpoint.txt~v6_PATCH_7_9_Infrastructure_for_shared_objects +46 -0
52 lines not on this page · raw message
include/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_7_9_Infrastructure_for_shared_objects +20 -0
@@ -28,6 +28,8 @@ struct cr_ctx {void *hbuf;/* temporary buffer for headers */ int hpos;/* position in headers buffer */ +struct cr_objhash *objhash;/* hash for shared objects */ +struct list_head pgarr_list;/* page array to dump VMA contents */ struct path *vfsroot;/* container root (FIXME) */
@@ -45,6 +47,24 @@ extern int cr_kread(struct cr_ctx *ctx,extern void *cr_hbuf_get (struct cr_ctx *ctx,int n);extern void cr_hbuf_put (struct cr_ctx *ctx,int n); +/* shared objects handling */ + +enum { +CR_OBJ_FILE =1 , +CR_OBJ_MAX +}; + +extern void cr_objhash_free (struct cr_ctx *ctx); +extern int cr_objhash_alloc (struct cr_ctx *ctx); +extern void *cr_obj_get_by_ref (struct cr_ctx *ctx, +int objref,unsigned short type); +extern int cr_obj_get_by_ptr (struct cr_ctx *ctx, +void *ptr,unsigned short type); +extern int cr_obj_add_ptr (struct cr_ctx *ctx,void *ptr,int *objref, +unsigned short type,unsigned short flags); +extern int cr_obj_add_ref (struct cr_ctx *ctx,void *ptr,int objref, +unsigned short type,unsigned short flags); +struct cr_hdr ;extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf);
_
PATCH 7/9 Infrastructure for shared objects
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Infrastructure to handle objects that may be shared and referenced by multiple tasks or other objects, e..g open files, memory address space etc.
The state of shared objects is saved once. On the first encounter, the state is dumped and the object is assigned a unique identifier (objref) and also stored in a hash table (indexed by its physical kenrel address).
Quoted 1 line
From then on the object will be found in the hash and only its identifier
is saved.
On restart the identifier is looked up in the hash table; if not found then the state is read, the object is created, and added to the hash table (this time indexed by its identifier). Otherwise, the object in the hash table is used.
---
linux-2.6.git-dave/Documentation/checkpoint.txt | 46 ++++ linux-2.6.git-dave/checkpoint/Makefile | 2 linux-2.6.git-dave/checkpoint/objhash.c | 268 ++++++++++++++++++++++++ linux-2.6.git-dave/checkpoint/sys.c | 6 linux-2.6.git-dave/include/linux/checkpoint.h | 20 + 5 files changed, 341 insertions(+), 1 deletion(-)
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_7_9_Infrastructure_for_shared_objects +1 -1
@@ -2,5 +2,5 @@ # Makefile for linux checkpoint/restart. # -obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o \ +obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o objhash.o \ ckpt_mem.o rstr_mem.o
checkpoint/objhash.c new file +268 -0
268 lines not on this page · raw message
checkpoint/sys.c renamed from checkpoint/sys.c~v6_PATCH_7_9_Infrastructure_for_shared_objects +6 -0
@@ -167,6 +167,7 @@ void cr_ctx_free(struct cr_ctx *ctx)path_put (ctx->vfsroot);cr_pgarr_free (ctx); +cr_objhash_free (ctx);kfree (ctx); }
@@ -191,6 +192,11 @@ struct cr_ctx *cr_ctx_alloc(pid_t pid, ireturn ERR_PTR (-ENOMEM ); } +if (cr_objhash_alloc (ctx) <0 ) { +cr_ctx_free (ctx); +return ERR_PTR (-ENOMEM ); + } +/* * assume checkpointer is in container's root vfs * FIXME: this works for now, but will change with real containers
Documentation/checkpoint.txt renamed from Documentation/checkpoint.txt~v6_PATCH_7_9_Infrastructure_for_shared_objects +46 -0
52 lines not on this page · raw message
include/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_7_9_Infrastructure_for_shared_objects +20 -0
@@ -28,6 +28,8 @@ struct cr_ctx {void *hbuf;/* temporary buffer for headers */ int hpos;/* position in headers buffer */ +struct cr_objhash *objhash;/* hash for shared objects */ +struct list_head pgarr_list;/* page array to dump VMA contents */ struct path *vfsroot;/* container root (FIXME) */
@@ -45,6 +47,24 @@ extern int cr_kread(struct cr_ctx *ctx,extern void *cr_hbuf_get (struct cr_ctx *ctx,int n);extern void cr_hbuf_put (struct cr_ctx *ctx,int n); +/* shared objects handling */ + +enum { +CR_OBJ_FILE =1 , +CR_OBJ_MAX +}; + +extern void cr_objhash_free (struct cr_ctx *ctx); +extern int cr_objhash_alloc (struct cr_ctx *ctx); +extern void *cr_obj_get_by_ref (struct cr_ctx *ctx, +int objref,unsigned short type); +extern int cr_obj_get_by_ptr (struct cr_ctx *ctx, +void *ptr,unsigned short type); +extern int cr_obj_add_ptr (struct cr_ctx *ctx,void *ptr,int *objref, +unsigned short type,unsigned short flags); +extern int cr_obj_add_ref (struct cr_ctx *ctx,void *ptr,int objref, +unsigned short type,unsigned short flags); +struct cr_hdr ;extern int cr_write_obj (struct cr_ctx *ctx,struct cr_hdr *h,void *buf);
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 8/9 Dump open file descriptors
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Dump the files_struct of a task with 'struct cr_hdr_files', followed by all open file descriptors. Since FDs can be shared, they are assigned an objref and registered in the object hash.
For each open FD there is a 'struct cr_hdr_fd_ent' with the FD, its objref and its close-on-exec property. If the FD is to be saved (first time) then this is followed by a 'struct cr_hdr_fd_data' with the FD state. Then will come the next FD and so on.
This patch only handles basic FDs - regular files, directories and also symbolic links.
---
linux-2.6.git-dave/checkpoint/Makefile | 2 linux-2.6.git-dave/checkpoint/checkpoint.c | 4 linux-2.6.git-dave/checkpoint/checkpoint_file.h | 17 + linux-2.6.git-dave/checkpoint/ckpt_file.c | 231 ++++++++++++++++++++++ linux-2.6.git-dave/include/linux/checkpoint.h | 7 linux-2.6.git-dave/include/linux/checkpoint_hdr.h | 32 ++- 6 files changed, 288 insertions(+), 5 deletions(-)
checkpoint/checkpoint.c renamed from checkpoint/checkpoint.c~v6_PATCH_8_9_Dump_open_file_descriptors +4 -0
@@ -203,6 +203,10 @@ static int cr_write_task(struct cr_ctx *cr_debug ("memory: ret %d\n" , ret);if (ret <0 ) goto out; + ret =cr_write_files (ctx, t); +cr_debug ("files: ret %d\n" , ret); +if (ret <0 ) + goto out; ret =cr_write_thread (ctx, t);cr_debug ("thread: ret %d\n" , ret);if (ret <0 )
checkpoint/checkpoint_file.h new file +17 -0
@@ -0,0 +1,17 @@ +#ifndef _CHECKPOINT_CKPT_FILE_H_ +#define _CHECKPOINT_CKPT_FILE_H_ +/* +* Checkpoint file descriptors +* +* 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/fdtable.h> + +int cr_scan_fds (struct files_struct *files,int **fdtable); + +#endif /* _CHECKPOINT_CKPT_FILE_H_ */
checkpoint/ckpt_file.c new file +231 -0
231 lines not on this page · raw message
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_8_9_Dump_open_file_descriptors +1 -1
@@ -3,4 +3,4 @@ # obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o objhash.o \ - ckpt_mem.o rstr_mem.o + ckpt_mem.o rstr_mem.o ckpt_file.o
include/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_8_9_Dump_open_file_descriptors +4 -3
@@ -13,7 +13,7 @@#include <linux/path.h> #include <linux/fs.h> -#define CR_VERSION 1 +#define CR_VERSION 2struct cr_ctx {pid_t pid;/* container identifier */
@@ -79,11 +79,12 @@ extern int cr_read_fname(struct cr_ctx *extern struct file *cr_read_open_fname (struct cr_ctx *ctx,int flags,int mode); +extern int do_checkpoint (struct cr_ctx *ctx);extern int cr_write_mm (struct cr_ctx *ctx,struct task_struct *t); -extern int cr_read_mm (struct cr_ctx *ctx); +extern int cr_write_files (struct cr_ctx *ctx,struct task_struct *t); -extern int do_checkpoint (struct cr_ctx *ctx);extern int do_restart (struct cr_ctx *ctx); +extern int cr_read_mm (struct cr_ctx *ctx);/* there are from fs/read_write.c, not exported otherwise in a header */ extern loff_t file_pos_read (struct file *file);
include/linux/checkpoint_hdr.h renamed from include/linux/checkpoint_hdr.h~v6_PATCH_8_9_Dump_open_file_descriptors +31 -1
@@ -17,7 +17,7 @@/* * To maintain compatibility between 32-bit and 64-bit architecture flavors, * keep data 64-bit aligned: use padding for structure members, and use -* __attribute__ ((aligned (8))) for the entire structure. +* __attribute__((aligned(8))) for the entire structure. */ /* records: generic header */
@@ -43,6 +43,10 @@ enum {CR_HDR_PGARR ,CR_HDR_MM_CONTEXT , +CR_HDR_FILES =301 , +CR_HDR_FD_ENT , +CR_HDR_FD_DATA , + CR_HDR_TAIL = 5001 };
@@ -105,4 +109,30 @@ struct cr_hdr_pgarr {__u64 nr_pages;/* number of pages to saved */ } __attribute__((aligned(8))); +struct cr_hdr_files { +__u32 objref;/* identifier for shared objects */ +__u32 nfds; +} __attribute__((aligned (8 ))); + +struct cr_hdr_fd_ent { +__u32 objref;/* identifier for shared objects */ +__s32 fd; +__u32 close_on_exec; +} __attribute__((aligned (8 ))); + +/* fd types */ +enum fd_type { +CR_FD_FILE =1 , +CR_FD_DIR , +CR_FD_LINK +}; + +struct cr_hdr_fd_data { +__u16 fd_type; +__u16 f_mode; +__u32 f_flags; +__u64 f_pos; +__u64 f_version; +} __attribute__((aligned (8 ))); +#endif /* _CHECKPOINT_CKPT_HDR_H_ */
_
PATCH 9/9 Restore open file descriprtors
In reply to Dave HansenFrom: Oren Laadan <[email protected]>
Restore open file descriptors: for each FD read 'struct cr_hdr_fd_ent' and lookup objref in the hash table; if not found (first occurence), read in 'struct cr_hdr_fd_data', create a new FD and register in the hash. Otherwise attach the file pointer from the hash as an FD.
This patch only handles basic FDs - regular files, directories and also symbolic links.
---
linux-2.6.git-dave/checkpoint/Makefile | 2 linux-2.6.git-dave/checkpoint/restart.c | 4 linux-2.6.git-dave/checkpoint/rstr_file.c | 246 ++++++++++++++++++++++++++ linux-2.6.git-dave/include/linux/checkpoint.h | 1 4 files changed, 252 insertions(+), 1 deletion(-)
checkpoint/Makefile renamed from checkpoint/Makefile~v6_PATCH_9_9_Restore_open_file_descriprtors +1 -1
@@ -3,4 +3,4 @@ # obj-$(CONFIG_CHECKPOINT_RESTART) += sys.o checkpoint.o restart.o objhash.o \ - ckpt_mem.o rstr_mem.o ckpt_file.o + ckpt_mem.o rstr_mem.o ckpt_file.o rstr_file.o
checkpoint/restart.c renamed from checkpoint/restart.c~v6_PATCH_9_9_Restore_open_file_descriprtors +4 -0
@@ -219,6 +219,10 @@ static int cr_read_task(struct cr_ctx *ccr_debug ("memory: ret %d\n" , ret);if (ret <0 ) goto out; + ret =cr_read_files (ctx); +cr_debug ("files: ret %d\n" , ret); +if (ret <0 ) + goto out; ret =cr_read_thread (ctx);cr_debug ("thread: ret %d\n" , ret);if (ret <0 )
checkpoint/rstr_file.c new file +246 -0
246 lines not on this page · raw message
include/linux/checkpoint.h renamed from include/linux/checkpoint.h~v6_PATCH_9_9_Restore_open_file_descriprtors +1 -0
@@ -85,6 +85,7 @@ extern int cr_write_files(struct cr_ctxextern int do_restart (struct cr_ctx *ctx);extern int cr_read_mm (struct cr_ctx *ctx); +extern int cr_read_files (struct cr_ctx *ctx);/* there are from fs/read_write.c, not exported otherwise in a header */ extern loff_t file_pos_read (struct file *file);
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>