aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStanislav Kinsbursky <skinsbursky@parallels.com>2013-01-04 18:34:56 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-01-04 19:11:45 -0500
commit3a665531a3b7c2ad2c87903b24646be6916340e4 (patch)
tree9f5186e3b9786216a74c092b6652d958abc8e2a9
parent4a674f34ba04a002244edaf891b5da7fc1473ae8 (diff)
selftests: IPC message queue copy feature test
This test can be used to check wheither kernel supports IPC message queue copy and restore features (required by CRIU project). Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Cc: Serge Hallyn <serge.hallyn@canonical.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Pavel Emelyanov <xemul@parallels.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/msg.h3
-rw-r--r--ipc/compat.c3
-rw-r--r--tools/testing/selftests/ipc/Makefile25
-rw-r--r--tools/testing/selftests/ipc/msgque.c246
4 files changed, 275 insertions, 2 deletions
diff --git a/include/linux/msg.h b/include/linux/msg.h
index fc5743a554e6..391af8d11cce 100644
--- a/include/linux/msg.h
+++ b/include/linux/msg.h
@@ -36,6 +36,7 @@ extern long do_msgsnd(int msqid, long mtype, void __user *mtext,
36 size_t msgsz, int msgflg); 36 size_t msgsz, int msgflg);
37extern long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, 37extern long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
38 int msgflg, 38 int msgflg,
39 long (*msg_fill)(void __user *, struct msg_msg *, size_t)); 39 long (*msg_fill)(void __user *, struct msg_msg *,
40 size_t));
40 41
41#endif /* _LINUX_MSG_H */ 42#endif /* _LINUX_MSG_H */
diff --git a/ipc/compat.c b/ipc/compat.c
index eb3ea16d2d1d..2547f29dcd1b 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -365,7 +365,8 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
365 uptr = compat_ptr(ipck.msgp); 365 uptr = compat_ptr(ipck.msgp);
366 msgtyp = ipck.msgtyp; 366 msgtyp = ipck.msgtyp;
367 } 367 }
368 return do_msgrcv(first, uptr, second, msgtyp, third, compat_do_msg_fill); 368 return do_msgrcv(first, uptr, second, msgtyp, third,
369 compat_do_msg_fill);
369} 370}
370#else 371#else
371long compat_sys_semctl(int semid, int semnum, int cmd, int arg) 372long compat_sys_semctl(int semid, int semnum, int cmd, int arg)
diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile
new file mode 100644
index 000000000000..5386fd7c43ae
--- /dev/null
+++ b/tools/testing/selftests/ipc/Makefile
@@ -0,0 +1,25 @@
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../../../../usr/include/
13
14all:
15ifeq ($(ARCH),X86)
16 gcc $(CFLAGS) msgque.c -o msgque_test
17else
18 echo "Not an x86 target, can't build msgque selftest"
19endif
20
21run_tests: all
22 ./msgque_test
23
24clean:
25 rm -fr ./msgque_test
diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c
new file mode 100644
index 000000000000..d66418237d21
--- /dev/null
+++ b/tools/testing/selftests/ipc/msgque.c
@@ -0,0 +1,246 @@
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <errno.h>
5#include <linux/msg.h>
6#include <fcntl.h>
7
8#define MAX_MSG_SIZE 32
9
10struct msg1 {
11 int msize;
12 long mtype;
13 char mtext[MAX_MSG_SIZE];
14};
15
16#define TEST_STRING "Test sysv5 msg"
17#define MSG_TYPE 1
18
19#define ANOTHER_TEST_STRING "Yet another test sysv5 msg"
20#define ANOTHER_MSG_TYPE 26538
21
22struct msgque_data {
23 key_t key;
24 int msq_id;
25 int qbytes;
26 int qnum;
27 int mode;
28 struct msg1 *messages;
29};
30
31int restore_queue(struct msgque_data *msgque)
32{
33 int fd, ret, id, i;
34 char buf[32];
35
36 fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY);
37 if (fd == -1) {
38 printf("Failed to open /proc/sys/kernel/msg_next_id\n");
39 return -errno;
40 }
41 sprintf(buf, "%d", msgque->msq_id);
42
43 ret = write(fd, buf, strlen(buf));
44 if (ret != strlen(buf)) {
45 printf("Failed to write to /proc/sys/kernel/msg_next_id\n");
46 return -errno;
47 }
48
49 id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL);
50 if (id == -1) {
51 printf("Failed to create queue\n");
52 return -errno;
53 }
54
55 if (id != msgque->msq_id) {
56 printf("Restored queue has wrong id (%d instead of %d)\n",
57 id, msgque->msq_id);
58 ret = -EFAULT;
59 goto destroy;
60 }
61
62 for (i = 0; i < msgque->qnum; i++) {
63 if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype,
64 msgque->messages[i].msize, IPC_NOWAIT) != 0) {
65 printf("msgsnd failed (%m)\n");
66 ret = -errno;
67 goto destroy;
68 };
69 }
70 return 0;
71
72destroy:
73 if (msgctl(id, IPC_RMID, 0))
74 printf("Failed to destroy queue: %d\n", -errno);
75 return ret;
76}
77
78int check_and_destroy_queue(struct msgque_data *msgque)
79{
80 struct msg1 message;
81 int cnt = 0, ret;
82
83 while (1) {
84 ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE,
85 0, IPC_NOWAIT);
86 if (ret < 0) {
87 if (errno == ENOMSG)
88 break;
89 printf("Failed to read IPC message: %m\n");
90 ret = -errno;
91 goto err;
92 }
93 if (ret != msgque->messages[cnt].msize) {
94 printf("Wrong message size: %d (expected %d)\n", ret,
95 msgque->messages[cnt].msize);
96 ret = -EINVAL;
97 goto err;
98 }
99 if (message.mtype != msgque->messages[cnt].mtype) {
100 printf("Wrong message type\n");
101 ret = -EINVAL;
102 goto err;
103 }
104 if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) {
105 printf("Wrong message content\n");
106 ret = -EINVAL;
107 goto err;
108 }
109 cnt++;
110 }
111
112 if (cnt != msgque->qnum) {
113 printf("Wrong message number\n");
114 ret = -EINVAL;
115 goto err;
116 }
117
118 ret = 0;
119err:
120 if (msgctl(msgque->msq_id, IPC_RMID, 0)) {
121 printf("Failed to destroy queue: %d\n", -errno);
122 return -errno;
123 }
124 return ret;
125}
126
127int dump_queue(struct msgque_data *msgque)
128{
129 struct msqid64_ds ds;
130 int kern_id;
131 int i, ret;
132
133 for (kern_id = 0; kern_id < 256; kern_id++) {
134 ret = msgctl(kern_id, MSG_STAT, &ds);
135 if (ret < 0) {
136 if (errno == -EINVAL)
137 continue;
138 printf("Failed to get stats for IPC queue with id %d\n",
139 kern_id);
140 return -errno;
141 }
142
143 if (ret == msgque->msq_id)
144 break;
145 }
146
147 msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum);
148 if (msgque->messages == NULL) {
149 printf("Failed to get stats for IPC queue\n");
150 return -ENOMEM;
151 }
152
153 msgque->qnum = ds.msg_qnum;
154 msgque->mode = ds.msg_perm.mode;
155 msgque->qbytes = ds.msg_qbytes;
156
157 for (i = 0; i < msgque->qnum; i++) {
158 ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype,
159 MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY);
160 if (ret < 0) {
161 printf("Failed to copy IPC message: %m (%d)\n", errno);
162 return -errno;
163 }
164 msgque->messages[i].msize = ret;
165 }
166 return 0;
167}
168
169int fill_msgque(struct msgque_data *msgque)
170{
171 struct msg1 msgbuf;
172
173 msgbuf.mtype = MSG_TYPE;
174 memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING));
175 if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING),
176 IPC_NOWAIT) != 0) {
177 printf("First message send failed (%m)\n");
178 return -errno;
179 };
180
181 msgbuf.mtype = ANOTHER_MSG_TYPE;
182 memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING));
183 if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING),
184 IPC_NOWAIT) != 0) {
185 printf("Second message send failed (%m)\n");
186 return -errno;
187 };
188 return 0;
189}
190
191int main(int argc, char **argv)
192{
193 int msg, pid, err;
194 struct msgque_data msgque;
195
196 msgque.key = ftok(argv[0], 822155650);
197 if (msgque.key == -1) {
198 printf("Can't make key\n");
199 return -errno;
200 }
201
202 msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
203 if (msgque.msq_id == -1) {
204 printf("Can't create queue\n");
205 goto err_out;
206 }
207
208 err = fill_msgque(&msgque);
209 if (err) {
210 printf("Failed to fill queue\n");
211 goto err_destroy;
212 }
213
214 err = dump_queue(&msgque);
215 if (err) {
216 printf("Failed to dump queue\n");
217 goto err_destroy;
218 }
219
220 err = check_and_destroy_queue(&msgque);
221 if (err) {
222 printf("Failed to check and destroy queue\n");
223 goto err_out;
224 }
225
226 err = restore_queue(&msgque);
227 if (err) {
228 printf("Failed to restore queue\n");
229 goto err_destroy;
230 }
231
232 err = check_and_destroy_queue(&msgque);
233 if (err) {
234 printf("Failed to test queue\n");
235 goto err_out;
236 }
237 return 0;
238
239err_destroy:
240 if (msgctl(msgque.msq_id, IPC_RMID, 0)) {
241 printf("Failed to destroy queue: %d\n", -errno);
242 return -errno;
243 }
244err_out:
245 return err;
246}