aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorCyrill Gorcunov2012-05-31 18:26:44 -0500
committerLinus Torvalds2012-05-31 19:49:32 -0500
commitd97b46a64674a267bc41c9e16132ee2a98c3347d (patch)
tree316f77d212c84aef226684eb05d5d33f40743ac9 /tools
parent818411616baf46ceba0cff6f05af3a9b294734f7 (diff)
downloadkernel-omap-d97b46a64674a267bc41c9e16132ee2a98c3347d.tar.gz
kernel-omap-d97b46a64674a267bc41c9e16132ee2a98c3347d.tar.xz
kernel-omap-d97b46a64674a267bc41c9e16132ee2a98c3347d.zip
syscalls, x86: add __NR_kcmp syscall
While doing the checkpoint-restore in the user space one need to determine whether various kernel objects (like mm_struct-s of file_struct-s) are shared between tasks and restore this state. The 2nd step can be solved by using appropriate CLONE_ flags and the unshare syscall, while there's currently no ways for solving the 1st one. One of the ways for checking whether two tasks share e.g. mm_struct is to provide some mm_struct ID of a task to its proc file, but showing such info considered to be not that good for security reasons. Thus after some debates we end up in conclusion that using that named 'comparison' syscall might be the best candidate. So here is it -- __NR_kcmp. It takes up to 5 arguments - the pids of the two tasks (which characteristics should be compared), the comparison type and (in case of comparison of files) two file descriptors. Lookups for pids are done in the caller's PID namespace only. At moment only x86 is supported and tested. [akpm@linux-foundation.org: fix up selftests, warnings] [akpm@linux-foundation.org: include errno.h] [akpm@linux-foundation.org: tweak comment text] Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Acked-by: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Pavel Emelyanov <xemul@parallels.com> Cc: Andrey Vagin <avagin@openvz.org> Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Glauber Costa <glommer@parallels.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Tejun Heo <tj@kernel.org> Cc: Matt Helsley <matthltc@us.ibm.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Vasiliy Kulikov <segoon@openwall.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Valdis.Kletnieks@vt.edu Cc: Michal Marek <mmarek@suse.cz> Cc: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/Makefile2
-rw-r--r--tools/testing/selftests/kcmp/Makefile29
-rw-r--r--tools/testing/selftests/kcmp/kcmp_test.c94
3 files changed, 124 insertions, 1 deletions
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 14972017a43e..a4162e15c25f 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,4 +1,4 @@
1TARGETS = breakpoints mqueue vm 1TARGETS = breakpoints kcmp mqueue vm
2 2
3all: 3all:
4 for TARGET in $(TARGETS); do \ 4 for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile
new file mode 100644
index 000000000000..dc79b86ea65c
--- /dev/null
+++ b/tools/testing/selftests/kcmp/Makefile
@@ -0,0 +1,29 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386)
4 ARCH := X86
5 CFLAGS := -DCONFIG_X86_32 -D__i386__
6endif
7ifeq ($(ARCH),x86_64)
8 ARCH := X86
9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__
10endif
11
12CFLAGS += -I../../../../arch/x86/include/generated/
13CFLAGS += -I../../../../include/
14CFLAGS += -I../../../../usr/include/
15CFLAGS += -I../../../../arch/x86/include/
16
17all:
18ifeq ($(ARCH),X86)
19 gcc $(CFLAGS) kcmp_test.c -o run_test
20else
21 echo "Not an x86 target, can't build kcmp selftest"
22endif
23
24run-tests: all
25 ./kcmp_test
26
27clean:
28 rm -fr ./run_test
29 rm -fr ./test-file
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c
new file mode 100644
index 000000000000..358cc6bfa35d
--- /dev/null
+++ b/tools/testing/selftests/kcmp/kcmp_test.c
@@ -0,0 +1,94 @@
1#define _GNU_SOURCE
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <signal.h>
6#include <limits.h>
7#include <unistd.h>
8#include <errno.h>
9#include <string.h>
10#include <fcntl.h>
11
12#include <linux/unistd.h>
13#include <linux/kcmp.h>
14
15#include <sys/syscall.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <sys/wait.h>
19
20static long sys_kcmp(int pid1, int pid2, int type, int fd1, int fd2)
21{
22 return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2);
23}
24
25int main(int argc, char **argv)
26{
27 const char kpath[] = "kcmp-test-file";
28 int pid1, pid2;
29 int fd1, fd2;
30 int status;
31
32 fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644);
33 pid1 = getpid();
34
35 if (fd1 < 0) {
36 perror("Can't create file");
37 exit(1);
38 }
39
40 pid2 = fork();
41 if (pid2 < 0) {
42 perror("fork failed");
43 exit(1);
44 }
45
46 if (!pid2) {
47 int pid2 = getpid();
48 int ret;
49
50 fd2 = open(kpath, O_RDWR, 0644);
51 if (fd2 < 0) {
52 perror("Can't open file");
53 exit(1);
54 }
55
56 /* An example of output and arguments */
57 printf("pid1: %6d pid2: %6d FD: %2ld FILES: %2ld VM: %2ld "
58 "FS: %2ld SIGHAND: %2ld IO: %2ld SYSVSEM: %2ld "
59 "INV: %2ld\n",
60 pid1, pid2,
61 sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd2),
62 sys_kcmp(pid1, pid2, KCMP_FILES, 0, 0),
63 sys_kcmp(pid1, pid2, KCMP_VM, 0, 0),
64 sys_kcmp(pid1, pid2, KCMP_FS, 0, 0),
65 sys_kcmp(pid1, pid2, KCMP_SIGHAND, 0, 0),
66 sys_kcmp(pid1, pid2, KCMP_IO, 0, 0),
67 sys_kcmp(pid1, pid2, KCMP_SYSVSEM, 0, 0),
68
69 /* This one should fail */
70 sys_kcmp(pid1, pid2, KCMP_TYPES + 1, 0, 0));
71
72 /* This one should return same fd */
73 ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd1);
74 if (ret) {
75 printf("FAIL: 0 expected but %d returned\n", ret);
76 ret = -1;
77 } else
78 printf("PASS: 0 returned as expected\n");
79
80 /* Compare with self */
81 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
82 if (ret) {
83 printf("FAIL: 0 expected but %li returned\n", ret);
84 ret = -1;
85 } else
86 printf("PASS: 0 returned as expected\n");
87
88 exit(ret);
89 }
90
91 waitpid(pid2, &status, P_ALL);
92
93 return 0;
94}