aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/mqueue.c74
1 files changed, 25 insertions, 49 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index e4e3f04803ca..a9d8b0ced4e9 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -428,7 +428,7 @@ static void wq_add(struct mqueue_inode_info *info, int sr,
428 * sr: SEND or RECV 428 * sr: SEND or RECV
429 */ 429 */
430static int wq_sleep(struct mqueue_inode_info *info, int sr, 430static int wq_sleep(struct mqueue_inode_info *info, int sr,
431 long timeout, struct ext_wait_queue *ewp) 431 ktime_t *timeout, struct ext_wait_queue *ewp)
432{ 432{
433 int retval; 433 int retval;
434 signed long time; 434 signed long time;
@@ -439,7 +439,8 @@ static int wq_sleep(struct mqueue_inode_info *info, int sr,
439 set_current_state(TASK_INTERRUPTIBLE); 439 set_current_state(TASK_INTERRUPTIBLE);
440 440
441 spin_unlock(&info->lock); 441 spin_unlock(&info->lock);
442 time = schedule_timeout(timeout); 442 time = schedule_hrtimeout_range_clock(timeout,
443 HRTIMER_MODE_ABS, 0, CLOCK_REALTIME);
443 444
444 while (ewp->state == STATE_PENDING) 445 while (ewp->state == STATE_PENDING)
445 cpu_relax(); 446 cpu_relax();
@@ -551,31 +552,16 @@ static void __do_notify(struct mqueue_inode_info *info)
551 wake_up(&info->wait_q); 552 wake_up(&info->wait_q);
552} 553}
553 554
554static long prepare_timeout(struct timespec *p) 555static int prepare_timeout(const struct timespec __user *u_abs_timeout,
556 ktime_t *expires, struct timespec *ts)
555{ 557{
556 struct timespec nowts; 558 if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec)))
557 long timeout; 559 return -EFAULT;
558 560 if (!timespec_valid(ts))
559 if (p) { 561 return -EINVAL;
560 if (unlikely(p->tv_nsec < 0 || p->tv_sec < 0
561 || p->tv_nsec >= NSEC_PER_SEC))
562 return -EINVAL;
563 nowts = CURRENT_TIME;
564 /* first subtract as jiffies can't be too big */
565 p->tv_sec -= nowts.tv_sec;
566 if (p->tv_nsec < nowts.tv_nsec) {
567 p->tv_nsec += NSEC_PER_SEC;
568 p->tv_sec--;
569 }
570 p->tv_nsec -= nowts.tv_nsec;
571 if (p->tv_sec < 0)
572 return 0;
573
574 timeout = timespec_to_jiffies(p) + 1;
575 } else
576 return MAX_SCHEDULE_TIMEOUT;
577 562
578 return timeout; 563 *expires = timespec_to_ktime(*ts);
564 return 0;
579} 565}
580 566
581static void remove_notification(struct mqueue_inode_info *info) 567static void remove_notification(struct mqueue_inode_info *info)
@@ -861,22 +847,21 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
861 struct ext_wait_queue *receiver; 847 struct ext_wait_queue *receiver;
862 struct msg_msg *msg_ptr; 848 struct msg_msg *msg_ptr;
863 struct mqueue_inode_info *info; 849 struct mqueue_inode_info *info;
864 struct timespec ts, *p = NULL; 850 ktime_t expires, *timeout = NULL;
865 long timeout; 851 struct timespec ts;
866 int ret; 852 int ret;
867 853
868 if (u_abs_timeout) { 854 if (u_abs_timeout) {
869 if (copy_from_user(&ts, u_abs_timeout, 855 int res = prepare_timeout(u_abs_timeout, &expires, &ts);
870 sizeof(struct timespec))) 856 if (res)
871 return -EFAULT; 857 return res;
872 p = &ts; 858 timeout = &expires;
873 } 859 }
874 860
875 if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX)) 861 if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
876 return -EINVAL; 862 return -EINVAL;
877 863
878 audit_mq_sendrecv(mqdes, msg_len, msg_prio, p); 864 audit_mq_sendrecv(mqdes, msg_len, msg_prio, timeout ? &ts : NULL);
879 timeout = prepare_timeout(p);
880 865
881 filp = fget(mqdes); 866 filp = fget(mqdes);
882 if (unlikely(!filp)) { 867 if (unlikely(!filp)) {
@@ -918,9 +903,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
918 if (filp->f_flags & O_NONBLOCK) { 903 if (filp->f_flags & O_NONBLOCK) {
919 spin_unlock(&info->lock); 904 spin_unlock(&info->lock);
920 ret = -EAGAIN; 905 ret = -EAGAIN;
921 } else if (unlikely(timeout < 0)) {
922 spin_unlock(&info->lock);
923 ret = timeout;
924 } else { 906 } else {
925 wait.task = current; 907 wait.task = current;
926 wait.msg = (void *) msg_ptr; 908 wait.msg = (void *) msg_ptr;
@@ -953,24 +935,23 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
953 size_t, msg_len, unsigned int __user *, u_msg_prio, 935 size_t, msg_len, unsigned int __user *, u_msg_prio,
954 const struct timespec __user *, u_abs_timeout) 936 const struct timespec __user *, u_abs_timeout)
955{ 937{
956 long timeout;
957 ssize_t ret; 938 ssize_t ret;
958 struct msg_msg *msg_ptr; 939 struct msg_msg *msg_ptr;
959 struct file *filp; 940 struct file *filp;
960 struct inode *inode; 941 struct inode *inode;
961 struct mqueue_inode_info *info; 942 struct mqueue_inode_info *info;
962 struct ext_wait_queue wait; 943 struct ext_wait_queue wait;
963 struct timespec ts, *p = NULL; 944 ktime_t expires, *timeout = NULL;
945 struct timespec ts;
964 946
965 if (u_abs_timeout) { 947 if (u_abs_timeout) {
966 if (copy_from_user(&ts, u_abs_timeout, 948 int res = prepare_timeout(u_abs_timeout, &expires, &ts);
967 sizeof(struct timespec))) 949 if (res)
968 return -EFAULT; 950 return res;
969 p = &ts; 951 timeout = &expires;
970 } 952 }
971 953
972 audit_mq_sendrecv(mqdes, msg_len, 0, p); 954 audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL);
973 timeout = prepare_timeout(p);
974 955
975 filp = fget(mqdes); 956 filp = fget(mqdes);
976 if (unlikely(!filp)) { 957 if (unlikely(!filp)) {
@@ -1002,11 +983,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
1002 if (filp->f_flags & O_NONBLOCK) { 983 if (filp->f_flags & O_NONBLOCK) {
1003 spin_unlock(&info->lock); 984 spin_unlock(&info->lock);
1004 ret = -EAGAIN; 985 ret = -EAGAIN;
1005 msg_ptr = NULL;
1006 } else if (unlikely(timeout < 0)) {
1007 spin_unlock(&info->lock);
1008 ret = timeout;
1009 msg_ptr = NULL;
1010 } else { 986 } else {
1011 wait.task = current; 987 wait.task = current;
1012 wait.state = STATE_NONE; 988 wait.state = STATE_NONE;