Commit ad7e3eda authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by Linus Torvalds

irda update 3/7:

        o [FEATURE] Replace interruptible_sleep_on() with wait_event().
                Most races were taken care off, but cleaner anyway
parent d8fd01e8
...@@ -568,15 +568,17 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name) ...@@ -568,15 +568,17 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name)
if(self->iriap == NULL) if(self->iriap == NULL)
return -ENOMEM; return -ENOMEM;
/* Treat unexpected signals as disconnect */ /* Treat unexpected wakeup as disconnect */
self->errno = -EHOSTUNREACH; self->errno = -EHOSTUNREACH;
/* Query remote LM-IAS */ /* Query remote LM-IAS */
iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr, iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
name, "IrDA:TinyTP:LsapSel"); name, "IrDA:TinyTP:LsapSel");
/* Wait for answer (if not already failed) */
if(self->iriap != NULL) /* Wait for answer, if not yet finished (or failed) */
interruptible_sleep_on(&self->query_wait); if (wait_event_interruptible(self->query_wait, (self->iriap==NULL)))
/* Treat signals as disconnect */
return -EHOSTUNREACH;
/* Check what happened */ /* Check what happened */
if (self->errno) if (self->errno)
...@@ -877,16 +879,47 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -877,16 +879,47 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
* The read queue this time is holding sockets ready to use * The read queue this time is holding sockets ready to use
* hooked into the SABM we saved * hooked into the SABM we saved
*/ */
do {
if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
if (flags & O_NONBLOCK)
return -EWOULDBLOCK;
interruptible_sleep_on(sk->sleep); /*
if (signal_pending(current)) * We can perform the accept only if there is incomming data
return -ERESTARTSYS; * on the listening socket.
* So, we will block the caller until we receive any data.
* If the caller was waiting on select() or poll() before
* calling us, the data is waiting for us ;-)
* Jean II
*/
skb = skb_dequeue(&sk->receive_queue);
if (skb == NULL) {
int ret = 0;
DECLARE_WAITQUEUE(waitq, current);
/* Non blocking operation */
if (flags & O_NONBLOCK)
return -EWOULDBLOCK;
/* The following code is a cut'n'paste of the
* wait_event_interruptible() macro.
* We don't us the macro because the condition has
* side effects : we want to make sure that only one
* skb get dequeued - Jean II */
add_wait_queue(sk->sleep, &waitq);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
skb = skb_dequeue(&sk->receive_queue);
if (skb != NULL)
break;
if (!signal_pending(current)) {
schedule();
continue;
}
ret = -ERESTARTSYS;
break;
} }
} while (skb == NULL); current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &waitq);
if(ret)
return -ERESTARTSYS;
}
newsk = newsock->sk; newsk = newsock->sk;
newsk->state = TCP_ESTABLISHED; newsk->state = TCP_ESTABLISHED;
...@@ -1024,19 +1057,9 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -1024,19 +1057,9 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS; return -EINPROGRESS;
/* Here, there is a race condition : the state may change between if (wait_event_interruptible(*(sk->sleep), (sk->state!=TCP_SYN_SENT)))
* our test and the sleep, via irda_connect_confirm(). return -ERESTARTSYS;
* The way to workaround that is to sleep with a timeout, so that
* we don't sleep forever and check the state when waking up.
* 50ms is plenty good enough, because the LAP is already connected.
* Jean II */
while (sk->state == TCP_SYN_SENT) {
interruptible_sleep_on_timeout(sk->sleep, HZ/20);
if (signal_pending(current)) {
return -ERESTARTSYS;
}
}
if (sk->state != TCP_ESTABLISHED) { if (sk->state != TCP_ESTABLISHED) {
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */ return sock_error(sk); /* Always set at this point */
...@@ -1280,17 +1303,14 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len, ...@@ -1280,17 +1303,14 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
ASSERT(self != NULL, return -1;); ASSERT(self != NULL, return -1;);
/* Check if IrTTP is wants us to slow down */ /* Check if IrTTP is wants us to slow down */
while (self->tx_flow == FLOW_STOP) {
IRDA_DEBUG(2, __FUNCTION__ "(), IrTTP is busy, going to sleep!\n"); if (wait_event_interruptible(*(sk->sleep),
interruptible_sleep_on(sk->sleep); (self->tx_flow != FLOW_STOP || sk->state != TCP_ESTABLISHED)))
return -ERESTARTSYS;
/* Check if we are still connected */
if (sk->state != TCP_ESTABLISHED) /* Check if we are still connected */
return -ENOTCONN; if (sk->state != TCP_ESTABLISHED)
/* Handle signals */ return -ENOTCONN;
if (signal_pending(current))
return -ERESTARTSYS;
}
/* Check that we don't send out to big frames */ /* Check that we don't send out to big frames */
if (len > self->max_data_size) { if (len > self->max_data_size) {
...@@ -1382,14 +1402,23 @@ static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg, ...@@ -1382,14 +1402,23 @@ static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg,
* *
* Sleep until data has arrive. But check for races.. * Sleep until data has arrive. But check for races..
* *
* The caller is expected to deal with the situation when we return
* due to pending signals. And even if not, the peeked skb might have
* been already dequeued due to concurrent operation.
* Currently irda_recvmsg_stream() is the only caller and is ok.
* Return 0 if condition packet has arrived, -ERESTARTSYS if signal_pending()
* Only used once in irda_recvmsg_stream() -> inline
*/ */
static void irda_data_wait(struct sock *sk) static inline int irda_data_wait(struct sock *sk)
{ {
int ret = 0;
if (!skb_peek(&sk->receive_queue)) { if (!skb_peek(&sk->receive_queue)) {
set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
interruptible_sleep_on(sk->sleep); __wait_event_interruptible(*(sk->sleep),
(skb_peek(&sk->receive_queue)!=NULL), ret);
clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
} }
return(ret);
} }
/* /*
...@@ -1444,8 +1473,8 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg, ...@@ -1444,8 +1473,8 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
if (noblock) if (noblock)
return -EAGAIN; return -EAGAIN;
irda_data_wait(sk); /* Wait process until data arrives */
if (signal_pending(current)) if (irda_data_wait(sk))
return -ERESTARTSYS; return -ERESTARTSYS;
continue; continue;
} }
...@@ -2281,7 +2310,12 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, ...@@ -2281,7 +2310,12 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
irda_getvalue_confirm); irda_getvalue_confirm);
/* Treat unexpected signals as disconnect */ if (self->iriap == NULL) {
kfree(ias_opt);
return -ENOMEM;
}
/* Treat unexpected wakeup as disconnect */
self->errno = -EHOSTUNREACH; self->errno = -EHOSTUNREACH;
/* Query remote LM-IAS */ /* Query remote LM-IAS */
...@@ -2289,9 +2323,17 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, ...@@ -2289,9 +2323,17 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
self->saddr, daddr, self->saddr, daddr,
ias_opt->irda_class_name, ias_opt->irda_class_name,
ias_opt->irda_attrib_name); ias_opt->irda_attrib_name);
/* Wait for answer (if not already failed) */
if(self->iriap != NULL) /* Wait for answer, if not yet finished (or failed) */
interruptible_sleep_on(&self->query_wait); if (wait_event_interruptible(self->query_wait,
(self->iriap == NULL))) {
/* pending request uses copy of ias_opt-content
* we can free it regardless! */
kfree(ias_opt);
/* Treat signals as disconnect */
return -EHOSTUNREACH;
}
/* Check what happened */ /* Check what happened */
if (self->errno) if (self->errno)
{ {
...@@ -2348,12 +2390,14 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, ...@@ -2348,12 +2390,14 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
irlmp_update_client(self->ckey, self->mask, irlmp_update_client(self->ckey, self->mask,
irda_selective_discovery_indication, irda_selective_discovery_indication,
NULL, (void *) self); NULL, (void *) self);
/* Do some discovery (and also return cached results) */ /* Do some discovery (and also return cached results) */
irlmp_discovery_request(self->nslots); irlmp_discovery_request(self->nslots);
/* Wait until a node is discovered */ /* Wait until a node is discovered */
if (!self->cachediscovery) { if (!self->cachediscovery) {
int ret = 0;
IRDA_DEBUG(1, __FUNCTION__ IRDA_DEBUG(1, __FUNCTION__
"(), nothing discovered yet, going to sleep...\n"); "(), nothing discovered yet, going to sleep...\n");
...@@ -2362,9 +2406,12 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, ...@@ -2362,9 +2406,12 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
self->watchdog.data = (unsigned long) self; self->watchdog.data = (unsigned long) self;
self->watchdog.expires = jiffies + (val * HZ/1000); self->watchdog.expires = jiffies + (val * HZ/1000);
add_timer(&(self->watchdog)); add_timer(&(self->watchdog));
self->errno = 0;
/* Wait for IR-LMP to call us back */ /* Wait for IR-LMP to call us back */
interruptible_sleep_on(&self->query_wait); __wait_event_interruptible(self->query_wait,
(self->cachediscovery!=NULL || self->errno==-ETIME),
ret);
/* If watchdog is still activated, kill it! */ /* If watchdog is still activated, kill it! */
if(timer_pending(&(self->watchdog))) if(timer_pending(&(self->watchdog)))
...@@ -2372,6 +2419,9 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, ...@@ -2372,6 +2419,9 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
IRDA_DEBUG(1, __FUNCTION__ IRDA_DEBUG(1, __FUNCTION__
"(), ...waking up !\n"); "(), ...waking up !\n");
if (ret != 0)
return ret;
} }
else else
IRDA_DEBUG(1, __FUNCTION__ IRDA_DEBUG(1, __FUNCTION__
......
...@@ -453,8 +453,21 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -453,8 +453,21 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
*/ */
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
(self->flags & ASYNC_CLOSING)) { (self->flags & ASYNC_CLOSING)) {
if (self->flags & ASYNC_CLOSING)
interruptible_sleep_on(&self->close_wait); /* Hm, why are we blocking on ASYNC_CLOSING if we
* do return -EAGAIN/-ERESTARTSYS below anyway?
* IMHO it's either not needed in the first place
* or for some reason we need to make sure the async
* closing has been finished - if so, wouldn't we
* probably better sleep uninterruptible?
*/
if (wait_event_interruptible(self->close_wait, !(self->flags&ASYNC_CLOSING))) {
WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
__FUNCTION__);
return -ERESTARTSYS;
}
/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
#ifdef SERIAL_DO_RESTART #ifdef SERIAL_DO_RESTART
return ((self->flags & ASYNC_HUP_NOTIFY) ? return ((self->flags & ASYNC_HUP_NOTIFY) ?
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment