diff options
Diffstat (limited to 'ipc')
-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 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 | */ |
430 | static int wq_sleep(struct mqueue_inode_info *info, int sr, | 430 | static 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 | ||
554 | static long prepare_timeout(struct timespec *p) | 555 | static 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 | ||
581 | static void remove_notification(struct mqueue_inode_info *info) | 567 | static 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; |