diff --git a/INTERNALS b/INTERNALS deleted file mode 100644 index d1eecd6c7..000000000 --- a/INTERNALS +++ /dev/null @@ -1,145 +0,0 @@ -crtools internals -================= - - -What CRtools is ---------------- -In short -- crtools is an utility to checkpoint/restore (CR) processes. Unlike CR -implemented completely in kernel space, it tries to achieve the same goal opreating -in user space. - -Since this tool (and overall concept) is under heavily development stage, there are -some known limitations - - - Only pure x86-64 environment is supported, no IA32 emulation. - - There is no way to use cgroups freezer facility. - - No network or IPC CR supported. - -At moment CR of the following resources are supported - - - Process tree - - Files (with some limitations) - - Pipes - - Memory - - -Basic design ------------- - -Checkpoint -~~~~~~~~~~ - -Checkpoint procedure relies on /proc file system (it's a general place -where crtools takes all the information needed). Which includes - - - File descriptors (via /proc/$pid/fd and /proc/$pid/fdinfo). - - Pipes parameters. - - Memory maps (via /proc/$pid/maps). - -Process dumper (lets call it "dumper") does the following steps during -checkpoint stage - - - A $pid of a process group leader is obtained from the command line. - - - By using this $pid the dumper walks though /proc/$pid/status and gathers - children $pid's recursively. At the end we will have a complete process tree. - - - Then it takes every $pid from a process tree, sends SIGSTOP to the every process - found and performs the following steps on each $pid - - - Collects VMA areas by parsing /proc/$pid/maps. - - - Seizes a task via relatively new ptrace interface. Seizing a task means to - put it into a special state when the task have no idea if it's being operated - by the ptrace. - - - Core parameters of a task (such as registers and friends) are being dumped via - ptrace interface and parsing the /proc/$pid/stat entry. - - - The dumper injects a parasite code into a task via ptrace interface. This allows - us to dump pages of a task right from within the task's address space. - An injection procedure is pretty simple one - - - The dumper scans executable VMA areas of a task (which were previously collected) - and tests if there a place for a few instructions. - - - Then (by ptrace as well) it substitutes an original code with new instructions - and creates a new VMA area inside process address space. - - - Finally parasite code get copied into the new VMA and the former code which was - being modified during the parasite bootstrap procedure -- restored. - - - Then the dumper flushes contents of a task's pages to a file, and drops out - the parasite code block completely, since we don't need it anymore. - - - Once the parasite code removed a task get unseized via ptrace call but remains - stopped still. - - - The dumper writes out parameters of opened files and pipes (flushing data on disk - if needed). - - - SIGCONT is sent to every task in the process tree (to continue execution). - -Restore -~~~~~~~ - -Restore procedure (aka restorer) proceed by the following steps - - - The process tree read from a file. - - - To restore the process tree the restorer executes clone(CLONE_CHILD_USEPID) - syscall which creates a process with $pid specified. Note if for some reason - you already have a process with the same $pid up and running, the restoration - procedure will refuse to proceed. - - - Files and pipes are restored (ie opened with file descriptors they had at - checkpoint time and positioned exactly as they were before. In case if the pipe - had some data buffered before checkpoint -- data will be sent back to the pipe). - - - Restoration of virtual memory (and memory pages) is a bit tricky and implemented - by the following steps - - - The restorer analyzes the current VMA map by parsing /proc/$pid/maps file. - - - Since we are to create completely new memory map the restorer enumerates - all VMA entries and figures out where is the place (or hole) between VMAs - which could be big enough to hold all code and parameters needed for the - rest of the restore procedure. - - - Once such area found the restorer copies own code and data to a new place. - - - Then the restorer pass execution there, which in turn does - - - Unmaps current active VMAs and maps areas the process had at - the checkpoint time. - - - Reads pages contents back to newly mapped memory. - - - Prepares rt-sigreturn frame on stack and yields __NR_rt_sigreturn - syscall, so in result the process start execution from the former - IP it had at checkpoint time. - - -Kernel area ------------ - -While CR is implemented in user-space still some help from the Linux kernel -is needed, so the following patches are needed - - - New directory /proc/$pid/map_files, which allows the CR to find and restore - anonymous shared memory areas. - - - Explicit "Children:" line in /proc/$pid/stat file added. This simplifies code - significantly (and kernel already has this information but simply not yet - exported). - - - An ability to call clone() with specified $pid. - - - start_data, end_data and a few more members of mm_struct. - - - Export added to /proc/$pid/stat. - - - Import implemented via new prctl codes. - - - An ability to map vDSO at predefined address (implemented via - new prctl code as well). diff --git a/README b/README index 70db238aa..7aaf0c81b 100644 --- a/README +++ b/README @@ -17,28 +17,16 @@ Licensed under GPLv2 (http://www.gnu.org/licenses/gpl-2.0.txt) Kernel patching =============== -To have crtools up and running either +To have crtools up and running clone -1) use patches from kernel/ directory -2) or clone git://github.com/cyrillos/linux-2.6.git - and switch to branch "crtools". Note these patches - are guaranteed to be up to date only with major - release of crtool. If you're testing development - version -- make sure you're applying series from - kernel/ directory. + git://github.com/cyrillos/linux-2.6.git + +and switch to branch "crtools". It's based on Linux - | commit 1ea6b8f48918282bdca0b32a34095504ee65bab5 - | Author: Linus Torvalds - | Date: Mon Nov 7 16:16:02 2011 -0800 - | - | Linux 3.2-rc1 - -The following patches are already in -mm tree - -fs-proc-Make-proc_get_link-to-use-dentry -fs-proc-Introduce-the-proc-pid-map_files-directory -procfs-introduce-the-proc-pid-map_files-directory-checkpatch -sysfs-add-kernel.ns_last_pid +commit 384703b8e6cd4c8ef08512e596024e028c91c339 +Author: Linus Torvalds +Date: Fri Dec 16 18:36:26 2011 -0800 + Linux 3.2-rc6 diff --git a/kernel/c-r-introduce-checkpoint_restore-symbol.patch b/kernel/c-r-introduce-checkpoint_restore-symbol.patch deleted file mode 100644 index 6358af617..000000000 --- a/kernel/c-r-introduce-checkpoint_restore-symbol.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Cyrill Gorcunov -Subject: c/r: introduce CHECKPOINT_RESTORE symbol - -For checkpoint/restore we need auxilary features being compiled into the -kernel, such as additional prctl codes, /proc//map_files and etc... -but same time these features are not mandatory for a regular kernel so -CHECKPOINT_RESTORE config symbol should bring a way to disable them all at -once if one wish to get rid of additional functionality. - -Signed-off-by: Cyrill Gorcunov -Cc: Tejun Heo -Cc: Andrew Vagin -Cc: Serge Hallyn -Cc: Vasiliy Kulikov -Reviewed-by: Kees Cook -Cc: KAMEZAWA Hiroyuki -Cc: Alexey Dobriyan -Cc: "Eric W. Biederman" -Signed-off-by: Andrew Morton ---- - - init/Kconfig | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -Index: linux-2.6.git/init/Kconfig -=================================================================== ---- linux-2.6.git.orig/init/Kconfig -+++ linux-2.6.git/init/Kconfig -@@ -773,6 +773,17 @@ config DEBUG_BLK_CGROUP - - endif # CGROUPS - -+config CHECKPOINT_RESTORE -+ bool "Checkpoint/restore support" if EXPERT -+ default n -+ help -+ Enables additional kernel features in a sake of checkpoint/restore. -+ In particular it adds auxiliary prctl codes to setup process text, -+ data and heap segment sizes, and a few additional /proc filesystem -+ entries. -+ -+ If unsure, say N here. -+ - menuconfig NAMESPACES - bool "Namespaces support" if EXPERT - default !EXPERT diff --git a/kernel/c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries-fix.patch b/kernel/c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries-fix.patch deleted file mode 100644 index 59a35afb6..000000000 --- a/kernel/c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries-fix.patch +++ /dev/null @@ -1,117 +0,0 @@ -From: Andrew Morton -Subject: c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries-fix - -cache current->mm in a local, saving 200 bytes text - -Cc: Andrew Vagin -Cc: Cyrill Gorcunov -Cc: KAMEZAWA Hiroyuki -Cc: Kees Cook -Cc: Michael Kerrisk -Cc: Pavel Emelyanov -Cc: Serge Hallyn -Cc: Tejun Heo -Cc: Vasiliy Kulikov -Signed-off-by: Andrew Morton ---- - - kernel/sys.c | 33 +++++++++++++++++---------------- - 1 file changed, 17 insertions(+), 16 deletions(-) - -Index: linux-2.6.git/kernel/sys.c -=================================================================== ---- linux-2.6.git.orig/kernel/sys.c -+++ linux-2.6.git/kernel/sys.c -@@ -1701,6 +1701,7 @@ static int prctl_set_mm(int opt, unsigne - unsigned long vm_bad_flags; - struct vm_area_struct *vma; - int error = 0; -+ struct mm_struct *mm = current->mm; - - if (arg4 | arg5) - return -EINVAL; -@@ -1711,8 +1712,8 @@ static int prctl_set_mm(int opt, unsigne - if (addr >= TASK_SIZE) - return -EINVAL; - -- down_read(¤t->mm->mmap_sem); -- vma = find_vma(current->mm, addr); -+ down_read(&mm->mmap_sem); -+ vma = find_vma(mm, addr); - - if (opt != PR_SET_MM_START_BRK && opt != PR_SET_MM_BRK) { - /* It must be existing VMA */ -@@ -1732,9 +1733,9 @@ static int prctl_set_mm(int opt, unsigne - goto out; - - if (opt == PR_SET_MM_START_CODE) -- current->mm->start_code = addr; -+ mm->start_code = addr; - else -- current->mm->end_code = addr; -+ mm->end_code = addr; - break; - - case PR_SET_MM_START_DATA: -@@ -1747,9 +1748,9 @@ static int prctl_set_mm(int opt, unsigne - goto out; - - if (opt == PR_SET_MM_START_DATA) -- current->mm->start_data = addr; -+ mm->start_data = addr; - else -- current->mm->end_data = addr; -+ mm->end_data = addr; - break; - - case PR_SET_MM_START_STACK: -@@ -1762,31 +1763,31 @@ static int prctl_set_mm(int opt, unsigne - if ((vma->vm_flags & vm_req_flags) != vm_req_flags) - goto out; - -- current->mm->start_stack = addr; -+ mm->start_stack = addr; - break; - - case PR_SET_MM_START_BRK: -- if (addr <= current->mm->end_data) -+ if (addr <= mm->end_data) - goto out; - - if (rlim < RLIM_INFINITY && -- (current->mm->brk - addr) + -- (current->mm->end_data - current->mm->start_data) > rlim) -+ (mm->brk - addr) + -+ (mm->end_data - mm->start_data) > rlim) - goto out; - -- current->mm->start_brk = addr; -+ mm->start_brk = addr; - break; - - case PR_SET_MM_BRK: -- if (addr <= current->mm->end_data) -+ if (addr <= mm->end_data) - goto out; - - if (rlim < RLIM_INFINITY && -- (addr - current->mm->start_brk) + -- (current->mm->end_data - current->mm->start_data) > rlim) -+ (addr - mm->start_brk) + -+ (mm->end_data - mm->start_data) > rlim) - goto out; - -- current->mm->brk = addr; -+ mm->brk = addr; - break; - - default: -@@ -1797,7 +1798,7 @@ static int prctl_set_mm(int opt, unsigne - error = 0; - - out: -- up_read(¤t->mm->mmap_sem); -+ up_read(&mm->mmap_sem); - - return error; - } diff --git a/kernel/c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries.patch b/kernel/c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries.patch deleted file mode 100644 index 1c1d4df09..000000000 --- a/kernel/c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries.patch +++ /dev/null @@ -1,205 +0,0 @@ -From: Cyrill Gorcunov -Subject: c/r: prctl: add PR_SET_MM codes to set up mm_struct entries - -When we restore a task we need to set up text, data and data heap sizes -from userspace to the values a task had at checkpoint time. This patch -adds auxilary prctl codes for that. - -While most of them have a statistical nature (their values are involved -into calculation of /proc//statm output) the start_brk and brk values -are used to compute an allowed size of program data segment expansion. -Which means an arbitrary changes of this values might be dangerous -operation. So to restrict access the following requirements applied to -prctl calls: - - - The process has to have CAP_SYS_ADMIN capability granted. - - For all opcodes except start_brk/brk members an appropriate - VMA area must exist and should fit certain VMA flags, - such as: - - code segment must be executable but not writable; - - data segment must not be executable. - -start_brk/brk values must not intersect with data segment and must not -exceed RLIMIT_DATA resource limit. - -Still the main guard is CAP_SYS_ADMIN capability check. - -Note the kernel should be compiled with CONFIG_CHECKPOINT_RESTORE support -otherwise these prctl calls will return -EINVAL. - -Signed-off-by: Cyrill Gorcunov -Cc: Andrew Morton -Reviewed-by: Kees Cook -Cc: Tejun Heo -Cc: Andrew Vagin -Cc: Serge Hallyn -Cc: Pavel Emelyanov -Cc: Vasiliy Kulikov -Cc: KAMEZAWA Hiroyuki -Cc: Michael Kerrisk -Signed-off-by: Andrew Morton ---- - - include/linux/prctl.h | 12 +++++ - kernel/sys.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 132 insertions(+) - -Index: linux-2.6.git/include/linux/prctl.h -=================================================================== ---- linux-2.6.git.orig/include/linux/prctl.h -+++ linux-2.6.git/include/linux/prctl.h -@@ -102,4 +102,16 @@ - - #define PR_MCE_KILL_GET 34 - -+/* -+ * Tune up process memory map specifics. -+ */ -+#define PR_SET_MM 35 -+# define PR_SET_MM_START_CODE 1 -+# define PR_SET_MM_END_CODE 2 -+# define PR_SET_MM_START_DATA 3 -+# define PR_SET_MM_END_DATA 4 -+# define PR_SET_MM_START_STACK 5 -+# define PR_SET_MM_START_BRK 6 -+# define PR_SET_MM_BRK 7 -+ - #endif /* _LINUX_PRCTL_H */ -Index: linux-2.6.git/kernel/sys.c -=================================================================== ---- linux-2.6.git.orig/kernel/sys.c -+++ linux-2.6.git/kernel/sys.c -@@ -1692,6 +1692,123 @@ SYSCALL_DEFINE1(umask, int, mask) - return mask; - } - -+#ifdef CONFIG_CHECKPOINT_RESTORE -+static int prctl_set_mm(int opt, unsigned long addr, -+ unsigned long arg4, unsigned long arg5) -+{ -+ unsigned long rlim = rlimit(RLIMIT_DATA); -+ unsigned long vm_req_flags; -+ unsigned long vm_bad_flags; -+ struct vm_area_struct *vma; -+ int error = 0; -+ -+ if (arg4 | arg5) -+ return -EINVAL; -+ -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ -+ if (addr >= TASK_SIZE) -+ return -EINVAL; -+ -+ down_read(¤t->mm->mmap_sem); -+ vma = find_vma(current->mm, addr); -+ -+ if (opt != PR_SET_MM_START_BRK && opt != PR_SET_MM_BRK) { -+ /* It must be existing VMA */ -+ if (!vma || vma->vm_start > addr) -+ goto out; -+ } -+ -+ error = -EINVAL; -+ switch (opt) { -+ case PR_SET_MM_START_CODE: -+ case PR_SET_MM_END_CODE: -+ vm_req_flags = VM_READ | VM_EXEC; -+ vm_bad_flags = VM_WRITE | VM_MAYSHARE; -+ -+ if ((vma->vm_flags & vm_req_flags) != vm_req_flags || -+ (vma->vm_flags & vm_bad_flags)) -+ goto out; -+ -+ if (opt == PR_SET_MM_START_CODE) -+ current->mm->start_code = addr; -+ else -+ current->mm->end_code = addr; -+ break; -+ -+ case PR_SET_MM_START_DATA: -+ case PR_SET_MM_END_DATA: -+ vm_req_flags = VM_READ | VM_WRITE; -+ vm_bad_flags = VM_EXEC | VM_MAYSHARE; -+ -+ if ((vma->vm_flags & vm_req_flags) != vm_req_flags || -+ (vma->vm_flags & vm_bad_flags)) -+ goto out; -+ -+ if (opt == PR_SET_MM_START_DATA) -+ current->mm->start_data = addr; -+ else -+ current->mm->end_data = addr; -+ break; -+ -+ case PR_SET_MM_START_STACK: -+ -+#ifdef CONFIG_STACK_GROWSUP -+ vm_req_flags = VM_READ | VM_WRITE | VM_GROWSUP; -+#else -+ vm_req_flags = VM_READ | VM_WRITE | VM_GROWSDOWN; -+#endif -+ if ((vma->vm_flags & vm_req_flags) != vm_req_flags) -+ goto out; -+ -+ current->mm->start_stack = addr; -+ break; -+ -+ case PR_SET_MM_START_BRK: -+ if (addr <= current->mm->end_data) -+ goto out; -+ -+ if (rlim < RLIM_INFINITY && -+ (current->mm->brk - addr) + -+ (current->mm->end_data - current->mm->start_data) > rlim) -+ goto out; -+ -+ current->mm->start_brk = addr; -+ break; -+ -+ case PR_SET_MM_BRK: -+ if (addr <= current->mm->end_data) -+ goto out; -+ -+ if (rlim < RLIM_INFINITY && -+ (addr - current->mm->start_brk) + -+ (current->mm->end_data - current->mm->start_data) > rlim) -+ goto out; -+ -+ current->mm->brk = addr; -+ break; -+ -+ default: -+ error = -EINVAL; -+ goto out; -+ } -+ -+ error = 0; -+ -+out: -+ up_read(¤t->mm->mmap_sem); -+ -+ return error; -+} -+#else /* CONFIG_CHECKPOINT_RESTORE */ -+static int prctl_set_mm(int opt, unsigned long addr, -+ unsigned long arg4, unsigned long arg5) -+{ -+ return -EINVAL; -+} -+#endif -+ - SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, - unsigned long, arg4, unsigned long, arg5) - { -@@ -1841,6 +1958,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsi - else - error = PR_MCE_KILL_DEFAULT; - break; -+ case PR_SET_MM: -+ error = prctl_set_mm(arg2, arg3, arg4, arg5); -+ break; - default: - error = -EINVAL; - break; diff --git a/kernel/c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4-fix.patch b/kernel/c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4-fix.patch deleted file mode 100644 index d6927bf2f..000000000 --- a/kernel/c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4-fix.patch +++ /dev/null @@ -1,31 +0,0 @@ -From: Andrew Morton -Subject: c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4-fix - -Cc: "Eric W. Biederman" -Cc: Alexey Dobriyan -Cc: Andrew Vagin -Cc: Cyrill Gorcunov -Cc: KAMEZAWA Hiroyuki -Cc: Kees Cook -Cc: Serge Hallyn -Cc: Tejun Heo -Cc: Vasiliy Kulikov -Signed-off-by: Andrew Morton ---- - - Documentation/filesystems/proc.txt | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -Index: linux-2.6.git/Documentation/filesystems/proc.txt -=================================================================== ---- linux-2.6.git.orig/Documentation/filesystems/proc.txt -+++ linux-2.6.git/Documentation/filesystems/proc.txt -@@ -307,7 +307,7 @@ Table 1-4: Contents of the stat files (a - cgtime guest time of the task children in jiffies - start_data address above which program data+bss is placed - end_data address below which program data+bss is placed -- start_brk address above which program heap can be expaned with brk() call -+ start_brk address above which program heap can be expanded with brk() - .............................................................................. - - The /proc/PID/maps file containing the currently mapped memory regions and diff --git a/kernel/c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4.patch b/kernel/c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4.patch deleted file mode 100644 index 1008c8ac5..000000000 --- a/kernel/c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4.patch +++ /dev/null @@ -1,70 +0,0 @@ -From: Cyrill Gorcunov -Subject: c/r: procfs: add start_data, end_data, start_brk members to /proc/$pid/stat v4 - -The mm->start_code/end_code, mm->start_data/end_data, mm->start_brk are -involved into calculation of program text/data segment sizes (which might -be seen in /proc//statm) and into brk() call final address. - -For restore we need to know all these values. While -mm->start_code/end_code already present in /proc/$pid/stat, the rest -members are not, so this patch brings them in. - -The restore procedure of these members is addressed in another patch using -prctl(). - -Signed-off-by: Cyrill Gorcunov -Acked-by: Serge Hallyn -Reviewed-by: Kees Cook -Reviewed-by: KAMEZAWA Hiroyuki -Cc: Alexey Dobriyan -Cc: Tejun Heo -Cc: Andrew Vagin -Cc: Vasiliy Kulikov -Cc: Alexey Dobriyan -Cc: "Eric W. Biederman" -Signed-off-by: Andrew Morton ---- - - Documentation/filesystems/proc.txt | 3 +++ - fs/proc/array.c | 7 +++++-- - 2 files changed, 8 insertions(+), 2 deletions(-) - -Index: linux-2.6.git/Documentation/filesystems/proc.txt -=================================================================== ---- linux-2.6.git.orig/Documentation/filesystems/proc.txt -+++ linux-2.6.git/Documentation/filesystems/proc.txt -@@ -305,6 +305,9 @@ Table 1-4: Contents of the stat files (a - blkio_ticks time spent waiting for block IO - gtime guest time of the task in jiffies - cgtime guest time of the task children in jiffies -+ start_data address above which program data+bss is placed -+ end_data address below which program data+bss is placed -+ start_brk address above which program heap can be expaned with brk() call - .............................................................................. - - The /proc/PID/maps file containing the currently mapped memory regions and -Index: linux-2.6.git/fs/proc/array.c -=================================================================== ---- linux-2.6.git.orig/fs/proc/array.c -+++ linux-2.6.git/fs/proc/array.c -@@ -464,7 +464,7 @@ static int do_task_stat(struct seq_file - - seq_printf(m, "%d (%s) %c %d %d %d %d %d %u %lu \ - %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ --%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", -+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld %lu %lu %lu\n", - pid_nr_ns(pid, ns), - tcomm, - state, -@@ -511,7 +511,10 @@ static int do_task_stat(struct seq_file - task->policy, - (unsigned long long)delayacct_blkio_ticks(task), - cputime_to_clock_t(gtime), -- cputime_to_clock_t(cgtime)); -+ cputime_to_clock_t(cgtime), -+ (mm && permitted) ? mm->start_data : 0, -+ (mm && permitted) ? mm->end_data : 0, -+ (mm && permitted) ? mm->start_brk : 0); - if (mm) - mmput(mm); - return 0; diff --git a/kernel/fs-proc-Introduce-the-proc-pid-map_files-directory b/kernel/fs-proc-Introduce-the-proc-pid-map_files-directory deleted file mode 100644 index 44f7ec1cb..000000000 --- a/kernel/fs-proc-Introduce-the-proc-pid-map_files-directory +++ /dev/null @@ -1,522 +0,0 @@ -From: Cyrill Gorcunov -Subject: [PATCH] fs, proc: Introduce the /proc//map_files/ directory v14 - -From: Pavel Emelyanov - -This one behaves similarly to the /proc//fd/ one - it contains symlinks -one for each mapping with file, the name of a symlink is "vma->vm_start-vma->vm_end", -the target is the file. Opening a symlink results in a file that point exactly -to the same inode as them vma's one. - -For example the ls -l of some arbitrary /proc//map_files/ - - | lr-x------ 1 root root 64 Aug 26 06:40 7f8f80403000-7f8f80404000 -> /lib64/libc-2.5.so - | lr-x------ 1 root root 64 Aug 26 06:40 7f8f8061e000-7f8f80620000 -> /lib64/libselinux.so.1 - | lr-x------ 1 root root 64 Aug 26 06:40 7f8f80826000-7f8f80827000 -> /lib64/libacl.so.1.1.0 - | lr-x------ 1 root root 64 Aug 26 06:40 7f8f80a2f000-7f8f80a30000 -> /lib64/librt-2.5.so - | lr-x------ 1 root root 64 Aug 26 06:40 7f8f80a30000-7f8f80a4c000 -> /lib64/ld-2.5.so - -This *helps* checkpointing process in three ways: - -1. When dumping a task mappings we do know exact file that is mapped by particular - region. We do this by opening /proc/$pid/map_files/$address symlink the way we do - with file descriptors. - -2. This also helps in determining which anonymous shared mappings are shared with - each other by comparing the inodes of them. - -3. When restoring a set of processes in case two of them has a mapping shared, we map - the memory by the 1st one and then open its /proc/$pid/map_files/$address file and - map it by the 2nd task. - -Using /proc/$pid/maps for this is quite inconvenient since it brings repeatable -re-reading and reparsing for this text file which slows down restore procedure -significantly. Also as being pointed in (3) it is a way easier to use top level -shared mapping in children as /proc/$pid/map_files/$address when needed. - -v2: (spotted by Tejun Heo) - - /proc//mfd changed to /proc//map_files - - find_vma helper is used instead of linear search - - routines are re-grouped - - d_revalidate is set now - -v3: - - d_revalidate reworked, now it should drops no longer valid dentries (Tejun Heo) - - ptrace_may_access added into proc_map_files_lookup (Vasiliy Kulikov) - - because of filldir (which eventually might need to lock mmap_sem) - the proc_map_files_readdir() was reworked to call proc_fill_cache() - with unlocked mmap_sem - -v4: (feedback by Tejun Heo and Vasiliy Kulikov) - - instead of saving data in proc_inode we rather make a dentry name - to keep both vm_start and vm_end accordingly - - d_revalidate now honor task credentials - -v5: (feedback by Kirill A. Shutemov) - - don't forget to release mmap_sem on error path - -v6: - - sizeof get used in map_files_info which shrink member a bit on - x86-32 (by Kirill A. Shutemov) - - map_name_to_addr returns -EINVAL instead of -1 - which is more appropriate (by Tejun Heo) - -v7: - - add [get/set]attr handlers for - proc_map_files_inode_operations (by Vasiliy Kulikov) - -v8: - - Kirill A. Shutemov spotted a parasite semicolon - which ruined the ptrace_check call, fixed. - -v9: (feedback by Andrew Morton) - - find_exact_vma moved into include/linux/mm.h as an inline helper - - proc_map_files_setattr uses either kmalloc or vmalloc depending - on how many objects are to be allocated - - no more map_name_to_addr but dname_to_vma_addr introduced instead - and it uses sscanf because in one case the find_exact_vma() is used - only to confirm existence of vma area the boolean flag is used - - fancy justification dropped - - still the proc_map_files_get/setattr leaved untouched - until additional fd/ patches applied first. - -v10: (feedback by Andrew Morton) - - flex_arrays are used instead of kmalloc/vmalloc calls - - map_files_d_revalidate use ptrace_may_access for - security reason (by Vasiliy Kulikov) - -v11: - - should use fput and drop !ret test from a loop code - (feedback by Andrew Morton) - - no need for 'used' variable, use existing - nr_files with file->pos predicate - - if preallocation fails no need to go further, - simply release mmap semaphore and jump out - -v12: - - rework map_files_d_revalidate to make sure - the task get released on return (by Vasiliy Kulikov) - -v13: - - proc_map_files_inode_operations are set to be the same - as proc_fd_inode_operations, ie to include .permission - pointing to proc_fd_permission - -v14: (by Vasiliy Kulikov) - - for security reason map_files/ entries are allowed for - readers with CAP_SYS_ADMIN credentials granted only - -Signed-off-by: Pavel Emelyanov -Signed-off-by: Cyrill Gorcunov -Reviewed-by: Vasiliy Kulikov -Reviewed-by: "Kirill A. Shutemov" -CC: Tejun Heo -CC: Alexey Dobriyan -CC: Al Viro -CC: Andrew Morton -CC: Pavel Machek ---- - fs/proc/base.c | 345 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - include/linux/mm.h | 12 + - 2 files changed, 357 insertions(+) - -Index: linux-2.6.git/fs/proc/base.c -=================================================================== ---- linux-2.6.git.orig/fs/proc/base.c -+++ linux-2.6.git/fs/proc/base.c -@@ -83,6 +83,7 @@ - #include - #include - #include -+#include - #ifdef CONFIG_HARDWALL - #include - #endif -@@ -133,6 +134,8 @@ struct pid_entry { - NULL, &proc_single_file_operations, \ - { .proc_show = show } ) - -+static int proc_fd_permission(struct inode *inode, int mask); -+ - /* - * Count the number of hardlinks for the pid_entry table, excluding the . - * and .. links. -@@ -2217,6 +2220,347 @@ static const struct file_operations proc - }; - - /* -+ * dname_to_vma_addr - maps a dentry name into two unsigned longs -+ * which represent vma start and end addresses. -+ */ -+static int dname_to_vma_addr(struct dentry *dentry, -+ unsigned long *start, unsigned long *end) -+{ -+ if (sscanf(dentry->d_name.name, "%lx-%lx", start, end) != 2) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd) -+{ -+ unsigned long vm_start, vm_end; -+ bool exact_vma_exists = false; -+ struct mm_struct *mm = NULL; -+ struct task_struct *task; -+ const struct cred *cred; -+ struct inode *inode; -+ int status = 0; -+ -+ if (nd && nd->flags & LOOKUP_RCU) -+ return -ECHILD; -+ -+ if (!capable(CAP_SYS_ADMIN)) { -+ status = -EACCES; -+ goto out_notask; -+ } -+ -+ inode = dentry->d_inode; -+ task = get_proc_task(inode); -+ if (!task) -+ goto out_notask; -+ -+ if (!ptrace_may_access(task, PTRACE_MODE_READ)) -+ goto out; -+ -+ mm = get_task_mm(task); -+ if (!mm) -+ goto out; -+ -+ if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) { -+ down_read(&mm->mmap_sem); -+ exact_vma_exists = !!find_exact_vma(mm, vm_start, vm_end); -+ up_read(&mm->mmap_sem); -+ } -+ -+ mmput(mm); -+ -+ if (exact_vma_exists) { -+ if (task_dumpable(task)) { -+ rcu_read_lock(); -+ cred = __task_cred(task); -+ inode->i_uid = cred->euid; -+ inode->i_gid = cred->egid; -+ rcu_read_unlock(); -+ } else { -+ inode->i_uid = 0; -+ inode->i_gid = 0; -+ } -+ security_task_to_inode(task, inode); -+ status = 1; -+ } -+ -+out: -+ put_task_struct(task); -+ -+out_notask: -+ if (status <= 0) -+ d_drop(dentry); -+ -+ return status; -+} -+ -+static const struct dentry_operations tid_map_files_dentry_operations = { -+ .d_revalidate = map_files_d_revalidate, -+ .d_delete = pid_delete_dentry, -+}; -+ -+static int proc_map_files_get_link(struct dentry *dentry, struct path *path) -+{ -+ unsigned long vm_start, vm_end; -+ struct vm_area_struct *vma; -+ struct task_struct *task; -+ struct mm_struct *mm; -+ int rc; -+ -+ rc = -ENOENT; -+ task = get_proc_task(dentry->d_inode); -+ if (!task) -+ goto out; -+ -+ mm = get_task_mm(task); -+ put_task_struct(task); -+ if (!mm) -+ goto out; -+ -+ rc = dname_to_vma_addr(dentry, &vm_start, &vm_end); -+ if (rc) -+ goto out_mmput; -+ -+ down_read(&mm->mmap_sem); -+ vma = find_exact_vma(mm, vm_start, vm_end); -+ if (vma && vma->vm_file) { -+ *path = vma->vm_file->f_path; -+ path_get(path); -+ rc = 0; -+ } -+ up_read(&mm->mmap_sem); -+ -+out_mmput: -+ mmput(mm); -+out: -+ return rc; -+} -+ -+struct map_files_info { -+ struct file *file; -+ unsigned long len; -+ unsigned char name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */ -+}; -+ -+static struct dentry * -+proc_map_files_instantiate(struct inode *dir, struct dentry *dentry, -+ struct task_struct *task, const void *ptr) -+{ -+ const struct file *file = ptr; -+ struct proc_inode *ei; -+ struct inode *inode; -+ -+ if (!file) -+ return ERR_PTR(-ENOENT); -+ -+ inode = proc_pid_make_inode(dir->i_sb, task); -+ if (!inode) -+ return ERR_PTR(-ENOENT); -+ -+ ei = PROC_I(inode); -+ ei->op.proc_get_link = proc_map_files_get_link; -+ -+ inode->i_op = &proc_pid_link_inode_operations; -+ inode->i_size = 64; -+ inode->i_mode = S_IFLNK; -+ -+ if (file->f_mode & FMODE_READ) -+ inode->i_mode |= S_IRUSR; -+ if (file->f_mode & FMODE_WRITE) -+ inode->i_mode |= S_IWUSR; -+ -+ d_set_d_op(dentry, &tid_map_files_dentry_operations); -+ d_add(dentry, inode); -+ -+ return NULL; -+} -+ -+static struct dentry *proc_map_files_lookup(struct inode *dir, -+ struct dentry *dentry, struct nameidata *nd) -+{ -+ unsigned long vm_start, vm_end; -+ struct vm_area_struct *vma; -+ struct task_struct *task; -+ struct dentry *result; -+ struct mm_struct *mm; -+ -+ result = ERR_PTR(-EACCES); -+ if (!capable(CAP_SYS_ADMIN)) -+ goto out; -+ -+ result = ERR_PTR(-ENOENT); -+ task = get_proc_task(dir); -+ if (!task) -+ goto out; -+ -+ result = ERR_PTR(-EACCES); -+ if (lock_trace(task)) -+ goto out_put_task; -+ -+ result = ERR_PTR(-ENOENT); -+ if (dname_to_vma_addr(dentry, &vm_start, &vm_end)) -+ goto out_unlock; -+ -+ mm = get_task_mm(task); -+ if (!mm) -+ goto out_unlock; -+ -+ down_read(&mm->mmap_sem); -+ vma = find_exact_vma(mm, vm_start, vm_end); -+ if (!vma) -+ goto out_no_vma; -+ -+ result = proc_map_files_instantiate(dir, dentry, task, vma->vm_file); -+ -+out_no_vma: -+ up_read(&mm->mmap_sem); -+ mmput(mm); -+out_unlock: -+ unlock_trace(task); -+out_put_task: -+ put_task_struct(task); -+out: -+ return result; -+} -+ -+static const struct inode_operations proc_map_files_inode_operations = { -+ .lookup = proc_map_files_lookup, -+ .permission = proc_fd_permission, -+ .setattr = proc_setattr, -+}; -+ -+static int proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) -+{ -+ struct dentry *dentry = filp->f_path.dentry; -+ struct inode *inode = dentry->d_inode; -+ struct vm_area_struct *vma; -+ struct task_struct *task; -+ struct mm_struct *mm; -+ ino_t ino; -+ int ret; -+ -+ ret = -EACCES; -+ if (!capable(CAP_SYS_ADMIN)) -+ goto out; -+ -+ ret = -ENOENT; -+ task = get_proc_task(inode); -+ if (!task) -+ goto out; -+ -+ ret = -EACCES; -+ if (lock_trace(task)) -+ goto out_put_task; -+ -+ ret = 0; -+ switch (filp->f_pos) { -+ case 0: -+ ino = inode->i_ino; -+ if (filldir(dirent, ".", 1, 0, ino, DT_DIR) < 0) -+ goto out_unlock; -+ filp->f_pos++; -+ case 1: -+ ino = parent_ino(dentry); -+ if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) -+ goto out_unlock; -+ filp->f_pos++; -+ default: -+ { -+ unsigned long nr_files, pos, i; -+ struct flex_array *fa = NULL; -+ struct map_files_info info; -+ struct map_files_info *p; -+ -+ mm = get_task_mm(task); -+ if (!mm) -+ goto out_unlock; -+ down_read(&mm->mmap_sem); -+ -+ nr_files = 0; -+ -+ /* -+ * We need two passes here: -+ * -+ * 1) Collect vmas of mapped files with mmap_sem taken -+ * 2) Release mmap_sem and instantiate entries -+ * -+ * otherwise we get lockdep complained, since filldir() -+ * routine might require mmap_sem taken in might_fault(). -+ */ -+ -+ for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { -+ if (vma->vm_file && ++pos > filp->f_pos) -+ nr_files++; -+ } -+ -+ if (nr_files) { -+ fa = flex_array_alloc(sizeof(info), nr_files, GFP_KERNEL); -+ if (!fa || flex_array_prealloc(fa, 0, nr_files, GFP_KERNEL)) { -+ ret = -ENOMEM; -+ if (fa) -+ flex_array_free(fa); -+ up_read(&mm->mmap_sem); -+ mmput(mm); -+ goto out_unlock; -+ } -+ for (i = 0, vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { -+ if (!vma->vm_file) -+ continue; -+ if (++pos <= filp->f_pos) -+ continue; -+ -+ get_file(vma->vm_file); -+ info.file = vma->vm_file; -+ info.len = snprintf(info.name, sizeof(info.name), -+ "%lx-%lx", vma->vm_start, -+ vma->vm_end); -+ if (flex_array_put(fa, i++, &info, GFP_KERNEL)) -+ BUG(); -+ } -+ } -+ up_read(&mm->mmap_sem); -+ -+ for (i = 0; i < nr_files; i++) { -+ p = flex_array_get(fa, i); -+ ret = proc_fill_cache(filp, dirent, filldir, -+ p->name, p->len, -+ proc_map_files_instantiate, -+ task, p->file); -+ if (ret) -+ break; -+ filp->f_pos++; -+ fput(p->file); -+ } -+ for (; i < nr_files; i++) { -+ /* -+ * In case of error don't forget -+ * to put rest of file refs. -+ */ -+ p = flex_array_get(fa, i); -+ fput(p->file); -+ } -+ if (fa) -+ flex_array_free(fa); -+ mmput(mm); -+ } -+ } -+ -+out_unlock: -+ unlock_trace(task); -+out_put_task: -+ put_task_struct(task); -+out: -+ return ret; -+} -+ -+static const struct file_operations proc_map_files_operations = { -+ .read = generic_read_dir, -+ .readdir = proc_map_files_readdir, -+ .llseek = default_llseek, -+}; -+ -+/* - * /proc/pid/fd needs a special permission handler so that a process can still - * access /proc/self/fd after it has executed a setuid(). - */ -@@ -2832,6 +3176,7 @@ static const struct inode_operations pro - static const struct pid_entry tgid_base_stuff[] = { - DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), - DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), -+ DIR("map_files", S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations), - DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), - DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), - #ifdef CONFIG_NET -Index: linux-2.6.git/include/linux/mm.h -=================================================================== ---- linux-2.6.git.orig/include/linux/mm.h -+++ linux-2.6.git/include/linux/mm.h -@@ -1491,6 +1491,18 @@ static inline unsigned long vma_pages(st - return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - } - -+/* Look up the first VMA which exactly match the interval vm_start ... vm_end */ -+static inline struct vm_area_struct * -+find_exact_vma(struct mm_struct *mm, unsigned long vm_start, unsigned long vm_end) -+{ -+ struct vm_area_struct *vma = find_vma(mm, vm_start); -+ -+ if (vma && (vma->vm_start != vm_start || vma->vm_end != vm_end)) -+ vma = NULL; -+ -+ return vma; -+} -+ - #ifdef CONFIG_MMU - pgprot_t vm_get_page_prot(unsigned long vm_flags); - #else diff --git a/kernel/fs-proc-Make-proc_get_link-to-use-dentry b/kernel/fs-proc-Make-proc_get_link-to-use-dentry deleted file mode 100644 index 39cc1e41a..000000000 --- a/kernel/fs-proc-Make-proc_get_link-to-use-dentry +++ /dev/null @@ -1,108 +0,0 @@ -From: Cyrill Gorcunov -Subject: [PATCH] fs, proc: Make proc_get_link to use dentry instead of inode - -From: Cyrill Gorcunov - -This patch prepares the ground for the next "map_files" -patch which needs a name of a link file to analyse. - -Signed-off-by: Cyrill Gorcunov -CC: Pavel Emelyanov -CC: Tejun Heo -CC: Vasiliy Kulikov -CC: "Kirill A. Shutemov" -CC: Alexey Dobriyan -CC: Al Viro -CC: Andrew Morton ---- - fs/proc/base.c | 20 ++++++++++---------- - include/linux/proc_fs.h | 2 +- - 2 files changed, 11 insertions(+), 11 deletions(-) - -Index: linux-2.6.git/fs/proc/base.c -=================================================================== ---- linux-2.6.git.orig/fs/proc/base.c -+++ linux-2.6.git/fs/proc/base.c -@@ -165,9 +165,9 @@ static int get_task_root(struct task_str - return result; - } - --static int proc_cwd_link(struct inode *inode, struct path *path) -+static int proc_cwd_link(struct dentry *dentry, struct path *path) - { -- struct task_struct *task = get_proc_task(inode); -+ struct task_struct *task = get_proc_task(dentry->d_inode); - int result = -ENOENT; - - if (task) { -@@ -182,9 +182,9 @@ static int proc_cwd_link(struct inode *i - return result; - } - --static int proc_root_link(struct inode *inode, struct path *path) -+static int proc_root_link(struct dentry *dentry, struct path *path) - { -- struct task_struct *task = get_proc_task(inode); -+ struct task_struct *task = get_proc_task(dentry->d_inode); - int result = -ENOENT; - - if (task) { -@@ -1567,13 +1567,13 @@ static const struct file_operations proc - .release = single_release, - }; - --static int proc_exe_link(struct inode *inode, struct path *exe_path) -+static int proc_exe_link(struct dentry *dentry, struct path *exe_path) - { - struct task_struct *task; - struct mm_struct *mm; - struct file *exe_file; - -- task = get_proc_task(inode); -+ task = get_proc_task(dentry->d_inode); - if (!task) - return -ENOENT; - mm = get_task_mm(task); -@@ -1603,7 +1603,7 @@ static void *proc_pid_follow_link(struct - if (!proc_fd_access_allowed(inode)) - goto out; - -- error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); -+ error = PROC_I(inode)->op.proc_get_link(dentry, &nd->path); - out: - return ERR_PTR(error); - } -@@ -1642,7 +1642,7 @@ static int proc_pid_readlink(struct dent - if (!proc_fd_access_allowed(inode)) - goto out; - -- error = PROC_I(inode)->op.proc_get_link(inode, &path); -+ error = PROC_I(inode)->op.proc_get_link(dentry, &path); - if (error) - goto out; - -@@ -1980,9 +1980,9 @@ out_task: - return rc; - } - --static int proc_fd_link(struct inode *inode, struct path *path) -+static int proc_fd_link(struct dentry *dentry, struct path *path) - { -- return proc_fd_info(inode, path, NULL); -+ return proc_fd_info(dentry->d_inode, path, NULL); - } - - static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) -Index: linux-2.6.git/include/linux/proc_fs.h -=================================================================== ---- linux-2.6.git.orig/include/linux/proc_fs.h -+++ linux-2.6.git/include/linux/proc_fs.h -@@ -253,7 +253,7 @@ extern const struct proc_ns_operations u - extern const struct proc_ns_operations ipcns_operations; - - union proc_op { -- int (*proc_get_link)(struct inode *, struct path *); -+ int (*proc_get_link)(struct dentry *, struct path *); - int (*proc_read)(struct task_struct *task, char *page); - int (*proc_show)(struct seq_file *m, - struct pid_namespace *ns, struct pid *pid, diff --git a/kernel/fs-proc-add-children-entry-11 b/kernel/fs-proc-add-children-entry-11 deleted file mode 100644 index f65e3cb6a..000000000 --- a/kernel/fs-proc-add-children-entry-11 +++ /dev/null @@ -1,279 +0,0 @@ -From: Cyrill Gorcunov -Subject: [PATCH] fs, proc: Introduce the /proc//children entry v4 - -There is no easy way to make a reverse parent->children chain -from arbitrary (while parent pid is provided in "PPid" -field of /proc//status). - -So instead of walking over all pids in the system to figure out which -children a task have -- we add explicit /proc//children entry, -because kernel already has this kind of information but it is not -yet exported. This is a first level children, not the whole process -tree, neither the process threads are identified with this interface. - -v2: - - Kame suggested to use a separated /proc//children entry - instead of poking /proc//status - - Andew suggested to use rcu facility instead of locking - tasklist_lock - - Tejun pointed that non-seekable seq file might not be - enough for tasks with large number of children - -v3: - - To be on a safe side use %lu format for pid_t printing - -v4: - - New line get printed when sequence ends not at seq->stop, - a nit pointed by Tejun - - Documentation update - - tasklist_lock is back, Oleg pointed that ->children list - is actually not rcu-safe - -Signed-off-by: Cyrill Gorcunov -Cc: Andrew Morton -Cc: Pavel Emelyanov -Cc: Serge Hallyn -Cc: KAMEZAWA Hiroyuki -Cc: Pavel Emelyanov ---- - Documentation/filesystems/proc.txt | 20 ++++ - fs/proc/array.c | 163 +++++++++++++++++++++++++++++++++++++ - fs/proc/base.c | 1 - fs/proc/internal.h | 6 + - 4 files changed, 190 insertions(+) - -Index: linux-2.6.git/Documentation/filesystems/proc.txt -=================================================================== ---- linux-2.6.git.orig/Documentation/filesystems/proc.txt -+++ linux-2.6.git/Documentation/filesystems/proc.txt -@@ -40,6 +40,7 @@ Table of Contents - 3.4 /proc//coredump_filter - Core dump filtering settings - 3.5 /proc//mountinfo - Information about mounts - 3.6 /proc//comm & /proc//task//comm -+ 3.7 /proc//children - Information about task children - - - ------------------------------------------------------------------------------ -@@ -1545,3 +1546,22 @@ a task to set its own or one of its thre - is limited in size compared to the cmdline value, so writing anything longer - then the kernel's TASK_COMM_LEN (currently 16 chars) will result in a truncated - comm value. -+ -+3.7 /proc//children - Information about task children -+-------------------------------------------------------------- -+This file provides a fast way to retrieve first level children pids -+of a task pointed by . The format is a stream of pids separated -+by space with a new line at the end. If a task has no children at -+all -- only a new line returned. -+ -+Note the "first level" here -- if a child has own children they will -+not be printed there, one need to read /proc//children -+to obtain descendants. The same applies to threads -- they are not -+counted here. -+ -+Because this interface is intended to be fast and cheap it doesn't -+guarantee to provide the precise results, which means if a child is -+exiting it might or might not be counted. The same applies to freshly -+created children -- they might or might not be counted. If one needs -+precise pids -- the task and children should be either stopped or -+frozen. -Index: linux-2.6.git/fs/proc/array.c -=================================================================== ---- linux-2.6.git.orig/fs/proc/array.c -+++ linux-2.6.git/fs/proc/array.c -@@ -547,3 +547,166 @@ int proc_pid_statm(struct seq_file *m, s - - return 0; - } -+ -+static struct list_head * -+children_get_at(struct proc_pid_children_iter *iter, loff_t pos) -+{ -+ struct task_struct *t = iter->group_leader; -+ struct task_struct *task; -+ -+ rcu_read_lock(); -+ do { -+ list_for_each_entry(task, &t->children, sibling) { -+ if (list_empty(&task->sibling)) -+ break; -+ if (pos-- == 0) { -+ put_task_struct(iter->last_group); -+ iter->last_group = t; -+ get_task_struct(iter->last_group); -+ get_task_struct(task); -+ rcu_read_unlock(); -+ return &task->sibling; -+ } -+ } -+ } while_each_thread(iter->group_leader, t); -+ rcu_read_unlock(); -+ -+ return NULL; -+} -+ -+static int children_seq_show(struct seq_file *seq, void *v) -+{ -+ struct task_struct *task = container_of(v, struct task_struct, sibling); -+ unsigned long pid; -+ int ret = -1; -+ -+ rcu_read_lock(); -+ if (pid_alive(task)) { -+ pid = (unsigned long)pid_vnr(task_pid(task)); -+ ret = 0; -+ } -+ rcu_read_unlock(); -+ -+ if (!ret) -+ ret = seq_printf(seq, " %lu", pid); -+ return ret; -+} -+ -+static void *children_seq_start(struct seq_file *seq, loff_t *pos) -+{ -+ return children_get_at(seq->private, *pos); -+} -+ -+static void *children_seq_next(struct seq_file *seq, void *v, loff_t *pos) -+{ -+ struct proc_pid_children_iter *iter = seq->private; -+ struct task_struct *task = container_of(v, struct task_struct, sibling); -+ struct list_head *next = NULL; -+ -+ if (!iter->last_group) -+ goto out; -+ -+ rcu_read_lock(); -+ -+ if (list_empty(&task->sibling) || -+ list_is_last(v, &iter->last_group->children)) { -+ struct task_struct *t = iter->last_group; -+ -+ while_each_thread(iter->group_leader, t) { -+ if (!list_empty(&t->children)) { -+ put_task_struct(task); -+ next = t->children.next; -+ task = container_of(next, struct task_struct, sibling); -+ get_task_struct(task); -+ put_task_struct(iter->last_group); -+ iter->last_group = t; -+ get_task_struct(iter->last_group); -+ goto out_unlock; -+ } -+ } -+ -+ put_task_struct(task); -+ put_task_struct(iter->last_group); -+ iter->last_group = NULL; -+ } else { -+ next = ((struct list_head *)v)->next; -+ put_task_struct(task); -+ task = container_of(next, struct task_struct, sibling); -+ get_task_struct(task); -+ } -+out_unlock: -+ rcu_read_unlock(); -+out: -+ ++*pos; -+ if (!next) -+ seq_printf(seq, "\n"); -+ return next; -+} -+ -+static void children_seq_stop(struct seq_file *seq, void *v) -+{ -+ struct proc_pid_children_iter *iter = seq->private; -+ if (iter->last_group) -+ put_task_struct(iter->last_group); -+ iter->last_group = NULL; -+} -+ -+static const struct seq_operations children_seq_ops = { -+ .start = children_seq_start, -+ .next = children_seq_next, -+ .stop = children_seq_stop, -+ .show = children_seq_show, -+}; -+ -+static int children_seq_open(struct inode *inode, struct file *file) -+{ -+ struct proc_pid_children_iter *iter = NULL; -+ struct task_struct *task = NULL; -+ int ret; -+ -+ ret = -ENOMEM; -+ iter = kmalloc(sizeof(*iter), GFP_KERNEL); -+ if (!iter) -+ goto err; -+ -+ ret = -ENOENT; -+ task = get_proc_task(inode); -+ if (!task) -+ goto err; -+ -+ ret = seq_open(file, &children_seq_ops); -+ if (!ret) { -+ struct seq_file *m = file->private_data; -+ m->private = iter; -+ iter->group_leader = task; -+ iter->last_group = task; -+ get_task_struct(iter->last_group); -+ } -+ -+err: -+ if (ret) { -+ if (task) -+ put_task_struct(task); -+ kfree(iter); -+ } -+ -+ return ret; -+} -+ -+int children_seq_release(struct inode *inode, struct file *file) -+{ -+ struct seq_file *m = file->private_data; -+ struct proc_pid_children_iter *iter = m->private; -+ -+ put_task_struct(iter->group_leader); -+ kfree(iter); -+ seq_release(inode, file); -+ return 0; -+} -+ -+const struct file_operations proc_pid_children_operations = { -+ .open = children_seq_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = children_seq_release, -+}; -Index: linux-2.6.git/fs/proc/base.c -=================================================================== ---- linux-2.6.git.orig/fs/proc/base.c -+++ linux-2.6.git/fs/proc/base.c -@@ -3204,6 +3204,7 @@ static const struct pid_entry tgid_base_ - INF("cmdline", S_IRUGO, proc_pid_cmdline), - ONE("stat", S_IRUGO, proc_tgid_stat), - ONE("statm", S_IRUGO, proc_pid_statm), -+ REG("children", S_IRUGO, proc_pid_children_operations), - REG("maps", S_IRUGO, proc_maps_operations), - #ifdef CONFIG_NUMA - REG("numa_maps", S_IRUGO, proc_numa_maps_operations), -Index: linux-2.6.git/fs/proc/internal.h -=================================================================== ---- linux-2.6.git.orig/fs/proc/internal.h -+++ linux-2.6.git/fs/proc/internal.h -@@ -53,6 +53,12 @@ extern int proc_pid_statm(struct seq_fil - struct pid *pid, struct task_struct *task); - extern loff_t mem_lseek(struct file *file, loff_t offset, int orig); - -+struct proc_pid_children_iter { -+ struct task_struct *group_leader; -+ struct task_struct *last_group; -+}; -+ -+extern const struct file_operations proc_pid_children_operations; - extern const struct file_operations proc_maps_operations; - extern const struct file_operations proc_numa_maps_operations; - extern const struct file_operations proc_smaps_operations; diff --git a/kernel/mincore-Add-named-constant-for-reported-present-bit b/kernel/mincore-Add-named-constant-for-reported-present-bit deleted file mode 100644 index 48ed8f41b..000000000 --- a/kernel/mincore-Add-named-constant-for-reported-present-bit +++ /dev/null @@ -1,87 +0,0 @@ -From: Cyrill Gorcunov -Subject: [PATCH] mincore: Add named constant for reported present bit - -From: Pavel Emelyanov - -Signed-off-by: Pavel Emelyanov -Signed-off-by: Cyrill Gorcunov ---- - include/linux/mman.h | 2 ++ - mm/huge_memory.c | 2 +- - mm/mincore.c | 10 +++++----- - 3 files changed, 8 insertions(+), 6 deletions(-) - -Index: linux-2.6.git/include/linux/mman.h -=================================================================== ---- linux-2.6.git.orig/include/linux/mman.h -+++ linux-2.6.git/include/linux/mman.h -@@ -10,6 +10,8 @@ - #define OVERCOMMIT_ALWAYS 1 - #define OVERCOMMIT_NEVER 2 - -+#define MINCORE_RESIDENT 0x1 -+ - #ifdef __KERNEL__ - #include - #include -Index: linux-2.6.git/mm/huge_memory.c -=================================================================== ---- linux-2.6.git.orig/mm/huge_memory.c -+++ linux-2.6.git/mm/huge_memory.c -@@ -1045,7 +1045,7 @@ int mincore_huge_pmd(struct vm_area_stru - * All logical pages in the range are present - * if backed by a huge page. - */ -- memset(vec, 1, (end - addr) >> PAGE_SHIFT); -+ memset(vec, MINCORE_RESIDENT, (end - addr) >> PAGE_SHIFT); - } - } else - spin_unlock(&vma->vm_mm->page_table_lock); -Index: linux-2.6.git/mm/mincore.c -=================================================================== ---- linux-2.6.git.orig/mm/mincore.c -+++ linux-2.6.git/mm/mincore.c -@@ -38,7 +38,7 @@ static void mincore_hugetlb_page_range(s - addr & huge_page_mask(h)); - present = ptep && !huge_pte_none(huge_ptep_get(ptep)); - while (1) { -- *vec = present; -+ *vec = (present ? MINCORE_RESIDENT : 0); - vec++; - addr += PAGE_SIZE; - if (addr == end) -@@ -83,7 +83,7 @@ static unsigned char mincore_page(struct - page_cache_release(page); - } - -- return present; -+ return present ? MINCORE_RESIDENT : 0; - } - - static void mincore_unmapped_range(struct vm_area_struct *vma, -@@ -122,7 +122,7 @@ static void mincore_pte_range(struct vm_ - if (pte_none(pte)) - mincore_unmapped_range(vma, addr, next, vec); - else if (pte_present(pte)) -- *vec = 1; -+ *vec = MINCORE_RESIDENT; - else if (pte_file(pte)) { - pgoff = pte_to_pgoff(pte); - *vec = mincore_page(vma->vm_file->f_mapping, pgoff); -@@ -131,14 +131,14 @@ static void mincore_pte_range(struct vm_ - - if (is_migration_entry(entry)) { - /* migration entries are always uptodate */ -- *vec = 1; -+ *vec = MINCORE_RESIDENT; - } else { - #ifdef CONFIG_SWAP - pgoff = entry.val; - *vec = mincore_page(&swapper_space, pgoff); - #else - WARN_ON(1); -- *vec = 1; -+ *vec = MINCORE_RESIDENT; - #endif - } - } diff --git a/kernel/mincore-Report-whether-page-is-anon-or-not b/kernel/mincore-Report-whether-page-is-anon-or-not deleted file mode 100644 index b203cdb57..000000000 --- a/kernel/mincore-Report-whether-page-is-anon-or-not +++ /dev/null @@ -1,74 +0,0 @@ -From: Cyrill Gorcunov -Subject: [PATCH] mincore: Report whether page is anon or not - -From: Pavel Emelyanov - -This is required not to dump pages from private file mappings, that are -not mapped or not yet COW-ed. - -The thing is that mincode reports bit 1 for pages that are in memory, regardless -of whether they are mapped or not. But in case we have mapped a file of 2 pages and -read a single page mincore will report 1 for both - the 1st one being mapped and -the 2nd one being in page cache due to readahead. - -With this fix both pages will be !PageAnon and we can skip them from dumping. - -Signed-off-by: Pavel Emelyanov -Signed-off-by: Cyrill Gorcunov ---- - include/linux/mman.h | 1 + - mm/mincore.c | 15 +++++++++++++-- - 2 files changed, 14 insertions(+), 2 deletions(-) - -Index: linux-2.6.git/include/linux/mman.h -=================================================================== ---- linux-2.6.git.orig/include/linux/mman.h -+++ linux-2.6.git/include/linux/mman.h -@@ -11,6 +11,7 @@ - #define OVERCOMMIT_NEVER 2 - - #define MINCORE_RESIDENT 0x1 -+#define MINCORE_ANON 0x2 - - #ifdef __KERNEL__ - #include -Index: linux-2.6.git/mm/mincore.c -=================================================================== ---- linux-2.6.git.orig/mm/mincore.c -+++ linux-2.6.git/mm/mincore.c -@@ -38,7 +38,7 @@ static void mincore_hugetlb_page_range(s - addr & huge_page_mask(h)); - present = ptep && !huge_pte_none(huge_ptep_get(ptep)); - while (1) { -- *vec = (present ? MINCORE_RESIDENT : 0); -+ *vec = (present ? MINCORE_RESIDENT : 0) | MINCORE_ANON; - vec++; - addr += PAGE_SIZE; - if (addr == end) -@@ -86,6 +86,17 @@ static unsigned char mincore_page(struct - return present ? MINCORE_RESIDENT : 0; - } - -+static unsigned char mincore_pte(struct vm_area_struct *vma, unsigned long addr, pte_t pte) -+{ -+ struct page *pg; -+ -+ pg = vm_normal_page(vma, addr, pte); -+ if (!pg) -+ return 0; -+ else -+ return PageAnon(pg) ? MINCORE_ANON : 0; -+} -+ - static void mincore_unmapped_range(struct vm_area_struct *vma, - unsigned long addr, unsigned long end, - unsigned char *vec) -@@ -122,7 +133,7 @@ static void mincore_pte_range(struct vm_ - if (pte_none(pte)) - mincore_unmapped_range(vma, addr, next, vec); - else if (pte_present(pte)) -- *vec = MINCORE_RESIDENT; -+ *vec = MINCORE_RESIDENT | mincore_pte(vma, addr, pte); - else if (pte_file(pte)) { - pgoff = pte_to_pgoff(pte); - *vec = mincore_page(vma->vm_file->f_mapping, pgoff); diff --git a/kernel/procfs-introduce-the-proc-pid-map_files-directory-checkpatch b/kernel/procfs-introduce-the-proc-pid-map_files-directory-checkpatch deleted file mode 100644 index 543109c22..000000000 --- a/kernel/procfs-introduce-the-proc-pid-map_files-directory-checkpatch +++ /dev/null @@ -1,115 +0,0 @@ -From: Cyrill Gorcunov -Subject: [PATCH] procfs-introduce-the-proc-pid-map_files-directory-checkpatch-fixes - -From: Andrew Morton - -Cc: "Kirill A. Shutemov" - -WARNING: line over 80 characters -#286: FILE: fs/proc/base.c:2433: -+static int proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) - -WARNING: line over 80 characters -#351: FILE: fs/proc/base.c:2498: -+ fa = flex_array_alloc(sizeof(info), nr_files, GFP_KERNEL); - -WARNING: line over 80 characters -#352: FILE: fs/proc/base.c:2499: -+ if (!fa || flex_array_prealloc(fa, 0, nr_files, GFP_KERNEL)) { - -WARNING: line over 80 characters -#360: FILE: fs/proc/base.c:2507: -+ for (i = 0, vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { - -WARNING: line over 80 characters -#368: FILE: fs/proc/base.c:2515: -+ info.len = snprintf(info.name, sizeof(info.name), - -WARNING: line over 80 characters -#424: FILE: fs/proc/base.c:3179: -+ DIR("map_files", S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations), - -WARNING: line over 80 characters -#437: FILE: include/linux/mm.h:1497: -+find_exact_vma(struct mm_struct *mm, unsigned long vm_start, unsigned long vm_end) - -total: 0 errors, 7 warnings, 387 lines checked - -./patches/procfs-introduce-the-proc-pid-map_files-directory.patch has style problems, please review. - -If any of these errors are false positives, please report -them to the maintainer, see CHECKPATCH in MAINTAINERS. - -Please run checkpatch prior to sending patches - -Cc: Cyrill Gorcunov -Signed-off-by: Andrew Morton ---- - fs/proc/base.c | 18 +++++++++++------- - include/linux/mm.h | 4 ++-- - 2 files changed, 13 insertions(+), 9 deletions(-) - ---- a/fs/proc/base.c -+++ b/fs/proc/base.c -@@ -2430,7 +2430,8 @@ static const struct inode_operations proc_map_files_inode_operations = { - .setattr = proc_setattr, - }; - --static int proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) -+static int -+proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) - { - struct dentry *dentry = filp->f_path.dentry; - struct inode *inode = dentry->d_inode; -@@ -2495,8 +2496,10 @@ static int proc_map_files_readdir(struct file *filp, void *dirent, filldir_t fil - } - - if (nr_files) { -- fa = flex_array_alloc(sizeof(info), nr_files, GFP_KERNEL); -- if (!fa || flex_array_prealloc(fa, 0, nr_files, GFP_KERNEL)) { -+ fa = flex_array_alloc(sizeof(info), nr_files, -+ GFP_KERNEL); -+ if (!fa || flex_array_prealloc(fa, 0, nr_files, -+ GFP_KERNEL)) { - ret = -ENOMEM; - if (fa) - flex_array_free(fa); -@@ -2504,7 +2507,8 @@ static int proc_map_files_readdir(struct file *filp, void *dirent, filldir_t fil - mmput(mm); - goto out_unlock; - } -- for (i = 0, vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { -+ for (i = 0, vma = mm->mmap, pos = 2; vma; -+ vma = vma->vm_next) { - if (!vma->vm_file) - continue; - if (++pos <= filp->f_pos) -@@ -2512,9 +2516,9 @@ static int proc_map_files_readdir(struct file *filp, void *dirent, filldir_t fil - - get_file(vma->vm_file); - info.file = vma->vm_file; -- info.len = snprintf(info.name, sizeof(info.name), -- "%lx-%lx", vma->vm_start, -- vma->vm_end); -+ info.len = snprintf(info.name, -+ sizeof(info.name), "%lx-%lx", -+ vma->vm_start, vma->vm_end); - if (flex_array_put(fa, i++, &info, GFP_KERNEL)) - BUG(); - } ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -1492,8 +1492,8 @@ static inline unsigned long vma_pages(struct vm_area_struct *vma) - } - - /* Look up the first VMA which exactly match the interval vm_start ... vm_end */ --static inline struct vm_area_struct * --find_exact_vma(struct mm_struct *mm, unsigned long vm_start, unsigned long vm_end) -+static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm, -+ unsigned long vm_start, unsigned long vm_end) - { - struct vm_area_struct *vma = find_vma(mm, vm_start); - --- -1.7.7.3 - diff --git a/kernel/series b/kernel/series deleted file mode 100644 index f0e5c31df..000000000 --- a/kernel/series +++ /dev/null @@ -1,12 +0,0 @@ -fs-proc-Make-proc_get_link-to-use-dentry -fs-proc-Introduce-the-proc-pid-map_files-directory -procfs-introduce-the-proc-pid-map_files-directory-checkpatch -sysfs-add-kernel.ns_last_pid -c-r-introduce-checkpoint_restore-symbol.patch -c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4.patch -c-r-procfs-add-start_data-end_data-start_brk-members-to-proc-pid-stat-v4-fix.patch -c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries.patch -c-r-prctl-add-pr_set_mm-codes-to-set-up-mm_struct-entries-fix.patch -mincore-Add-named-constant-for-reported-present-bit -mincore-Report-whether-page-is-anon-or-not -fs-proc-add-children-entry-11 diff --git a/kernel/sysfs-add-kernel.ns_last_pid b/kernel/sysfs-add-kernel.ns_last_pid deleted file mode 100644 index 0ef64887d..000000000 --- a/kernel/sysfs-add-kernel.ns_last_pid +++ /dev/null @@ -1,104 +0,0 @@ -From: Cyrill Gorcunov -Subject: [PATCH] sysctl: Add the kernel.ns_last_pid control - -From: Pavel Emelyanov - -The sysctl works on the current task's pid namespace, getting and setting its -last_pid field. - -Writing is allowed for CAP_SYS_ADMIN-capable tasks thus making it possible to -create a task with desired pid value. This ability is required badly for the -checkpoint/restore in userspace. - -This approach suits all the parties for now. - -Signed-off-by: Pavel Emelyanov -Acked-by: Tejun Heo -CC: Oleg Nesterov -CC: Andrew Morton -Signed-off-by: Cyrill Gorcunov ---- - Documentation/sysctl/kernel.txt | 8 ++++++++ - kernel/pid.c | 4 +++- - kernel/pid_namespace.c | 31 +++++++++++++++++++++++++++++++ - 3 files changed, 42 insertions(+), 1 deletion(-) - -Index: linux-2.6.git/Documentation/sysctl/kernel.txt -=================================================================== ---- linux-2.6.git.orig/Documentation/sysctl/kernel.txt -+++ linux-2.6.git/Documentation/sysctl/kernel.txt -@@ -401,6 +401,14 @@ PIDs of value pid_max or larger are not - - ============================================================== - -+ns_last_pid: -+ -+The last pid allocated in the current (the one task using this sysctl -+lives in) pid namespace. When selecting a pid for a next task on fork -+kernel tries to allocate a number starting from this one. -+ -+============================================================== -+ - powersave-nap: (PPC only) - - If set, Linux-PPC will use the 'nap' mode of powersaving, -Index: linux-2.6.git/kernel/pid.c -=================================================================== ---- linux-2.6.git.orig/kernel/pid.c -+++ linux-2.6.git/kernel/pid.c -@@ -137,7 +137,9 @@ static int pid_before(int base, int a, i - } - - /* -- * We might be racing with someone else trying to set pid_ns->last_pid. -+ * We might be racing with someone else trying to set pid_ns->last_pid -+ * at the pid allocation time (there's also a sysctl for this, but racing -+ * with this one is OK, see comment in kernel/pid_namespace.c about it). - * We want the winner to have the "later" value, because if the - * "earlier" value prevails, then a pid may get reused immediately. - * -Index: linux-2.6.git/kernel/pid_namespace.c -=================================================================== ---- linux-2.6.git.orig/kernel/pid_namespace.c -+++ linux-2.6.git/kernel/pid_namespace.c -@@ -191,9 +191,40 @@ void zap_pid_ns_processes(struct pid_nam - return; - } - -+static int pid_ns_ctl_handler(struct ctl_table *table, int write, -+ void __user *buffer, size_t *lenp, loff_t *ppos) -+{ -+ struct ctl_table tmp = *table; -+ -+ if (write && !capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ -+ /* -+ * Writing directly to ns' last_pid field is OK, since this field -+ * is volatile in a living namespace anyway and a code writing to -+ * it should synchronize its usage with external means. -+ */ -+ -+ tmp.data = ¤t->nsproxy->pid_ns->last_pid; -+ return proc_dointvec(&tmp, write, buffer, lenp, ppos); -+} -+ -+static struct ctl_table pid_ns_ctl_table[] = { -+ { -+ .procname = "ns_last_pid", -+ .maxlen = sizeof(int), -+ .mode = 0666, /* permissions are checked in the handler */ -+ .proc_handler = pid_ns_ctl_handler, -+ }, -+ { } -+}; -+ -+static struct ctl_path kern_path[] = { { .procname = "kernel", }, { } }; -+ - static __init int pid_namespaces_init(void) - { - pid_ns_cachep = KMEM_CACHE(pid_namespace, SLAB_PANIC); -+ register_sysctl_paths(kern_path, pid_ns_ctl_table); - return 0; - } -