aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c64
1 files changed, 62 insertions, 2 deletions
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)
769 return msgsz; 769 return msgsz;
770} 770}
771 771
772#ifdef CONFIG_CHECKPOINT_RESTORE
773static inline struct msg_msg *fill_copy(unsigned long copy_nr,
774 unsigned long msg_nr,
775 struct msg_msg *msg,
776 struct msg_msg *copy)
777{
778 if (copy_nr == msg_nr)
779 return copy_msg(msg, copy);
780 return NULL;
781}
782
783static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz,
784 int msgflg, long *msgtyp,
785 unsigned long *copy_number)
786{
787 struct msg_msg *copy;
788
789 *copy_number = *msgtyp;
790 *msgtyp = 0;
791 /*
792 * Create dummy message to copy real message to.
793 */
794 copy = load_msg(buf, bufsz);
795 if (!IS_ERR(copy))
796 copy->m_ts = bufsz;
797 return copy;
798}
799
800static inline void free_copy(int msgflg, struct msg_msg *copy)
801{
802 if (msgflg & MSG_COPY)
803 free_msg(copy);
804}
805#else
806#define free_copy(msgflg, copy) do {} while (0)
807#define prepare_copy(buf, sz, msgflg, msgtyp, copy_nr) ERR_PTR(-ENOSYS)
808#define fill_copy(copy_nr, msg_nr, msg, copy) NULL
809#endif
810
772long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, 811long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
773 int msgflg, 812 int msgflg,
774 long (*msg_handler)(void __user *, struct msg_msg *, size_t)) 813 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,
777 struct msg_msg *msg; 816 struct msg_msg *msg;
778 int mode; 817 int mode;
779 struct ipc_namespace *ns; 818 struct ipc_namespace *ns;
819 struct msg_msg *copy;
820 unsigned long __maybe_unused copy_number;
780 821
781 if (msqid < 0 || (long) bufsz < 0) 822 if (msqid < 0 || (long) bufsz < 0)
782 return -EINVAL; 823 return -EINVAL;
824 if (msgflg & MSG_COPY) {
825 copy = prepare_copy(buf, bufsz, msgflg, &msgtyp, &copy_number);
826 if (IS_ERR(copy))
827 return PTR_ERR(copy);
828 }
783 mode = convert_mode(&msgtyp, msgflg); 829 mode = convert_mode(&msgtyp, msgflg);
784 ns = current->nsproxy->ipc_ns; 830 ns = current->nsproxy->ipc_ns;
785 831
786 msq = msg_lock_check(ns, msqid); 832 msq = msg_lock_check(ns, msqid);
787 if (IS_ERR(msq)) 833 if (IS_ERR(msq)) {
834 free_copy(msgflg, copy);
788 return PTR_ERR(msq); 835 return PTR_ERR(msq);
836 }
789 837
790 for (;;) { 838 for (;;) {
791 struct msg_receiver msr_d; 839 struct msg_receiver msr_d;
792 struct list_head *tmp; 840 struct list_head *tmp;
841 long msg_counter = 0;
793 842
794 msg = ERR_PTR(-EACCES); 843 msg = ERR_PTR(-EACCES);
795 if (ipcperms(ns, &msq->q_perm, S_IRUGO)) 844 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,
809 if (mode == SEARCH_LESSEQUAL && 858 if (mode == SEARCH_LESSEQUAL &&
810 walk_msg->m_type != 1) { 859 walk_msg->m_type != 1) {
811 msgtyp = walk_msg->m_type - 1; 860 msgtyp = walk_msg->m_type - 1;
861 } else if (msgflg & MSG_COPY) {
862 msg = fill_copy(copy_number,
863 msg_counter,
864 walk_msg, copy);
865 if (msg)
866 break;
812 } else 867 } else
813 break; 868 break;
869 msg_counter++;
814 } 870 }
815 tmp = tmp->next; 871 tmp = tmp->next;
816 } 872 }
@@ -823,6 +879,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
823 msg = ERR_PTR(-E2BIG); 879 msg = ERR_PTR(-E2BIG);
824 goto out_unlock; 880 goto out_unlock;
825 } 881 }
882 if (msgflg & MSG_COPY)
883 goto out_unlock;
826 list_del(&msg->m_list); 884 list_del(&msg->m_list);
827 msq->q_qnum--; 885 msq->q_qnum--;
828 msq->q_rtime = get_seconds(); 886 msq->q_rtime = get_seconds();
@@ -906,8 +964,10 @@ out_unlock:
906 break; 964 break;
907 } 965 }
908 } 966 }
909 if (IS_ERR(msg)) 967 if (IS_ERR(msg)) {
968 free_copy(msgflg, copy);
910 return PTR_ERR(msg); 969 return PTR_ERR(msg);
970 }
911 971
912 bufsz = msg_handler(buf, msg, bufsz); 972 bufsz = msg_handler(buf, msg, bufsz);
913 free_msg(msg); 973 free_msg(msg);