patch-2.4.26 linux-2.4.26/net/ipv4/ipvs/ip_vs_conn.c

Next file: linux-2.4.26/net/ipv4/ipvs/ip_vs_ctl.c
Previous file: linux-2.4.26/net/ipv4/ipvs/ip_vs_app.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_conn.c linux-2.4.26/net/ipv4/ipvs/ip_vs_conn.c
@@ -24,12 +24,8 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
-#include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/compiler.h>
 #include <linux/vmalloc.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>                  /* for tcphdr */
@@ -141,25 +137,27 @@
 static int ip_vs_conn_hash(struct ip_vs_conn *cp)
 {
 	unsigned hash;
-
-	if (cp->flags & IP_VS_CONN_F_HASHED) {
-		IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, "
-			  "called from %p\n", __builtin_return_address(0));
-		return 0;
-	}
+	int ret;
 
 	/* Hash by protocol, client address and port */
 	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
 
 	ct_write_lock(hash);
 
-	list_add(&cp->c_list, &ip_vs_conn_tab[hash]);
-	cp->flags |= IP_VS_CONN_F_HASHED;
-	atomic_inc(&cp->refcnt);
+	if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
+		list_add(&cp->c_list, &ip_vs_conn_tab[hash]);
+		cp->flags |= IP_VS_CONN_F_HASHED;
+		atomic_inc(&cp->refcnt);
+		ret = 1;
+	} else {
+		IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, "
+			  "called from %p\n", __builtin_return_address(0));
+		ret = 0;
+	}
 
 	ct_write_unlock(hash);
 
-	return 1;
+	return ret;
 }
 
 
@@ -170,24 +168,23 @@
 static int ip_vs_conn_unhash(struct ip_vs_conn *cp)
 {
 	unsigned hash;
-
-	if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
-		IP_VS_ERR("ip_vs_conn_unhash(): request for unhash flagged, "
-			  "called from %p\n", __builtin_return_address(0));
-		return 0;
-	}
+	int ret;
 
 	/* unhash it and decrease its reference counter */
 	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
 	ct_write_lock(hash);
 
-	list_del(&cp->c_list);
-	cp->flags &= ~IP_VS_CONN_F_HASHED;
-	atomic_dec(&cp->refcnt);
+	if (cp->flags & IP_VS_CONN_F_HASHED) {
+		list_del(&cp->c_list);
+		cp->flags &= ~IP_VS_CONN_F_HASHED;
+		atomic_dec(&cp->refcnt);
+		ret = 1;
+	} else
+		ret = 0;
 
 	ct_write_unlock(hash);
 
-	return 1;
+	return ret;
 }
 
 
@@ -725,15 +722,20 @@
 	/*
 	 *  Check if it is no_cport connection ...
 	 */
-	if (cp->flags & IP_VS_CONN_F_NO_CPORT) {
-		atomic_dec(&ip_vs_conn_no_cport_cnt);
-		ip_vs_conn_unhash(cp);
-		cp->flags &= ~IP_VS_CONN_F_NO_CPORT;
-		cp->cport = h.portp[0];
-		/* hash on new dport */
-		ip_vs_conn_hash(cp);
+	if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+		if (ip_vs_conn_unhash(cp)) {
+			spin_lock(&cp->lock);
+			if (cp->flags & IP_VS_CONN_F_NO_CPORT) {
+				atomic_dec(&ip_vs_conn_no_cport_cnt);
+				cp->flags &= ~IP_VS_CONN_F_NO_CPORT;
+				cp->cport = h.portp[0];
+				IP_VS_DBG(10, "filled cport=%d\n", ntohs(cp->dport));
+			}
+			spin_unlock(&cp->lock);
 
-		IP_VS_DBG(10, "filled cport=%d\n", ntohs(cp->dport));
+			/* hash on new dport */
+			ip_vs_conn_hash(cp);
+		}
 	}
 
 	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
@@ -890,8 +892,6 @@
 	/* update checksum because skb might be defragmented */
 	ip_send_check(old_iph);
 
-	skb->h.raw = skb->nh.raw;
-
 	/*
 	 * Okay, now see if we can stuff it in the buffer as-is.
 	 */
@@ -911,6 +911,7 @@
 		old_iph = skb->nh.iph;
 	}
 
+	skb->h.raw = skb->nh.raw;
 	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 
@@ -1142,11 +1143,14 @@
 		/*
 		 * Invalidate the connection template
 		 */
-		ip_vs_conn_unhash(ct);
-		ct->dport = 65535;
-		ct->vport = 65535;
-		ct->cport = 0;
-		ip_vs_conn_hash(ct);
+		if (ct->cport) {
+			if (ip_vs_conn_unhash(ct)) {
+				ct->dport = 65535;
+				ct->vport = 65535;
+				ct->cport = 0;
+				ip_vs_conn_hash(ct);
+			}
+		}
 
 		/*
 		 * Simply decrease the refcnt of the template,
@@ -1200,7 +1204,8 @@
 	/*
 	 *	unhash it if it is hashed in the conn table
 	 */
-	ip_vs_conn_unhash(cp);
+	if (!ip_vs_conn_unhash(cp))
+		goto expire_later;
 
 	/*
 	 *	refcnt==1 implies I'm the only one referrer

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)