summaryrefslogtreecommitdiff
path: root/include/net
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2013-03-21 11:58:10 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2013-04-02 00:23:45 +0200
commit088339a57d6042a8a19a3d5794594b558cd7b624 (patch)
tree835a3b82d7504f7f5670a7b130eedabf14d0ccc2 /include/net
parent60b6aa3b319d902db49dbaee7433fe2ac7d0cdb5 (diff)
ipvs: convert connection locking
Convert __ip_vs_conntbl_lock_array as follows: - readers that do not modify conn lists will use RCU lock - updaters that modify lists will use spinlock_t Now for conn lookups we will use RCU read-side critical section. Without using __ip_vs_conn_get such places have access to connection fields and can dereference some pointers like pe and pe_data plus the ability to update timer expiration. If full access is required we contend for reference. We add barrier in __ip_vs_conn_put, so that other CPUs see the refcnt operation after other writes. With the introduction of ip_vs_conn_unlink() we try to reorganize ip_vs_conn_expire(), so that unhashing of connections that should stay more time is avoided, even if it is for very short time. Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off by: Hans Schillstrom <hans@schillstrom.com> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'include/net')
-rw-r--r--include/net/ip_vs.h12
1 files changed, 12 insertions, 0 deletions
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index b06aa6c939fa..5700b07b5186 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -620,6 +620,8 @@ struct ip_vs_conn {
const struct ip_vs_pe *pe;
char *pe_data;
__u8 pe_data_len;
+
+ struct rcu_head rcu_head;
};
/*
@@ -1185,9 +1187,19 @@ struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
const struct ip_vs_iphdr *iph,
int inverse);
+/* Get reference to gain full access to conn.
+ * By default, RCU read-side critical sections have access only to
+ * conn fields and its PE data, see ip_vs_conn_rcu_free() for reference.
+ */
+static inline bool __ip_vs_conn_get(struct ip_vs_conn *cp)
+{
+ return atomic_inc_not_zero(&cp->refcnt);
+}
+
/* put back the conn without restarting its timer */
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
{
+ smp_mb__before_atomic_dec();
atomic_dec(&cp->refcnt);
}
extern void ip_vs_conn_put(struct ip_vs_conn *cp);