From: Stanislav Kinsbursky <skinsbursky@parallels.com>
To: akpm@linux-foundation.org
Cc: serge.hallyn@canonical.com, criu@openvz.org,
lucas.demarchi@profusion.mobi, linux-kernel@vger.kernel.org,
cmetcalf@tilera.com, dhowells@redhat.com
Subject: [PATCH 2/2] IPC: message queue stealing feature introduced
Date: Wed, 15 Feb 2012 20:54:39 +0400 [thread overview]
Message-ID: <20120215165439.27978.43513.stgit@localhost6.localdomain6> (raw)
In-Reply-To: <20120215163203.27978.52494.stgit@localhost6.localdomain6>
v2:
1) compat functions added.
2) message slot size in array is now aligned by struct msgbuf_a.
3) check for enough free space in buffer before message copying added.
4) if MSG_STEAL flag is set, then do_msgrcv() returns number of bytes written
to buffer.
5) flag MSG_NOERROR is ignored if MSG_STEAL flag is set.
This patch is required for checkpoint/restore in userspace.
IOW, c/r requires some way to get all pending IPC messages without deleting
them for the queue (checkpoint can fail and in this case tasks will be resumed,
so queue have to be valid).
To achive this, new operation flag MSG_STEAL for sys_msgrcv() system call
introduced.
If this flag is set, then passed struct msgbuf pointer will be used for storing
array of structures:
struct msgbuf_a {
long mtype; /* type of message */
int msize; /* size of message */
char mtext[0]; /* message text */
};
each of which will be followed by corresponding message data.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
include/linux/msg.h | 8 ++++++++
ipc/compat.c | 31 ++++++++++++++++++++++++++++++-
ipc/msg.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/include/linux/msg.h b/include/linux/msg.h
index 9411b76..5eb43a2 100644
--- a/include/linux/msg.h
+++ b/include/linux/msg.h
@@ -11,6 +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 */
/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct msqid_ds {
@@ -38,6 +39,13 @@ struct msgbuf {
char mtext[1]; /* message text */
};
+/* message buffer for msgrcv in case of array calls */
+struct msgbuf_a {
+ long mtype; /* type of message */
+ int msize; /* size of message */
+ char mtext[0]; /* message text */
+};
+
/* buffer for msgctl calls IPC_INFO, MSG_INFO */
struct msginfo {
int msgpool;
diff --git a/ipc/compat.c b/ipc/compat.c
index 38c1ee5..d2b34f8 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -38,6 +38,12 @@ struct compat_msgbuf {
char mtext[1];
};
+struct compat_msgbuf_a {
+ compat_long_t mtype;
+ int msize;
+ char mtext[0];
+};
+
struct compat_ipc_perm {
key_t key;
__compat_uid_t uid;
@@ -328,6 +334,27 @@ long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
return do_msgsnd(first, type, up->mtext, second, third);
}
+
+static long compat_do_msg_steal(void __user *dest, struct msg_msg *msg, size_t bufsz)
+{
+ struct compat_msgbuf_a __user *msgp = dest;
+ size_t msgsz;
+
+ msgsz = roundup(sizeof(struct msgbuf_a) + msg->m_ts,
+ __alignof__(struct msgbuf_a));
+
+ if (bufsz < msgsz)
+ return -E2BIG;
+
+ if (put_user(msg->m_type, &msgp->mtype))
+ return -EFAULT;
+ if (put_user(msg->m_ts, &msgp->msize))
+ return -EFAULT;
+ if (store_msg(msgp->mtext, msg, msg->m_ts))
+ return -EFAULT;
+ return msgsz;
+}
+
long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
{
struct compat_msgbuf __user *msgp;
@@ -359,7 +386,9 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
uptr = compat_ptr(ipck.msgp);
msgtyp = ipck.msgtyp;
}
- return do_msgrcv(first, uptr, second, msgtyp, third, compat_do_msg_fill);
+ return do_msgrcv(first, uptr, second, msgtyp, third,
+ (third & MSG_STEAL) ? compat_do_msg_steal
+ : compat_do_msg_fill);
}
static inline int get_compat_msqid64(struct msqid64_ds *m64,
diff --git a/ipc/msg.c b/ipc/msg.c
index 1d34c11..64f83b6 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -762,6 +762,33 @@ 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)
+{
+ struct msgbuf_a __user *msgp = dest;
+ size_t msgsz;
+
+ /*
+ * Message size have to be aligned.
+ */
+ msgsz = roundup(sizeof(struct msgbuf_a) + msg->m_ts,
+ __alignof__(struct msgbuf_a));
+
+ /*
+ * No need to support MSG_NOERROR flag because truncated message array
+ * is useless.
+ */
+ if (bufsz < msgsz)
+ return -E2BIG;
+
+ if (put_user(msg->m_type, &msgp->mtype))
+ return -EFAULT;
+ if (put_user(msg->m_ts, &msgp->msize))
+ return -EFAULT;
+ if (store_msg(msgp->mtext, msg, msg->m_ts))
+ return -EFAULT;
+ return msgsz;
+}
+
static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
{
struct msgbuf __user *msgp = dest;
@@ -784,6 +811,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
struct msg_msg *msg;
int mode;
struct ipc_namespace *ns;
+ size_t arrsz = bufsz;
if (msqid < 0 || (long) bufsz < 0)
return -EINVAL;
@@ -817,6 +845,16 @@ 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) {
+ long ret;
+
+ ret = msg_fill(buf, msg, arrsz);
+ if (ret < 0) {
+ msg = ERR_PTR(ret);
+ goto out_unlock;
+ }
+ buf += ret;
+ arrsz -= ret;
} else {
msg = walk_msg;
break;
@@ -825,6 +863,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
tmp = tmp->next;
}
if (!IS_ERR(msg)) {
+ if (msgflg & MSG_STEAL)
+ goto out_unlock;
/*
* Found a suitable message.
* Unlink it from the queue.
@@ -919,6 +959,9 @@ out_unlock:
if (IS_ERR(msg))
return PTR_ERR(msg);
+ if (msgflg & MSG_STEAL)
+ return bufsz - arrsz;
+
bufsz = msg_fill(buf, msg, bufsz);
free_msg(msg);
@@ -928,7 +971,8 @@ out_unlock:
SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
long, msgtyp, int, msgflg)
{
- return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
+ return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg,
+ (msgflg & MSG_STEAL) ? do_msg_steal : do_msg_fill);
}
#ifdef CONFIG_PROC_FS
next prev parent reply other threads:[~2012-02-15 16:55 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-02-15 16:54 [PATCH 0/2] IPC: message queue checkpoint support Stanislav Kinsbursky
2012-02-15 16:54 ` [PATCH 1/2] IPC: message queue receive cleanup Stanislav Kinsbursky
2012-04-04 23:05 ` Andrew Morton
2012-04-04 23:39 ` Chris Metcalf
2012-02-15 16:54 ` Stanislav Kinsbursky [this message]
2012-04-04 23:12 ` [PATCH 2/2] IPC: message queue stealing feature introduced Andrew Morton
2012-04-04 23:50 ` Michael Kerrisk (man-pages)
2012-04-04 23:59 ` Michael Kerrisk
2012-04-05 11:42 ` Stanislav Kinsbursky
2012-04-05 10:53 ` Stanislav Kinsbursky
2012-03-05 13:04 ` [CRIU] [PATCH 0/2] IPC: message queue checkpoint support Kinsbursky Stanislav
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120215165439.27978.43513.stgit@localhost6.localdomain6 \
--to=skinsbursky@parallels.com \
--cc=akpm@linux-foundation.org \
--cc=cmetcalf@tilera.com \
--cc=criu@openvz.org \
--cc=dhowells@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lucas.demarchi@profusion.mobi \
--cc=serge.hallyn@canonical.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox