Messages in this thread Patch in this message | | | Date | Fri, 02 Mar 2012 16:42:35 +0900 | From | Akira Takeuchi <> | Subject | [REGRESSION][PATCH] mqueue: Ignore the validity of abs_timeout parameter when message can be performed immediately |
| |
This patch fixes up the regression problem of mq_timed{send,receive} syscall.
When a message of mqueue can be performed immediately, the validity of abs_timeout parameter should not be checked.
According to the manpage of mq_timedreceive: Under no circumstance shall the operation fail with a timeout if a message can be removed from the message queue immediately. The validity of the abstime parameter need not be checked if a message can be removed from the message queue immediately.
On 2.6.35+ kernel, mq_timed{send,receive} returns EINVAL incorrectly, in this situation.
I found this problem during the OPTS testcase "conformance/interfaces/mq_timedreceive/10-2":
# ./10-2.test FAIL: the validity of abs_timeout is checked Test FAILED
Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> --- ipc/mqueue.c | 31 +++++++++++++++++++++++++++---- 1 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 86ee272..7cd4411 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -861,14 +861,22 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, struct msg_msg *msg_ptr; struct mqueue_inode_info *info; ktime_t expires, *timeout = NULL; + int timeout_param_error = 0; struct timespec ts; int ret; if (u_abs_timeout) { int res = prepare_timeout(u_abs_timeout, &expires, &ts); if (res) - return res; - timeout = &expires; + /* + * The validity of the abs_timeout parameter need not be + * checked when there is sufficient room in the queue. + * So, do not return here, even if the parameter is + * invalid. + */ + timeout_param_error = res; + else + timeout = &expires; } if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX)) @@ -916,6 +924,9 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, if (filp->f_flags & O_NONBLOCK) { spin_unlock(&info->lock); ret = -EAGAIN; + } else if (unlikely(timeout_param_error)) { + spin_unlock(&info->lock); + ret = timeout_param_error; } else { wait.task = current; wait.msg = (void *) msg_ptr; @@ -955,13 +966,21 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, struct mqueue_inode_info *info; struct ext_wait_queue wait; ktime_t expires, *timeout = NULL; + int timeout_param_error = 0; struct timespec ts; if (u_abs_timeout) { int res = prepare_timeout(u_abs_timeout, &expires, &ts); if (res) - return res; - timeout = &expires; + /* + * The validity of the abs_timeout parameter need not be + * checked if a message can be removed from the message + * queue immediately. So, do not return here, even if + * the parameter is invalid. + */ + timeout_param_error = res; + else + timeout = &expires; } audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL); @@ -996,6 +1015,10 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, if (filp->f_flags & O_NONBLOCK) { spin_unlock(&info->lock); ret = -EAGAIN; + } else if (unlikely(timeout_param_error)) { + spin_unlock(&info->lock); + ret = timeout_param_error; + msg_ptr = NULL; /* just for shutting up warning */ } else { wait.task = current; wait.state = STATE_NONE; -- 1.7.4.1
| |