|
@@ -29,12 +29,29 @@ int inet_twsk_unhash(struct inet_timewait_sock *tw)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * unhash a timewait socket from bind hash
|
|
|
+ * lock must be hold by caller
|
|
|
+ */
|
|
|
+int inet_twsk_bind_unhash(struct inet_timewait_sock *tw,
|
|
|
+ struct inet_hashinfo *hashinfo)
|
|
|
+{
|
|
|
+ struct inet_bind_bucket *tb = tw->tw_tb;
|
|
|
+
|
|
|
+ if (!tb)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ __hlist_del(&tw->tw_bind_node);
|
|
|
+ tw->tw_tb = NULL;
|
|
|
+ inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
/* Must be called with locally disabled BHs. */
|
|
|
static void __inet_twsk_kill(struct inet_timewait_sock *tw,
|
|
|
struct inet_hashinfo *hashinfo)
|
|
|
{
|
|
|
struct inet_bind_hashbucket *bhead;
|
|
|
- struct inet_bind_bucket *tb;
|
|
|
int refcnt;
|
|
|
/* Unlink from established hashes. */
|
|
|
spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash);
|
|
@@ -46,15 +63,11 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw,
|
|
|
/* Disassociate with bind bucket. */
|
|
|
bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num,
|
|
|
hashinfo->bhash_size)];
|
|
|
+
|
|
|
spin_lock(&bhead->lock);
|
|
|
- tb = tw->tw_tb;
|
|
|
- if (tb) {
|
|
|
- __hlist_del(&tw->tw_bind_node);
|
|
|
- tw->tw_tb = NULL;
|
|
|
- inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
|
|
|
- refcnt++;
|
|
|
- }
|
|
|
+ refcnt += inet_twsk_bind_unhash(tw, hashinfo);
|
|
|
spin_unlock(&bhead->lock);
|
|
|
+
|
|
|
#ifdef SOCK_REFCNT_DEBUG
|
|
|
if (atomic_read(&tw->tw_refcnt) != 1) {
|
|
|
printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",
|