summaryrefslogtreecommitdiffstats
path: root/net/dccp/proto.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-05-12 10:48:52 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2006-05-12 10:48:52 -0400
commit7d63b54a65ce902f9aaa8efe8192aa3b983264d4 (patch)
tree250a77bebe92cbd6edac70a649866044295876db /net/dccp/proto.c
parentfd88de569b802c4a04aaa6ee74667775f4aed8c6 (diff)
parentd8c3291c73b958243b33f8509d4507e76dafd055 (diff)
downloadlinux-7d63b54a65ce902f9aaa8efe8192aa3b983264d4.tar.gz
linux-7d63b54a65ce902f9aaa8efe8192aa3b983264d4.tar.bz2
linux-7d63b54a65ce902f9aaa8efe8192aa3b983264d4.zip
Merge branch 'master'
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r--net/dccp/proto.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 1ff7328b0e17..2e0ee8355c41 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -848,6 +848,7 @@ static int dccp_close_state(struct sock *sk)
void dccp_close(struct sock *sk, long timeout)
{
struct sk_buff *skb;
+ int state;
lock_sock(sk);
@@ -882,6 +883,11 @@ void dccp_close(struct sock *sk, long timeout)
sk_stream_wait_close(sk, timeout);
adjudge_to_death:
+ state = sk->sk_state;
+ sock_hold(sk);
+ sock_orphan(sk);
+ atomic_inc(sk->sk_prot->orphan_count);
+
/*
* It is the last release_sock in its life. It will remove backlog.
*/
@@ -894,8 +900,9 @@ adjudge_to_death:
bh_lock_sock(sk);
BUG_TRAP(!sock_owned_by_user(sk));
- sock_hold(sk);
- sock_orphan(sk);
+ /* Have we already been destroyed by a softirq or backlog? */
+ if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
+ goto out;
/*
* The last release_sock may have processed the CLOSE or RESET
@@ -915,12 +922,12 @@ adjudge_to_death:
#endif
}
- atomic_inc(sk->sk_prot->orphan_count);
if (sk->sk_state == DCCP_CLOSED)
inet_csk_destroy_sock(sk);
/* Otherwise, socket is reprieved until protocol close. */
+out:
bh_unlock_sock(sk);
local_bh_enable();
sock_put(sk);