|
@@ -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
|