Commit 26d0a7ee authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by Linus Torvalds

IrDA update 1/2: cache-wait-data fixes

        o [CRITICA] Fix one instance were we forgot to clear LSAP cache
        o [CORRECT] Fix a bogus conversion to wait_event()
                The socket closure would never propagate to the app
parent 362dff46
...@@ -140,8 +140,10 @@ static void irda_disconnect_indication(void *instance, void *sap, ...@@ -140,8 +140,10 @@ static void irda_disconnect_indication(void *instance, void *sap,
dev_kfree_skb(skb); dev_kfree_skb(skb);
sk = self->sk; sk = self->sk;
if (sk == NULL) if (sk == NULL) {
IRDA_DEBUG(0, __FUNCTION__ "(%p) : BUG : sk is NULL\n", self);
return; return;
}
/* Prevent race conditions with irda_release() and irda_shutdown() */ /* Prevent race conditions with irda_release() and irda_shutdown() */
if ((!sk->dead) && (sk->state != TCP_CLOSE)) { if ((!sk->dead) && (sk->state != TCP_CLOSE)) {
...@@ -1317,12 +1319,12 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len, ...@@ -1317,12 +1319,12 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
len = self->max_data_size; len = self->max_data_size;
} }
skb = sock_alloc_send_skb(sk, len + self->max_header_size, skb = sock_alloc_send_skb(sk, len + self->max_header_size + 16,
msg->msg_flags & MSG_DONTWAIT, &err); msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb) if (!skb)
return -ENOBUFS; return -ENOBUFS;
skb_reserve(skb, self->max_header_size); skb_reserve(skb, self->max_header_size + 16);
asmptr = skb->h.raw = skb_put(skb, len); asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len); memcpy_fromiovec(asmptr, msg->msg_iov, len);
...@@ -1394,30 +1396,6 @@ static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg, ...@@ -1394,30 +1396,6 @@ static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg,
return copied; return copied;
} }
/*
* Function irda_data_wait (sk)
*
* 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 inline int irda_data_wait(struct sock *sk)
{
int ret = 0;
if (!skb_peek(&sk->receive_queue)) {
set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
__wait_event_interruptible(*(sk->sleep),
(skb_peek(&sk->receive_queue)!=NULL), ret);
clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
}
return(ret);
}
/* /*
* Function irda_recvmsg_stream (sock, msg, size, flags, scm) * Function irda_recvmsg_stream (sock, msg, size, flags, scm)
*/ */
...@@ -1429,6 +1407,7 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg, ...@@ -1429,6 +1407,7 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
int noblock = flags & MSG_DONTWAIT; int noblock = flags & MSG_DONTWAIT;
int copied = 0; int copied = 0;
int target = 1; int target = 1;
DECLARE_WAITQUEUE(waitq, current);
IRDA_DEBUG(3, __FUNCTION__ "()\n"); IRDA_DEBUG(3, __FUNCTION__ "()\n");
...@@ -1451,25 +1430,43 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg, ...@@ -1451,25 +1430,43 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
skb=skb_dequeue(&sk->receive_queue); skb=skb_dequeue(&sk->receive_queue);
if (skb==NULL) { if (skb==NULL) {
int ret = 0;
if (copied >= target) if (copied >= target)
break; break;
/* The following code is a cut'n'paste of the
* wait_event_interruptible() macro.
* We don't us the macro because the test condition
* is messy. - Jean II */
set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
add_wait_queue(sk->sleep, &waitq);
set_current_state(TASK_INTERRUPTIBLE);
/* /*
* POSIX 1003.1g mandates this order. * POSIX 1003.1g mandates this order.
*/ */
if (sk->err)
ret = sock_error(sk);
else if (sk->shutdown & RCV_SHUTDOWN)
;
else if (noblock)
ret = -EAGAIN;
else if (signal_pending(current))
ret = -ERESTARTSYS;
else if (skb_peek(&sk->receive_queue) == NULL)
/* Wait process until data arrives */
schedule();
if (sk->err) { current->state = TASK_RUNNING;
return sock_error(sk); remove_wait_queue(sk->sleep, &waitq);
} clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
if(ret)
return(ret);
if (sk->shutdown & RCV_SHUTDOWN) if (sk->shutdown & RCV_SHUTDOWN)
break; break;
if (noblock)
return -EAGAIN;
/* Wait process until data arrives */
if (irda_data_wait(sk))
return -ERESTARTSYS;
continue; continue;
} }
...@@ -2383,11 +2380,11 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, ...@@ -2383,11 +2380,11 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
"(), nothing discovered yet, going to sleep...\n"); "(), nothing discovered yet, going to sleep...\n");
/* Set watchdog timer to expire in <val> ms. */ /* Set watchdog timer to expire in <val> ms. */
self->errno = 0;
self->watchdog.function = irda_discovery_timeout; self->watchdog.function = irda_discovery_timeout;
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 */
__wait_event_interruptible(self->query_wait, __wait_event_interruptible(self->query_wait,
......
...@@ -648,6 +648,9 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) ...@@ -648,6 +648,9 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
ASSERT(self->lap->lsaps != NULL, return -1;); ASSERT(self->lap->lsaps != NULL, return -1;);
lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL); lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
self->lap->cache.valid = FALSE;
#endif
ASSERT(lsap != NULL, return -1;); ASSERT(lsap != NULL, return -1;);
ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
......
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