diff options
author | Julian Anastasov <ja@ssi.bg> | 2013-03-21 11:58:10 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-04-02 00:23:45 +0200 |
commit | 088339a57d6042a8a19a3d5794594b558cd7b624 (patch) | |
tree | 835a3b82d7504f7f5670a7b130eedabf14d0ccc2 /include/net | |
parent | 60b6aa3b319d902db49dbaee7433fe2ac7d0cdb5 (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.h | 12 |
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); |