2004-04-09 23:01:51

by Jakub Jelinek

[permalink] [raw]
Subject: [PATCH] Only fail with invalid timespec if mq_timed{send,receive} needs to block

Hi!

POSIX requires EINVAL to be set if:
"The process or thread would have blocked, and the abs_timeout parameter
specified a nanoseconds field value less than zero or greater than or equal
to 1000 million."
but 2.6.5-mm3 returns -EINVAL even if the process or thread would not block
(if the queue is not empty for timedreceive or not full for timedsend).

--- linux-2.6.5-mm3/mqueue.c.jj 2004-04-08 22:56:25.000000000 +0200
+++ linux-2.6.5-mm3/mqueue.c 2004-04-10 00:30:53.910430420 +0200
@@ -828,8 +828,7 @@ asmlinkage long sys_mq_timedsend(mqd_t m
if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
return -EINVAL;

- if (unlikely((timeout = prepare_timeout(u_abs_timeout)) < 0))
- return timeout;
+ timeout = prepare_timeout(u_abs_timeout);

ret = -EBADF;
filp = fget(mqdes);
@@ -865,6 +864,9 @@ asmlinkage long sys_mq_timedsend(mqd_t m
if (filp->f_flags & O_NONBLOCK) {
spin_unlock(&info->lock);
ret = -EAGAIN;
+ } else if (unlikely(timeout < 0)) {
+ spin_unlock(&info->lock);
+ ret = timeout;
} else {
wait.task = current;
wait.msg = (void *) msg_ptr;
@@ -905,9 +907,7 @@ asmlinkage ssize_t sys_mq_timedreceive(m
struct mqueue_inode_info *info;
struct ext_wait_queue wait;

-
- if (unlikely((timeout = prepare_timeout(u_abs_timeout)) < 0))
- return timeout;
+ timeout = prepare_timeout(u_abs_timeout);

ret = -EBADF;
filp = fget(mqdes);
@@ -934,6 +934,10 @@ asmlinkage ssize_t sys_mq_timedreceive(m
spin_unlock(&info->lock);
ret = -EAGAIN;
msg_ptr = NULL;
+ } else if (unlikely(timeout < 0)) {
+ spin_unlock(&info->lock);
+ ret = timeout;
+ msg_ptr = NULL;
} else {
wait.task = current;
wait.state = STATE_NONE;

Jakub