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))
        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))
                                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;
                }
                                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();
                        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);
 
        free_msg(msg);
        return ERR_PTR(err);
 }
+#ifdef CONFIG_CHECKPOINT_RESTORE
+struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
+{
+       struct msg_msgseg *dst_pseg, *src_pseg;
+       int len = src->m_ts;
+       int alen;
+
+       BUG_ON(dst == NULL);
+       if (src->m_ts > dst->m_ts)
+               return ERR_PTR(-EINVAL);
+
+       alen = len;
+       if (alen > DATALEN_MSG)
+               alen = DATALEN_MSG;
+
+       dst->next = NULL;
+       dst->security = NULL;
 
+       memcpy(dst + 1, src + 1, alen);
+
+       len -= alen;
+       dst_pseg = dst->next;
+       src_pseg = src->next;
+       while (len > 0) {
+               alen = len;
+               if (alen > DATALEN_SEG)
+                       alen = DATALEN_SEG;
+               memcpy(dst_pseg + 1, src_pseg + 1, alen);
+               dst_pseg = dst_pseg->next;
+               len -= alen;
+               src_pseg = src_pseg->next;
+       }
+
+       dst->m_type = src->m_type;
+       dst->m_ts = src->m_ts;
+
+       return dst;
+}
+#endif
 int store_msg(void __user *dest, struct msg_msg *msg, int len)
 {
        int alen;