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