[LLC] llc_ui_wait_for_data and socket locking fixes

. now llc_ui_accept uses llc_ui_wait_for_data (llc_ui_recvmsg probably
  will use it too, we'll see)
. all the llc_ui_wait_for_ now receive the timeout in jiffies, not
  in seconds
. use sk_rcvtimeo()
. release_sock before going to sleep in the llc_ui_wait_for functions
. llc_ui_release has to get the socket lock
parent 45bbe785
...@@ -54,8 +54,9 @@ static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED; ...@@ -54,8 +54,9 @@ static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED;
static int llc_ui_indicate(struct llc_prim_if_block *prim); static int llc_ui_indicate(struct llc_prim_if_block *prim);
static int llc_ui_confirm(struct llc_prim_if_block *prim); static int llc_ui_confirm(struct llc_prim_if_block *prim);
static int llc_ui_wait_for_conn(struct sock *sk, int seconds); static int llc_ui_wait_for_conn(struct sock *sk, int timeout);
static int llc_ui_wait_for_disc(struct sock *sk, int seconds); static int llc_ui_wait_for_disc(struct sock *sk, int timeout);
static int llc_ui_wait_for_data(struct sock *sk, int timeout);
/** /**
* llc_ui_next_link_no - return the next unused link number for a sap * llc_ui_next_link_no - return the next unused link number for a sap
...@@ -512,10 +513,14 @@ static int llc_ui_release(struct socket *sock) ...@@ -512,10 +513,14 @@ static int llc_ui_release(struct socket *sock)
if (!sk) if (!sk)
goto out; goto out;
sock_hold(sk);
lock_sock(sk);
llc_ui = llc_ui_sk(sk); llc_ui = llc_ui_sk(sk);
if (llc_ui->core_sk && !llc_ui_send_disc(sk)) if (llc_ui->core_sk && !llc_ui_send_disc(sk))
llc_ui_wait_for_disc(sk, 255); llc_ui_wait_for_disc(sk, sk->rcvtimeo);
llc_ui_remove_socket(sk); llc_ui_remove_socket(sk);
release_sock(sk);
if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap)) if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap))
llc_sap_close(llc_ui->sap); llc_sap_close(llc_ui->sap);
sock_orphan(sk); sock_orphan(sk);
...@@ -530,6 +535,7 @@ static int llc_ui_release(struct socket *sock) ...@@ -530,6 +535,7 @@ static int llc_ui_release(struct socket *sock)
sk->timer.data = (unsigned long)sk; sk->timer.data = (unsigned long)sk;
add_timer(&sk->timer); add_timer(&sk->timer);
} }
sock_put(sk);
out: out:
return 0; return 0;
} }
...@@ -706,7 +712,7 @@ static int llc_ui_shutdown(struct socket *sock, int how) ...@@ -706,7 +712,7 @@ static int llc_ui_shutdown(struct socket *sock, int how)
goto out; goto out;
rc = llc_ui_send_disc(sk); rc = llc_ui_send_disc(sk);
if (!rc) if (!rc)
llc_ui_wait_for_disc(sk, 255); llc_ui_wait_for_disc(sk, sk->rcvtimeo);
/* Wake up anyone sleeping in poll */ /* Wake up anyone sleeping in poll */
sk->state_change(sk); sk->state_change(sk);
out: out:
...@@ -772,7 +778,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -772,7 +778,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
goto out; goto out;
} }
rc = llc_ui_wait_for_conn(sk, 255); rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo);
out: out:
release_sock(sk); release_sock(sk);
return rc; return rc;
...@@ -814,18 +820,20 @@ static int llc_ui_listen(struct socket *sock, int backlog) ...@@ -814,18 +820,20 @@ static int llc_ui_listen(struct socket *sock, int backlog)
return rc; return rc;
} }
static int llc_ui_wait_for_disc(struct sock *sk, int seconds) static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int rc, timeout = seconds * HZ; int rc;
add_wait_queue_exclusive(sk->sleep, &wait); add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
rc = 0; rc = 0;
if (sk->state != TCP_CLOSE) if (sk->state != TCP_CLOSE) {
release_sock(sk);
timeout = schedule_timeout(timeout); timeout = schedule_timeout(timeout);
else lock_sock(sk);
} else
break; break;
rc = -ERESTARTSYS; rc = -ERESTARTSYS;
if (signal_pending(current)) if (signal_pending(current))
...@@ -839,19 +847,21 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds) ...@@ -839,19 +847,21 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds)
return rc; return rc;
} }
static int llc_ui_wait_for_conn(struct sock *sk, int seconds) static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
{ {
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int rc, timeout = seconds * HZ; int rc;
add_wait_queue_exclusive(sk->sleep, &wait); add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
rc = 0; rc = 0;
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED) {
release_sock(sk);
timeout = schedule_timeout(timeout); timeout = schedule_timeout(timeout);
if (sk->state == TCP_ESTABLISHED) { lock_sock(sk);
} else {
if (!llc_ui->core_sk) if (!llc_ui->core_sk)
rc = -EAGAIN; rc = -EAGAIN;
break; break;
...@@ -871,6 +881,33 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds) ...@@ -871,6 +881,33 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds)
return rc; return rc;
} }
static int llc_ui_wait_for_data(struct sock *sk, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
int rc;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
rc = 0;
if (skb_queue_empty(&sk->receive_queue)) {
release_sock(sk);
timeout = schedule_timeout(timeout);
lock_sock(sk);
} else
break;
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
rc = -EAGAIN;
if (!timeout)
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
return rc;
}
/** /**
* llc_ui_accept - accept a new incoming connection. * llc_ui_accept - accept a new incoming connection.
* @sock: Socket which connections arrive on. * @sock: Socket which connections arrive on.
...@@ -895,21 +932,13 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -895,21 +932,13 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN) if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN)
goto out; goto out;
/* wait for a connection to arrive. */ /* wait for a connection to arrive. */
do { rc = llc_ui_wait_for_data(sk, sk->rcvtimeo);
skb = skb_dequeue(&sk->receive_queue); if (rc)
if (!skb) { goto out;
rc = -EWOULDBLOCK; skb = skb_dequeue(&sk->receive_queue);
if (flags & O_NONBLOCK)
goto out;
interruptible_sleep_on(sk->sleep);
rc = -ERESTARTSYS;
if (signal_pending(current))
goto out;
}
} while (!skb);
rc = -EINVAL; rc = -EINVAL;
if(!skb->sk) if (!skb->sk)
goto frees; goto frees;
/* attach connection to a new socket. */ /* attach connection to a new socket. */
rc = llc_ui_create(newsock, sk->protocol); rc = llc_ui_create(newsock, sk->protocol);
......
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