IPC: message queue checkpoint/restore - requested updates
cover IPC: message queue checkpoint/restore - requested updates
This patch set updates IPC checkpoint/restore support according to discussion of previous patch set named "IPC: message queue checkpoint support". What has been changed:
1) MSG_STEAL was replaced by MSG_PEEK_ALL (as suggested by Michael Kerrisk)
2) All checkpoint/restore code has been put under CONFIG_CHECKPOINT_RESTORE define.
3) Added return of ENOSYS in case of sys_msgrcv was called with MSG_PEEK_ALL flag, but kernel was compiled without checkpoint/restore support.
4) Test for support of SYSV IPC message queues checkpoint/restore added to the series. Test file: msgque.c
Michael, please, tell me, what I have to do (or provide) to update man page accordingly.
The following series consists of:
---
Stanislav Kinsbursky (4):
ipc: rename obfuscating MSG_STEAL flag into MSG_PEEK_ALL
ipc: move all checkpoint-restore code under appropriate define
ipc: handle MSG_PEEK_ALL flag if CONFIG_CHECKPOINT_RESTORE is dropped
test: IPC message queue migration test
include/linux/msg.h | 2 - ipc/compat.c | 16 ++++- ipc/msg.c | 27 +++++++-- msgque.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 11 deletions(-) create mode 100644 msgque.c
PATCH 1/4 ipc: rename obfuscating MSG_STEAL flag into MSG_PEEK_ALL
MSG_PEEK_ALL looks familiar because MSG_PEEK for one socket message is used already.
--- include/linux/msg.h | 2 +- ipc/compat.c | 6 +++--- ipc/msg.c | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-)
include/linux/msg.h +1 -1
@@ -11,7 +11,7 @@/* msgrcv options */ #define MSG_NOERROR 010000/* no error if message is too big */ #define MSG_EXCEPT 020000/* recv any msg except of specified type.*/ -#define MSG_STEAL 040000/* copy (not remove) all queue messages */ +#define MSG_PEEK_ALL 040000/* copy (not remove) all queue messages */ /* Obsolete, used only for backwards compatibility and libc5 compiles */ struct msqid_ds {
ipc/compat.c +3 -3
@@ -335,7 +335,7 @@ long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) } -static long compat_do_msg_steal (void __user *dest,struct msg_msg *msg,size_t bufsz) +static long compat_do_msg_peek_all (void __user *dest,struct msg_msg *msg,size_t bufsz) {struct compat_msgbuf_a __user *msgp = dest;size_t msgsz;
@@ -387,8 +387,8 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third, msgtyp = ipck.msgtyp; }return do_msgrcv (first, uptr, second, msgtyp, third, - (third &MSG_STEAL ) ? compat_do_msg_steal - : compat_do_msg_fill); + (third &MSG_PEEK_ALL ) ? compat_do_msg_peek_all + : compat_do_msg_fill); } static inline int get_compat_msqid64(struct msqid64_ds *m64,
ipc/msg.c +5 -5
@@ -762,7 +762,7 @@ static inline int convert_mode(long *msgtyp, int msgflg)return SEARCH_EQUAL ; } -static long do_msg_steal (void __user *dest,struct msg_msg *msg,size_t bufsz) +static long do_msg_peek_all (void __user *dest,struct msg_msg *msg,size_t bufsz) {struct msgbuf_a __user *msgp = dest;size_t msgsz;
@@ -845,7 +845,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, walk_msg->m_type != 1) { msg = walk_msg; msgtyp = walk_msg->m_type -1 ; - } else if (msgflg & MSG_STEAL) { + } else if (msgflg & MSG_PEEK_ALL) {long ret; ret =msg_fill (buf, msg, arrsz);
@@ -863,7 +863,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, tmp = tmp->next; }if (!IS_ERR (msg)) { -if (msgflg &MSG_STEAL ) +if (msgflg &MSG_PEEK_ALL ) goto out_unlock;/* * Found a suitable message.
@@ -959,7 +959,7 @@ out_unlock:if (IS_ERR (msg))return PTR_ERR (msg); -if (msgflg &MSG_STEAL ) +if (msgflg &MSG_PEEK_ALL )return bufsz - arrsz; bufsz =msg_fill (buf, msg, bufsz);
@@ -972,7 +972,7 @@ SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, long, msgtyp, int, msgflg) { return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, - (msgflg & MSG_STEAL) ? do_msg_steal : do_msg_fill); + (msgflg & MSG_PEEK_ALL) ? do_msg_peek_all : do_msg_fill); }#ifdef CONFIG_PROC_FS
PATCH 2/4 ipc: move all checkpoint-restore code under appropriate define
In reply to Stanislav KinsburskyAll new checkpoint/restore code parts are now covered with CONFIG_CHECKPOINT_RESTORE marco. So it would be easy to remove them, in case the whole project fails.
--- ipc/compat.c | 9 ++++++--- ipc/msg.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-)
ipc/compat.c +6 -3
@@ -334,7 +334,7 @@ long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)return do_msgsnd (first, type, up->mtext, second, third); } - +#ifdef CONFIG_CHECKPOINT_RESTORE static long compat_do_msg_peek_all (void __user *dest,struct msg_msg *msg,size_t bufsz) {struct compat_msgbuf_a __user *msgp = dest;
@@ -354,6 +354,7 @@ static long compat_do_msg_peek_all(void __user *dest, struct msg_msg *msg, size_return -EFAULT ; return msgsz; } +#endif long compat_do_msg_fill (void __user *dest,struct msg_msg *msg,size_t bufsz) {
@@ -387,8 +388,10 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third, msgtyp = ipck.msgtyp; }return do_msgrcv (first, uptr, second, msgtyp, third, - (third &MSG_PEEK_ALL ) ? compat_do_msg_peek_all - : compat_do_msg_fill); +#ifdef CONFIG_CHECKPOINT_RESTORE + (third &MSG_PEEK_ALL ) ? compat_do_msg_peek_all : +#endif + compat_do_msg_fill); } static inline int get_compat_msqid64(struct msqid64_ds *m64,
ipc/msg.c +14 -1
@@ -762,6 +762,7 @@ static inline int convert_mode(long *msgtyp, int msgflg)return SEARCH_EQUAL ; } +#ifdef CONFIG_CHECKPOINT_RESTORE static long do_msg_peek_all (void __user *dest,struct msg_msg *msg,size_t bufsz) {struct msgbuf_a __user *msgp = dest;
@@ -788,6 +789,7 @@ static long do_msg_peek_all(void __user *dest, struct msg_msg *msg, size_t bufszreturn -EFAULT ; return msgsz; } +#endif static long do_msg_fill (void __user *dest,struct msg_msg *msg,size_t bufsz) {
@@ -811,7 +813,9 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,struct msg_msg *msg;int mode;struct ipc_namespace *ns; +#ifdef CONFIG_CHECKPOINT_RESTORE size_t arrsz = bufsz; +#endif if (msqid <0 || (long ) bufsz <0 )return -EINVAL ;
@@ -845,6 +849,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, walk_msg->m_type != 1) { msg = walk_msg; msgtyp = walk_msg->m_type -1 ; +#ifdef CONFIG_CHECKPOINT_RESTORE } else if (msgflg & MSG_PEEK_ALL) {long ret;
@@ -855,6 +860,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, } buf += ret; arrsz -= ret; +#endif }else { msg = walk_msg;break ;
@@ -863,8 +869,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, tmp = tmp->next; }if (!IS_ERR (msg)) { +#ifdef CONFIG_CHECKPOINT_RESTORE if (msgflg &MSG_PEEK_ALL ) goto out_unlock; +#endif /* * Found a suitable message. * Unlink it from the queue.
@@ -959,8 +967,10 @@ out_unlock:if (IS_ERR (msg))return PTR_ERR (msg); +#ifdef CONFIG_CHECKPOINT_RESTORE if (msgflg &MSG_PEEK_ALL )return bufsz - arrsz; +#endif bufsz =msg_fill (buf, msg, bufsz);free_msg (msg);
@@ -972,7 +982,10 @@ SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, long, msgtyp, int, msgflg) { return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, - (msgflg & MSG_PEEK_ALL) ? do_msg_peek_all : do_msg_fill); +#ifdef CONFIG_CHECKPOINT_RESTORE + (msgflg & MSG_PEEK_ALL) ? do_msg_peek_all : +#endif + do_msg_fill); }#ifdef CONFIG_PROC_FS
Re: [CRIU] [PATCH 2/4] ipc: move all checkpoint-restore code under appropriate define
Quoted 10 lines · Stanislav Kinsbursky
All new checkpoint/restore code parts are now covered with
CONFIG_CHECKPOINT_RESTOREmarco. So it would be easy to remove them, in case the whole project fails.--- ipc/compat.c | 9 ++++++--- ipc/msg.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-)
ipc/compat.c long compat_sys_msgrcv(int first, int second, int msgtyp, int third, · line 394
Quoted 9 lines
ipc/compat.c +4
-2@@ -387,8 +388,10 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third, msgtyp = ipck.msgtyp; }return do_msgrcv (first, uptr, second, msgtyp, third, - (third &MSG_PEEK_ALL ) ? compat_do_msg_peek_all - : compat_do_msg_fill); +#ifdef CONFIG_CHECKPOINT_RESTORE + (third &MSG_PEEK_ALL ) ? compat_do_msg_peek_all : +#endif + compat_do_msg_fill);
These ifdefs in the middle of the code look not very elegant. Is there a way to replace the checks they surround with static inline function (reporting 0 when CHECKPOINT_RESTORE is off) potentially letting the compiler optimize out the code sitting under if (0) ?
Quoted 5 lines
ipc/compat.c +0
-0} static inline int get_compat_msqid64(struct msqid64_ds *m64,ipc/msg.c +0
-0
Re: [CRIU] [PATCH 2/4] ipc: move all checkpoint-restore code under appropriate define
09.04.2012 23:47, Pavel Emelyanov пишет:
Quoted 10 lines · Stanislav Kinsbursky
Quoted 9 lines
All new checkpoint/restore code parts are now covered with
CONFIG_CHECKPOINT_RESTOREmarco. So it would be easy to remove them, in case the whole project fails.--- ipc/compat.c | 9 ++++++--- ipc/msg.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-)
Quoted 16 lines
ipc/compat.c long compat_sys_msgrcv(int first, int second, int msgtyp, int third, · line 394
Quoted 10 lines
ipc/compat.c +4
-2@@ -387,8 +388,10 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third, msgtyp = ipck.msgtyp; }return do_msgrcv (first, uptr, second, msgtyp, third, - (third&MSG_PEEK_ALL ) ? compat_do_msg_peek_all - : compat_do_msg_fill); +#ifdef CONFIG_CHECKPOINT_RESTORE + (third&MSG_PEEK_ALL ) ? compat_do_msg_peek_all : +#endif + compat_do_msg_fill);These ifdefs in the middle of the code look not very elegant. Is there a way to replace the checks they surround with static inline function (reporting 0 when
CHECKPOINT_RESTOREis off) potentially letting the compiler optimize out the code sitting under if (0) ?
Yes, sure. I'll do this.
Signature · 2 lines
Best regards, Stanislav Kinsbursky
PATCH v2 2/4 ipc: move all checkpoint-restore code under appropriate define
In reply to Pavel Emelyanovv2: added dummy compat_do_msg_peek_all() and do_msg_peek_all() functions used in case of CONFIG_CHECKPOINT_RESTORE is not defined.
All new checkpoint/restore code parts are now covered with CONFIG_CHECKPOINT_RESTORE macro. So it would be easy to remove them, in case the whole project fails.
--- ipc/compat.c | 8 +++++++- ipc/msg.c | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletions(-)
ipc/compat.c +1 -1
@@ -334,7 +334,7 @@ long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)return do_msgsnd (first, type, up->mtext, second, third); } - +#ifdef CONFIG_CHECKPOINT_RESTORE static long compat_do_msg_peek_all(void __user *dest, struct msg_msg *msg,
size_t bufsz)
{
struct compat_msgbuf_a __user *msgp = dest;
@@ -354,6 +354,12 @@ static long compat_do_msg_peek_all(void __user *dest, struct msg_msg *msg, size_
return -EFAULT;
return msgsz; }
+#else
+static long compat_do_msg_peek_all(void __user *dest, struct msg_msg *msg, size_t bufsz) +{
+ return -EINVAL;
+}
+#endif
long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) {
ipc/msg.c +15 -0
@@ -762,6 +762,7 @@ static inline int convert_mode(long *msgtyp, int msgflg)return SEARCH_EQUAL ; } +#ifdef CONFIG_CHECKPOINT_RESTORE static long do_msg_peek_all (void __user *dest,struct msg_msg *msg,size_t bufsz) {struct msgbuf_a __user *msgp = dest;
@@ -788,6 +789,12 @@ static long do_msg_peek_all(void __user *dest, struct msg_msg *msg, size_t bufszreturn -EFAULT ; return msgsz; } +#else +static long do_msg_peek_all (void __user *dest,struct msg_msg *msg,size_t bufsz) +{ +return -EINVAL ; +} +#endif static long do_msg_fill (void __user *dest,struct msg_msg *msg,size_t bufsz) {
@@ -811,7 +818,9 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,struct msg_msg *msg;int mode;struct ipc_namespace *ns; +#ifdef CONFIG_CHECKPOINT_RESTORE size_t arrsz = bufsz; +#endif if (msqid <0 || (long ) bufsz <0 )return -EINVAL ;
@@ -845,6 +854,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, walk_msg->m_type != 1) { msg = walk_msg; msgtyp = walk_msg->m_type -1 ; +#ifdef CONFIG_CHECKPOINT_RESTORE } else if (msgflg & MSG_PEEK_ALL) {long ret;
@@ -855,6 +865,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, } buf += ret; arrsz -= ret; +#endif }else { msg = walk_msg;break ;
@@ -863,8 +874,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, tmp = tmp->next; }if (!IS_ERR (msg)) { +#ifdef CONFIG_CHECKPOINT_RESTORE if (msgflg &MSG_PEEK_ALL ) goto out_unlock; +#endif /* * Found a suitable message. * Unlink it from the queue.
@@ -959,8 +972,10 @@ out_unlock:if (IS_ERR (msg))return PTR_ERR (msg); +#ifdef CONFIG_CHECKPOINT_RESTORE if (msgflg &MSG_PEEK_ALL )return bufsz - arrsz; +#endif bufsz =msg_fill (buf, msg, bufsz);free_msg (msg);
PATCH 3/4 ipc: handle MSG_PEEK_ALL flag if CONFIG_CHECKPOINT_RESTORE is dropped
In reply to Stanislav KinsburskyReturn -ENOSYS, if user called sys_msgrcv() with MSG_PEEK_ALL flag set and checkpoint/restore code wasn't compiled.
--- ipc/compat.c | 5 ++++- ipc/msg.c | 4 ++++ 2 files changed, 8 insertions(+), 1 deletions(-)
ipc/compat.c +4 -1
@@ -377,7 +377,10 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third,return -EINVAL ;if (second <0 )return -EINVAL ; - +#ifndef CONFIG_CHECKPOINT_RESTORE +if (third &MSG_PEEK_ALL ) +return -ENOSYS ; +#endif if (!version) {struct compat_ipc_kludge ipck;if (!uptr)
ipc/msg.c +4 -0
@@ -819,6 +819,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,if (msqid <0 || (long ) bufsz <0 )return -EINVAL ; +#ifndef CONFIG_CHECKPOINT_RESTORE +if (msgflg &MSG_PEEK_ALL ) +return -ENOSYS ; +#endif mode =convert_mode (&msgtyp, msgflg); ns = current->nsproxy->ipc_ns;
PATCH 4/4 test: IPC message queue migration test
In reply to Stanislav KinsburskyThis test is a part of CRIU development test suit.
--- msgque.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 151 insertions(+), 0 deletions(-) create mode 100644 msgque.c
msgque.c new file +151 -0
@@ -0,0 +1,151 @@ +#define _GNU_SOURCE +#include <sched.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/sem.h> +#include <sys/ipc.h> +#include <sys/msg.h> +#include <signal.h> +#include <errno.h> + +#include "zdtmtst.h" + +const char *test_doc="Tests sysv5 msg queues supporting by checkpointing" ; +const char *test_author="Stanislav Kinsbursky <[email protected]>" ; + +struct msg1 { +long mtype; +char mtext[20 ]; +}; +#define TEST_STRING "Test sysv5 msg" +#define MSG_TYPE 1 + +#define ANOTHER_TEST_STRING "Yet another test sysv5 msg" +#define ANOTHER_MSG_TYPE 26538 + +static int test_fn (int argc,char **argv) +{ +key_t key; +int msg, pid; +struct msg1 msgbuf; +int chret; + + key =ftok (argv[0 ],822155650 ); +if (key ==-1 ) { +err ("Can't make key" ); +exit (1 ); + } + + pid =test_fork (); +if (pid <0 ) { +err ("Can't fork" ); +exit (1 ); + } + + msg =msgget (key,IPC_CREAT |IPC_EXCL |0666 ); +if (msg ==-1 ) { + msg =msgget (key,0666 ); +if (msg ==-1 ) { +err ("Can't get queue" ); + goto err_kill; + } + } + +if (pid ==0 ) { +/* +* Here is the place where test sleeps and waits for signal. +* This place is used for suspend/restore test. +*/ +test_waitsig (); + +if (msgrcv (msg, &msgbuf,sizeof (TEST_STRING ),MSG_TYPE ,IPC_NOWAIT ) ==-1 ) { +fail ("Child: msgrcv failed (%m)" ); +return -errno; + } + +if (strncmp (TEST_STRING , msgbuf.mtext,sizeof (TEST_STRING ))) { +fail ("Child: the source and received strings aren't equal" ); +return -errno; + } +test_msg ("Child: received %s\n" , msgbuf.mtext); + + msgbuf.mtype =ANOTHER_MSG_TYPE ; +memcpy (msgbuf.mtext,ANOTHER_TEST_STRING ,sizeof (ANOTHER_TEST_STRING )); +if (msgsnd (msg, &msgbuf,sizeof (ANOTHER_TEST_STRING ),IPC_NOWAIT ) !=0 ) { +fail ("Child: msgsnd failed (%m)" ); +return -errno; + }; +pass (); +return 0 ; + }else { + msgbuf.mtype =MSG_TYPE ; +memcpy (msgbuf.mtext,TEST_STRING ,sizeof (TEST_STRING )); +if (msgsnd (msg, &msgbuf,sizeof (TEST_STRING ),IPC_NOWAIT ) !=0 ) { +fail ("Parent: msgsnd failed (%m)" ); + goto err_kill; + }; + + msgbuf.mtype =ANOTHER_MSG_TYPE ; +memcpy (msgbuf.mtext,ANOTHER_TEST_STRING ,sizeof (ANOTHER_TEST_STRING )); +if (msgsnd (msg, &msgbuf,sizeof (ANOTHER_TEST_STRING ),IPC_NOWAIT ) !=0 ) { +fail ("child: msgsnd (2) failed (%m)" ); +return -errno; + }; + +test_daemon (); +test_waitsig (); + +kill (pid,SIGTERM ); + +wait (&chret); + chret =WEXITSTATUS (chret); +if (chret) { +fail ("Parent: child exited with non-zero code %d (%s)\n" , + chret,strerror (chret)); + goto out; + } + +if (msgrcv (msg, &msgbuf,sizeof (ANOTHER_TEST_STRING ),ANOTHER_MSG_TYPE ,IPC_NOWAIT ) ==-1 ) { +fail ("Parent: msgrcv failed (%m)" ); + goto err; + } + +if (strncmp (ANOTHER_TEST_STRING , msgbuf.mtext,sizeof (ANOTHER_TEST_STRING ))) { +fail ("Parent: the source and received strings aren't equal" ); + goto err; + } +test_msg ("Parent: received %s\n" , msgbuf.mtext); + +pass (); + } + +out: +if (msgctl (msg,IPC_RMID ,0 )) { +fail ("Failed to destroy message queue: %d\n" , -errno); +return -errno; + } +return chret; + +err_kill: +kill (pid,SIGKILL ); +wait (NULL ); +err: + chret = -errno; + goto out; +} + +int main (int argc,char **argv) +{ +#ifdef NEW_IPC_NS +test_init_ns (argc, argv,CLONE_NEWIPC , test_fn); +#else +test_init (argc, argv); +test_fn (); +#endif +return 0 ; +}
Re: [PATCH 4/4] test: IPC message queue migration test
Quoted 4 lines · On Mon, 09 Apr 2012 21:54:19 +0400 Stanislav Kinsbursky…
This test is a part of CRIU development test suit.
--- msgque.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Neat. Can you please integrate this into tools/testing/selftests? You'll need to decide whether it should be under tools/testing/selftests/checkpoint-restore or tools/testing/selftests/ipc. Perhaps the former, as you guys will hopefully have more userspace test harnesses?
Also, I suggest that I throw away the current c-r-ipc-message-queue-stealing-feature-introduced.patch. Please fold all the changes you've made to that patch into a single patch and resend the whole series. I guess that will be two patches:
c-r-ipc-message-queue-stealing-feature-introduced-v2 and the tools/testing/selftests/ addition.