aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c123
1 files changed, 96 insertions, 27 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index a71af5a65abf..950572f9d796 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -755,26 +755,91 @@ static inline int convert_mode(long *msgtyp, int msgflg)
755 return SEARCH_EQUAL; 755 return SEARCH_EQUAL;
756} 756}
757 757
758long do_msgrcv(int msqid, long *pmtype, void __user *mtext, 758static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
759 size_t msgsz, long msgtyp, int msgflg) 759{
760 struct msgbuf __user *msgp = dest;
761 size_t msgsz;
762
763 if (put_user(msg->m_type, &msgp->mtype))
764 return -EFAULT;
765
766 msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
767 if (store_msg(msgp->mtext, msg, msgsz))
768 return -EFAULT;
769 return msgsz;
770}
771
772#ifdef CONFIG_CHECKPOINT_RESTORE
773/*
774 * This function creates new kernel message structure, large enough to store
775 * bufsz message bytes.
776 */
777static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz,
778 int msgflg, long *msgtyp,
779 unsigned long *copy_number)
780{
781 struct msg_msg *copy;
782
783 *copy_number = *msgtyp;
784 *msgtyp = 0;
785 /*
786 * Create dummy message to copy real message to.
787 */
788 copy = load_msg(buf, bufsz);
789 if (!IS_ERR(copy))
790 copy->m_ts = bufsz;
791 return copy;
792}
793
794static inline void free_copy(struct msg_msg *copy)
795{
796 if (copy)
797 free_msg(copy);
798}
799#else
800static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz,
801 int msgflg, long *msgtyp,
802 unsigned long *copy_number)
803{
804 return ERR_PTR(-ENOSYS);
805}
806
807static inline void free_copy(struct msg_msg *copy)
808{
809}
810#endif
811
812long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
813 int msgflg,
814 long (*msg_handler)(void __user *, struct msg_msg *, size_t))
760{ 815{
761 struct msg_queue *msq; 816 struct msg_queue *msq;
762 struct msg_msg *msg; 817 struct msg_msg *msg;
763 int mode; 818 int mode;
764 struct ipc_namespace *ns; 819 struct ipc_namespace *ns;
820 struct msg_msg *copy = NULL;
821 unsigned long copy_number = 0;
765 822
766 if (msqid < 0 || (long) msgsz < 0) 823 if (msqid < 0 || (long) bufsz < 0)
767 return -EINVAL; 824 return -EINVAL;
825 if (msgflg & MSG_COPY) {
826 copy = prepare_copy(buf, bufsz, msgflg, &msgtyp, &copy_number);
827 if (IS_ERR(copy))
828 return PTR_ERR(copy);
829 }
768 mode = convert_mode(&msgtyp, msgflg); 830 mode = convert_mode(&msgtyp, msgflg);
769 ns = current->nsproxy->ipc_ns; 831 ns = current->nsproxy->ipc_ns;
770 832
771 msq = msg_lock_check(ns, msqid); 833 msq = msg_lock_check(ns, msqid);
772 if (IS_ERR(msq)) 834 if (IS_ERR(msq)) {
835 free_copy(copy);
773 return PTR_ERR(msq); 836 return PTR_ERR(msq);
837 }
774 838
775 for (;;) { 839 for (;;) {
776 struct msg_receiver msr_d; 840 struct msg_receiver msr_d;
777 struct list_head *tmp; 841 struct list_head *tmp;
842 long msg_counter = 0;
778 843
779 msg = ERR_PTR(-EACCES); 844 msg = ERR_PTR(-EACCES);
780 if (ipcperms(ns, &msq->q_perm, S_IRUGO)) 845 if (ipcperms(ns, &msq->q_perm, S_IRUGO))
@@ -793,12 +858,21 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
793 msg = walk_msg; 858 msg = walk_msg;
794 if (mode == SEARCH_LESSEQUAL && 859 if (mode == SEARCH_LESSEQUAL &&
795 walk_msg->m_type != 1) { 860 walk_msg->m_type != 1) {
796 msg = walk_msg;
797 msgtyp = walk_msg->m_type - 1; 861 msgtyp = walk_msg->m_type - 1;
798 } else { 862 } else if (msgflg & MSG_COPY) {
799 msg = walk_msg; 863 if (copy_number == msg_counter) {
864 /*
865 * Found requested message.
866 * Copy it.
867 */
868 msg = copy_msg(msg, copy);
869 if (IS_ERR(msg))
870 goto out_unlock;
871 break;
872 }
873 } else
800 break; 874 break;
801 } 875 msg_counter++;
802 } 876 }
803 tmp = tmp->next; 877 tmp = tmp->next;
804 } 878 }
@@ -807,10 +881,16 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
807 * Found a suitable message. 881 * Found a suitable message.
808 * Unlink it from the queue. 882 * Unlink it from the queue.
809 */ 883 */
810 if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { 884 if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
811 msg = ERR_PTR(-E2BIG); 885 msg = ERR_PTR(-E2BIG);
812 goto out_unlock; 886 goto out_unlock;
813 } 887 }
888 /*
889 * If we are copying, then do not unlink message and do
890 * not update queue parameters.
891 */
892 if (msgflg & MSG_COPY)
893 goto out_unlock;
814 list_del(&msg->m_list); 894 list_del(&msg->m_list);
815 msq->q_qnum--; 895 msq->q_qnum--;
816 msq->q_rtime = get_seconds(); 896 msq->q_rtime = get_seconds();
@@ -834,7 +914,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
834 if (msgflg & MSG_NOERROR) 914 if (msgflg & MSG_NOERROR)
835 msr_d.r_maxsize = INT_MAX; 915 msr_d.r_maxsize = INT_MAX;
836 else 916 else
837 msr_d.r_maxsize = msgsz; 917 msr_d.r_maxsize = bufsz;
838 msr_d.r_msg = ERR_PTR(-EAGAIN); 918 msr_d.r_msg = ERR_PTR(-EAGAIN);
839 current->state = TASK_INTERRUPTIBLE; 919 current->state = TASK_INTERRUPTIBLE;
840 msg_unlock(msq); 920 msg_unlock(msq);
@@ -894,32 +974,21 @@ out_unlock:
894 break; 974 break;
895 } 975 }
896 } 976 }
897 if (IS_ERR(msg)) 977 if (IS_ERR(msg)) {
978 free_copy(copy);
898 return PTR_ERR(msg); 979 return PTR_ERR(msg);
980 }
899 981
900 msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; 982 bufsz = msg_handler(buf, msg, bufsz);
901 *pmtype = msg->m_type;
902 if (store_msg(mtext, msg, msgsz))
903 msgsz = -EFAULT;
904
905 free_msg(msg); 983 free_msg(msg);
906 984
907 return msgsz; 985 return bufsz;
908} 986}
909 987
910SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, 988SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
911 long, msgtyp, int, msgflg) 989 long, msgtyp, int, msgflg)
912{ 990{
913 long err, mtype; 991 return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
914
915 err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
916 if (err < 0)
917 goto out;
918
919 if (put_user(mtype, &msgp->mtype))
920 err = -EFAULT;
921out:
922 return err;
923} 992}
924 993
925#ifdef CONFIG_PROC_FS 994#ifdef CONFIG_PROC_FS