Commit 90c1aff7 authored by David Windsor's avatar David Windsor Committed by Pablo Neira Ayuso

ipvs: free ip_vs_dest structs when refcnt=0

Currently, the ip_vs_dest cache frees ip_vs_dest objects when their
reference count becomes < 0.  Aside from not being semantically sound,
this is problematic for the new type refcount_t, which will be introduced
shortly in a separate patch. refcount_t is the new kernel type for
holding reference counts, and provides overflow protection and a
constrained interface relative to atomic_t (the type currently being
used for kernel reference counts).

Per Julian Anastasov: "The problem is that dest_trash currently holds
deleted dests (unlinked from RCU lists) with refcnt=0."  Changing
dest_trash to hold dest with refcnt=1 will allow us to free ip_vs_dest
structs when their refcnt=0, in ip_vs_dest_put_and_free().
Signed-off-by: default avatarDavid Windsor <dwindsor@gmail.com>
Signed-off-by: default avatarJulian Anastasov <ja@ssi.bg>
Signed-off-by: default avatarSimon Horman <horms@verge.net.au>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent a9e419dc
...@@ -1421,7 +1421,7 @@ static inline void ip_vs_dest_put(struct ip_vs_dest *dest) ...@@ -1421,7 +1421,7 @@ static inline void ip_vs_dest_put(struct ip_vs_dest *dest)
static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest) static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest)
{ {
if (atomic_dec_return(&dest->refcnt) < 0) if (atomic_dec_and_test(&dest->refcnt))
kfree(dest); kfree(dest);
} }
......
...@@ -711,7 +711,6 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, int dest_af, ...@@ -711,7 +711,6 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, int dest_af,
dest->vport == svc->port))) { dest->vport == svc->port))) {
/* HIT */ /* HIT */
list_del(&dest->t_list); list_del(&dest->t_list);
ip_vs_dest_hold(dest);
goto out; goto out;
} }
} }
...@@ -741,7 +740,7 @@ static void ip_vs_dest_free(struct ip_vs_dest *dest) ...@@ -741,7 +740,7 @@ static void ip_vs_dest_free(struct ip_vs_dest *dest)
* When the ip_vs_control_clearup is activated by ipvs module exit, * When the ip_vs_control_clearup is activated by ipvs module exit,
* the service tables must have been flushed and all the connections * the service tables must have been flushed and all the connections
* are expired, and the refcnt of each destination in the trash must * are expired, and the refcnt of each destination in the trash must
* be 0, so we simply release them here. * be 1, so we simply release them here.
*/ */
static void ip_vs_trash_cleanup(struct netns_ipvs *ipvs) static void ip_vs_trash_cleanup(struct netns_ipvs *ipvs)
{ {
...@@ -1080,11 +1079,10 @@ static void __ip_vs_del_dest(struct netns_ipvs *ipvs, struct ip_vs_dest *dest, ...@@ -1080,11 +1079,10 @@ static void __ip_vs_del_dest(struct netns_ipvs *ipvs, struct ip_vs_dest *dest,
if (list_empty(&ipvs->dest_trash) && !cleanup) if (list_empty(&ipvs->dest_trash) && !cleanup)
mod_timer(&ipvs->dest_trash_timer, mod_timer(&ipvs->dest_trash_timer,
jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1)); jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
/* dest lives in trash without reference */ /* dest lives in trash with reference */
list_add(&dest->t_list, &ipvs->dest_trash); list_add(&dest->t_list, &ipvs->dest_trash);
dest->idle_start = 0; dest->idle_start = 0;
spin_unlock_bh(&ipvs->dest_trash_lock); spin_unlock_bh(&ipvs->dest_trash_lock);
ip_vs_dest_put(dest);
} }
...@@ -1160,7 +1158,7 @@ static void ip_vs_dest_trash_expire(unsigned long data) ...@@ -1160,7 +1158,7 @@ static void ip_vs_dest_trash_expire(unsigned long data)
spin_lock(&ipvs->dest_trash_lock); spin_lock(&ipvs->dest_trash_lock);
list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) { list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
if (atomic_read(&dest->refcnt) > 0) if (atomic_read(&dest->refcnt) > 1)
continue; continue;
if (dest->idle_start) { if (dest->idle_start) {
if (time_before(now, dest->idle_start + if (time_before(now, dest->idle_start +
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment