From 9afdacda0252fc1ddb7907728e878518edbcdfce Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 4 Jan 2013 15:34:47 -0800 Subject: ipc: remove forced assignment of selected message This is a cleanup patch. The assignment is redundant. Signed-off-by: Stanislav Kinsbursky Cc: Serge Hallyn Cc: "Eric W. Biederman" Cc: Pavel Emelyanov Cc: Al Viro Cc: KOSAKI Motohiro Cc: Michael Kerrisk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index a71af5a65abf..2f272fa76595 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -793,12 +793,9 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext, msg = walk_msg; if (mode == SEARCH_LESSEQUAL && walk_msg->m_type != 1) { - msg = walk_msg; msgtyp = walk_msg->m_type - 1; - } else { - msg = walk_msg; + } else break; - } } tmp = tmp->next; } -- cgit From f9dd87f4738c7555aca2cdf8cb2b2326cafb0cad Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 4 Jan 2013 15:34:52 -0800 Subject: ipc: message queue receive cleanup Move all message related manipulation into one function msg_fill(). Actually, two functions because of the compat one. [akpm@linux-foundation.org: checkpatch fixes] Signed-off-by: Stanislav Kinsbursky Cc: Serge Hallyn Cc: "Eric W. Biederman" Cc: Pavel Emelyanov Cc: Al Viro Cc: KOSAKI Motohiro Cc: Michael Kerrisk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index 2f272fa76595..cefc24f46e3e 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -755,15 +755,30 @@ static inline int convert_mode(long *msgtyp, int msgflg) return SEARCH_EQUAL; } -long do_msgrcv(int msqid, long *pmtype, void __user *mtext, - size_t msgsz, long msgtyp, int msgflg) +static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) +{ + struct msgbuf __user *msgp = dest; + size_t msgsz; + + if (put_user(msg->m_type, &msgp->mtype)) + return -EFAULT; + + msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; + if (store_msg(msgp->mtext, msg, msgsz)) + return -EFAULT; + return msgsz; +} + +long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, + int msgflg, + long (*msg_handler)(void __user *, struct msg_msg *, size_t)) { struct msg_queue *msq; struct msg_msg *msg; int mode; struct ipc_namespace *ns; - if (msqid < 0 || (long) msgsz < 0) + if (msqid < 0 || (long) bufsz < 0) return -EINVAL; mode = convert_mode(&msgtyp, msgflg); ns = current->nsproxy->ipc_ns; @@ -804,7 +819,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext, * Found a suitable message. * Unlink it from the queue. */ - if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { + if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { msg = ERR_PTR(-E2BIG); goto out_unlock; } @@ -831,7 +846,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext, if (msgflg & MSG_NOERROR) msr_d.r_maxsize = INT_MAX; else - msr_d.r_maxsize = msgsz; + msr_d.r_maxsize = bufsz; msr_d.r_msg = ERR_PTR(-EAGAIN); current->state = TASK_INTERRUPTIBLE; msg_unlock(msq); @@ -894,29 +909,16 @@ out_unlock: if (IS_ERR(msg)) return PTR_ERR(msg); - msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; - *pmtype = msg->m_type; - if (store_msg(mtext, msg, msgsz)) - msgsz = -EFAULT; - + bufsz = msg_handler(buf, msg, bufsz); free_msg(msg); - return msgsz; + return bufsz; } SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, long, msgtyp, int, msgflg) { - long err, mtype; - - err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg); - if (err < 0) - goto out; - - if (put_user(mtype, &msgp->mtype)) - err = -EFAULT; -out: - return err; + return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill); } #ifdef CONFIG_PROC_FS -- cgit From 4a674f34ba04a002244edaf891b5da7fc1473ae8 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 4 Jan 2013 15:34:55 -0800 Subject: ipc: introduce message queue copy feature This patch is required for checkpoint/restore in userspace. c/r requires some way to get all pending IPC messages without deleting them from 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_COPY for sys_msgrcv() system call was introduced. If this flag was specified, then mtype is interpreted as number of the message to copy. If MSG_COPY is set, then kernel will allocate dummy message with passed size, and then use new copy_msg() helper function to copy desired message (instead of unlinking it from the queue). Notes: 1) Return -ENOSYS if MSG_COPY is specified, but CONFIG_CHECKPOINT_RESTORE is not set. Signed-off-by: Stanislav Kinsbursky Cc: Serge Hallyn Cc: "Eric W. Biederman" Cc: Pavel Emelyanov Cc: Al Viro Cc: KOSAKI Motohiro Cc: Michael Kerrisk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index cefc24f46e3e..d20ffc7d3f24 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -769,6 +769,45 @@ static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) return msgsz; } +#ifdef CONFIG_CHECKPOINT_RESTORE +static inline struct msg_msg *fill_copy(unsigned long copy_nr, + unsigned long msg_nr, + struct msg_msg *msg, + struct msg_msg *copy) +{ + if (copy_nr == msg_nr) + return copy_msg(msg, copy); + return NULL; +} + +static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz, + int msgflg, long *msgtyp, + unsigned long *copy_number) +{ + struct msg_msg *copy; + + *copy_number = *msgtyp; + *msgtyp = 0; + /* + * Create dummy message to copy real message to. + */ + copy = load_msg(buf, bufsz); + if (!IS_ERR(copy)) + copy->m_ts = bufsz; + return copy; +} + +static inline void free_copy(int msgflg, struct msg_msg *copy) +{ + if (msgflg & MSG_COPY) + free_msg(copy); +} +#else +#define free_copy(msgflg, copy) do {} while (0) +#define prepare_copy(buf, sz, msgflg, msgtyp, copy_nr) ERR_PTR(-ENOSYS) +#define fill_copy(copy_nr, msg_nr, msg, copy) NULL +#endif + long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg, long (*msg_handler)(void __user *, struct msg_msg *, size_t)) @@ -777,19 +816,29 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, struct msg_msg *msg; int mode; struct ipc_namespace *ns; + struct msg_msg *copy; + unsigned long __maybe_unused copy_number; if (msqid < 0 || (long) bufsz < 0) return -EINVAL; + if (msgflg & MSG_COPY) { + copy = prepare_copy(buf, bufsz, msgflg, &msgtyp, ©_number); + if (IS_ERR(copy)) + return PTR_ERR(copy); + } mode = convert_mode(&msgtyp, msgflg); ns = current->nsproxy->ipc_ns; msq = msg_lock_check(ns, msqid); - if (IS_ERR(msq)) + if (IS_ERR(msq)) { + free_copy(msgflg, copy); return PTR_ERR(msq); + } for (;;) { struct msg_receiver msr_d; struct list_head *tmp; + long msg_counter = 0; msg = ERR_PTR(-EACCES); if (ipcperms(ns, &msq->q_perm, S_IRUGO)) @@ -809,8 +858,15 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, if (mode == SEARCH_LESSEQUAL && walk_msg->m_type != 1) { msgtyp = walk_msg->m_type - 1; + } else if (msgflg & MSG_COPY) { + msg = fill_copy(copy_number, + msg_counter, + walk_msg, copy); + if (msg) + break; } else break; + msg_counter++; } tmp = tmp->next; } @@ -823,6 +879,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, msg = ERR_PTR(-E2BIG); goto out_unlock; } + if (msgflg & MSG_COPY) + goto out_unlock; list_del(&msg->m_list); msq->q_qnum--; msq->q_rtime = get_seconds(); @@ -906,8 +964,10 @@ out_unlock: break; } } - if (IS_ERR(msg)) + if (IS_ERR(msg)) { + free_copy(msgflg, copy); return PTR_ERR(msg); + } bufsz = msg_handler(buf, msg, bufsz); free_msg(msg); -- cgit From 85398aa8de1d68f44ff1b5d0ed9ceb2b0c51ce49 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 4 Jan 2013 15:34:58 -0800 Subject: ipc: simplify free_copy() call Passing and checking of msgflg to free_copy() is redundant. This patch sets copy to NULL on declaration instead and checks for non-NULL in free_copy(). Note: in case of copy allocation failure, error is returned immediately. So no need to check for IS_ERR() in free_copy(). Signed-off-by: Stanislav Kinsbursky Cc: "Eric W. Biederman" Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index d20ffc7d3f24..7a20536c3a50 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -797,15 +797,17 @@ static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz, return copy; } -static inline void free_copy(int msgflg, struct msg_msg *copy) +static inline void free_copy(struct msg_msg *copy) { - if (msgflg & MSG_COPY) + if (copy) free_msg(copy); } #else -#define free_copy(msgflg, copy) do {} while (0) #define prepare_copy(buf, sz, msgflg, msgtyp, copy_nr) ERR_PTR(-ENOSYS) #define fill_copy(copy_nr, msg_nr, msg, copy) NULL +static inline void free_copy(struct msg_msg *copy) +{ +} #endif long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, @@ -816,7 +818,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, struct msg_msg *msg; int mode; struct ipc_namespace *ns; - struct msg_msg *copy; + struct msg_msg *copy = NULL; unsigned long __maybe_unused copy_number; if (msqid < 0 || (long) bufsz < 0) @@ -831,7 +833,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, msq = msg_lock_check(ns, msqid); if (IS_ERR(msq)) { - free_copy(msgflg, copy); + free_copy(copy); return PTR_ERR(msq); } @@ -965,7 +967,7 @@ out_unlock: } } if (IS_ERR(msg)) { - free_copy(msgflg, copy); + free_copy(copy); return PTR_ERR(msg); } -- cgit From b30efe2775ee0a1d911514292579770b214d31c3 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 4 Jan 2013 15:35:00 -0800 Subject: ipc: convert prepare_copy() from macro to function This code works if CONFIG_CHECKPOINT_RESTORE is disabled. [akpm@linux-foundation.org: remove __maybe_unused] Signed-off-by: Stanislav Kinsbursky Cc: "Eric W. Biederman" Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index 7a20536c3a50..038a7d79eb0e 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -803,8 +803,15 @@ static inline void free_copy(struct msg_msg *copy) free_msg(copy); } #else -#define prepare_copy(buf, sz, msgflg, msgtyp, copy_nr) ERR_PTR(-ENOSYS) #define fill_copy(copy_nr, msg_nr, msg, copy) NULL + +static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz, + int msgflg, long *msgtyp, + unsigned long *copy_number) +{ + return ERR_PTR(-ENOSYS); +} + static inline void free_copy(struct msg_msg *copy) { } @@ -819,7 +826,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int mode; struct ipc_namespace *ns; struct msg_msg *copy = NULL; - unsigned long __maybe_unused copy_number; + unsigned long copy_number = 0; if (msqid < 0 || (long) bufsz < 0) return -EINVAL; -- cgit From 51eeacaa07d1372a7bc9612548ffe6cd846f4f2f Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 4 Jan 2013 15:35:01 -0800 Subject: ipc: simplify message copying Remove the redundant and confusing fill_copy(). Also add copy_msg() check for error. In this case exit from the function have to be done instead of break, because further code interprets any error as EAGAIN. Also define copy_msg() for the case when CONFIG_CHECKPOINT_RESTORE is disabled. Signed-off-by: Stanislav Kinsbursky Cc: "Eric W. Biederman" Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index 038a7d79eb0e..8493e1d7e353 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -770,16 +770,6 @@ static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) } #ifdef CONFIG_CHECKPOINT_RESTORE -static inline struct msg_msg *fill_copy(unsigned long copy_nr, - unsigned long msg_nr, - struct msg_msg *msg, - struct msg_msg *copy) -{ - if (copy_nr == msg_nr) - return copy_msg(msg, copy); - return NULL; -} - static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz, int msgflg, long *msgtyp, unsigned long *copy_number) @@ -803,8 +793,6 @@ static inline void free_copy(struct msg_msg *copy) free_msg(copy); } #else -#define fill_copy(copy_nr, msg_nr, msg, copy) NULL - static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz, int msgflg, long *msgtyp, unsigned long *copy_number) @@ -868,11 +856,16 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, walk_msg->m_type != 1) { msgtyp = walk_msg->m_type - 1; } else if (msgflg & MSG_COPY) { - msg = fill_copy(copy_number, - msg_counter, - walk_msg, copy); - if (msg) + if (copy_number == msg_counter) { + /* + * Found requested message. + * Copy it. + */ + msg = copy_msg(msg, copy); + if (IS_ERR(msg)) + goto out_unlock; break; + } } else break; msg_counter++; -- cgit From 3fcfe78658695b424314ddb76abc8d58b4fc98e6 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 4 Jan 2013 15:35:03 -0800 Subject: ipc: add more comments to message copying related code Signed-off-by: Stanislav Kinsbursky Cc: "Eric W. Biederman" Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index 8493e1d7e353..950572f9d796 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -770,6 +770,10 @@ static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) } #ifdef CONFIG_CHECKPOINT_RESTORE +/* + * This function creates new kernel message structure, large enough to store + * bufsz message bytes. + */ static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz, int msgflg, long *msgtyp, unsigned long *copy_number) @@ -881,6 +885,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, msg = ERR_PTR(-E2BIG); goto out_unlock; } + /* + * If we are copying, then do not unlink message and do + * not update queue parameters. + */ if (msgflg & MSG_COPY) goto out_unlock; list_del(&msg->m_list); -- cgit