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