diff options
Diffstat (limited to 'ipc/msg.c')
-rw-r--r-- | ipc/msg.c | 64 |
1 files changed, 62 insertions, 2 deletions
@@ -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 | ||
773 | static 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 | |||
783 | static 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 | |||
800 | static 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 | |||
772 | long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, | 811 | long 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, ©_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); |