* [PATCH net 0/4] IPVS fixes for corner cases
@ 2013-08-28 16:29 Julian Anastasov
2013-08-28 16:29 ` [PATCH net 1/4] ipvs: do not use dest after ip_vs_dest_put in LBLC Julian Anastasov
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Julian Anastasov @ 2013-08-28 16:29 UTC (permalink / raw)
To: Simon Horman; +Cc: lvs-devel
The patchset contains fixes for races during
dest and service deletion caused from the recent RCU changes.
The last change is required if CPU 0 can be missing
from the mask of possible CPUs. Otherwise, it can be
considered a non-fatal change.
Julian Anastasov (4):
ipvs: do not use dest after ip_vs_dest_put in LBLC
ipvs: do not use dest after ip_vs_dest_put in LBLCR
ipvs: make the service replacement more robust
ipvs: stats should not depend on CPU 0
include/net/ip_vs.h | 6 +--
net/netfilter/ipvs/ip_vs_core.c | 12 ++++-
net/netfilter/ipvs/ip_vs_ctl.c | 90 +++++++++++++++-----------------------
net/netfilter/ipvs/ip_vs_est.c | 4 +-
net/netfilter/ipvs/ip_vs_lblc.c | 68 +++++++++++++---------------
net/netfilter/ipvs/ip_vs_lblcr.c | 50 ++++++++-------------
6 files changed, 101 insertions(+), 129 deletions(-)
--
1.7.3.4
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net 1/4] ipvs: do not use dest after ip_vs_dest_put in LBLC
2013-08-28 16:29 [PATCH net 0/4] IPVS fixes for corner cases Julian Anastasov
@ 2013-08-28 16:29 ` Julian Anastasov
2013-08-28 16:29 ` [PATCH net 2/4] ipvs: do not use dest after ip_vs_dest_put in LBLCR Julian Anastasov
` (2 subsequent siblings)
3 siblings, 0 replies; 13+ messages in thread
From: Julian Anastasov @ 2013-08-28 16:29 UTC (permalink / raw)
To: Simon Horman; +Cc: lvs-devel
commit c2a4ffb70eef39 ("ipvs: convert lblc scheduler to rcu")
allows RCU readers to use dest after calling ip_vs_dest_put().
In the corner case it can race with ip_vs_dest_trash_expire()
which can release the dest while it is being returned to the
RCU readers as scheduling result.
To fix the problem do not allow en->dest to be replaced and
defer the ip_vs_dest_put() call by using RCU callback. Now
en->dest does not need to be RCU pointer.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
---
net/netfilter/ipvs/ip_vs_lblc.c | 68 ++++++++++++++++++---------------------
1 files changed, 31 insertions(+), 37 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 1383b0e..b39b0e9 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -93,7 +93,7 @@ struct ip_vs_lblc_entry {
struct hlist_node list;
int af; /* address family */
union nf_inet_addr addr; /* destination IP address */
- struct ip_vs_dest __rcu *dest; /* real server (cache) */
+ struct ip_vs_dest *dest; /* real server (cache) */
unsigned long lastuse; /* last used time */
struct rcu_head rcu_head;
};
@@ -130,20 +130,21 @@ static struct ctl_table vs_vars_table[] = {
};
#endif
-static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
+static void ip_vs_lblc_rcu_free(struct rcu_head *head)
{
- struct ip_vs_dest *dest;
+ struct ip_vs_lblc_entry *en = container_of(head,
+ struct ip_vs_lblc_entry,
+ rcu_head);
- hlist_del_rcu(&en->list);
- /*
- * We don't kfree dest because it is referred either by its service
- * or the trash dest list.
- */
- dest = rcu_dereference_protected(en->dest, 1);
- ip_vs_dest_put(dest);
- kfree_rcu(en, rcu_head);
+ ip_vs_dest_put(en->dest);
+ kfree(en);
}
+static inline void ip_vs_lblc_del(struct ip_vs_lblc_entry *en)
+{
+ hlist_del_rcu(&en->list);
+ call_rcu(&en->rcu_head, ip_vs_lblc_rcu_free);
+}
/*
* Returns hash value for IPVS LBLC entry
@@ -203,30 +204,23 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
struct ip_vs_lblc_entry *en;
en = ip_vs_lblc_get(dest->af, tbl, daddr);
- if (!en) {
- en = kmalloc(sizeof(*en), GFP_ATOMIC);
- if (!en)
- return NULL;
-
- en->af = dest->af;
- ip_vs_addr_copy(dest->af, &en->addr, daddr);
- en->lastuse = jiffies;
+ if (en) {
+ if (en->dest == dest)
+ return en;
+ ip_vs_lblc_del(en);
+ }
+ en = kmalloc(sizeof(*en), GFP_ATOMIC);
+ if (!en)
+ return NULL;
- ip_vs_dest_hold(dest);
- RCU_INIT_POINTER(en->dest, dest);
+ en->af = dest->af;
+ ip_vs_addr_copy(dest->af, &en->addr, daddr);
+ en->lastuse = jiffies;
- ip_vs_lblc_hash(tbl, en);
- } else {
- struct ip_vs_dest *old_dest;
+ ip_vs_dest_hold(dest);
+ en->dest = dest;
- old_dest = rcu_dereference_protected(en->dest, 1);
- if (old_dest != dest) {
- ip_vs_dest_put(old_dest);
- ip_vs_dest_hold(dest);
- /* No ordering constraints for refcnt */
- RCU_INIT_POINTER(en->dest, dest);
- }
- }
+ ip_vs_lblc_hash(tbl, en);
return en;
}
@@ -246,7 +240,7 @@ static void ip_vs_lblc_flush(struct ip_vs_service *svc)
tbl->dead = 1;
for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) {
- ip_vs_lblc_free(en);
+ ip_vs_lblc_del(en);
atomic_dec(&tbl->entries);
}
}
@@ -281,7 +275,7 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
sysctl_lblc_expiration(svc)))
continue;
- ip_vs_lblc_free(en);
+ ip_vs_lblc_del(en);
atomic_dec(&tbl->entries);
}
spin_unlock(&svc->sched_lock);
@@ -335,7 +329,7 @@ static void ip_vs_lblc_check_expire(unsigned long data)
if (time_before(now, en->lastuse + ENTRY_TIMEOUT))
continue;
- ip_vs_lblc_free(en);
+ ip_vs_lblc_del(en);
atomic_dec(&tbl->entries);
goal--;
}
@@ -511,7 +505,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
* free up entries from the trash at any time.
*/
- dest = rcu_dereference(en->dest);
+ dest = en->dest;
if ((dest->flags & IP_VS_DEST_F_AVAILABLE) &&
atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
goto out;
@@ -631,7 +625,7 @@ static void __exit ip_vs_lblc_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
unregister_pernet_subsys(&ip_vs_lblc_ops);
- synchronize_rcu();
+ rcu_barrier();
}
--
1.7.3.4
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net 2/4] ipvs: do not use dest after ip_vs_dest_put in LBLCR
2013-08-28 16:29 [PATCH net 0/4] IPVS fixes for corner cases Julian Anastasov
2013-08-28 16:29 ` [PATCH net 1/4] ipvs: do not use dest after ip_vs_dest_put in LBLC Julian Anastasov
@ 2013-08-28 16:29 ` Julian Anastasov
2013-08-28 16:29 ` [PATCH net 3/4] ipvs: make the service replacement more robust Julian Anastasov
2013-08-28 16:29 ` [PATCH net 4/4] ipvs: stats should not depend on CPU 0 Julian Anastasov
3 siblings, 0 replies; 13+ messages in thread
From: Julian Anastasov @ 2013-08-28 16:29 UTC (permalink / raw)
To: Simon Horman; +Cc: lvs-devel
commit c5549571f975ab ("ipvs: convert lblcr scheduler to rcu")
allows RCU readers to use dest after calling ip_vs_dest_put().
In the corner case it can race with ip_vs_dest_trash_expire()
which can release the dest while it is being returned to the
RCU readers as scheduling result.
To fix the problem do not allow e->dest to be replaced and
defer the ip_vs_dest_put() call by using RCU callback. Now
e->dest does not need to be RCU pointer.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
---
net/netfilter/ipvs/ip_vs_lblcr.c | 50 +++++++++++++++----------------------
1 files changed, 20 insertions(+), 30 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index 3cd85b2..64de585 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -89,7 +89,7 @@
*/
struct ip_vs_dest_set_elem {
struct list_head list; /* list link */
- struct ip_vs_dest __rcu *dest; /* destination server */
+ struct ip_vs_dest *dest; /* destination server */
struct rcu_head rcu_head;
};
@@ -107,11 +107,7 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
if (check) {
list_for_each_entry(e, &set->list, list) {
- struct ip_vs_dest *d;
-
- d = rcu_dereference_protected(e->dest, 1);
- if (d == dest)
- /* already existed */
+ if (e->dest == dest)
return;
}
}
@@ -121,7 +117,7 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
return;
ip_vs_dest_hold(dest);
- RCU_INIT_POINTER(e->dest, dest);
+ e->dest = dest;
list_add_rcu(&e->list, &set->list);
atomic_inc(&set->size);
@@ -129,22 +125,27 @@ static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
set->lastmod = jiffies;
}
+static void ip_vs_lblcr_elem_rcu_free(struct rcu_head *head)
+{
+ struct ip_vs_dest_set_elem *e;
+
+ e = container_of(head, struct ip_vs_dest_set_elem, rcu_head);
+ ip_vs_dest_put(e->dest);
+ kfree(e);
+}
+
static void
ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
{
struct ip_vs_dest_set_elem *e;
list_for_each_entry(e, &set->list, list) {
- struct ip_vs_dest *d;
-
- d = rcu_dereference_protected(e->dest, 1);
- if (d == dest) {
+ if (e->dest == dest) {
/* HIT */
atomic_dec(&set->size);
set->lastmod = jiffies;
- ip_vs_dest_put(dest);
list_del_rcu(&e->list);
- kfree_rcu(e, rcu_head);
+ call_rcu(&e->rcu_head, ip_vs_lblcr_elem_rcu_free);
break;
}
}
@@ -155,16 +156,8 @@ static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
struct ip_vs_dest_set_elem *e, *ep;
list_for_each_entry_safe(e, ep, &set->list, list) {
- struct ip_vs_dest *d;
-
- d = rcu_dereference_protected(e->dest, 1);
- /*
- * We don't kfree dest because it is referred either
- * by its service or by the trash dest list.
- */
- ip_vs_dest_put(d);
list_del_rcu(&e->list);
- kfree_rcu(e, rcu_head);
+ call_rcu(&e->rcu_head, ip_vs_lblcr_elem_rcu_free);
}
}
@@ -175,12 +168,9 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
struct ip_vs_dest *dest, *least;
int loh, doh;
- if (set == NULL)
- return NULL;
-
/* select the first destination server, whose weight > 0 */
list_for_each_entry_rcu(e, &set->list, list) {
- least = rcu_dereference(e->dest);
+ least = e->dest;
if (least->flags & IP_VS_DEST_F_OVERLOAD)
continue;
@@ -195,7 +185,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
/* find the destination with the weighted least load */
nextstage:
list_for_each_entry_continue_rcu(e, &set->list, list) {
- dest = rcu_dereference(e->dest);
+ dest = e->dest;
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
continue;
@@ -232,7 +222,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
/* select the first destination server, whose weight > 0 */
list_for_each_entry(e, &set->list, list) {
- most = rcu_dereference_protected(e->dest, 1);
+ most = e->dest;
if (atomic_read(&most->weight) > 0) {
moh = ip_vs_dest_conn_overhead(most);
goto nextstage;
@@ -243,7 +233,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
/* find the destination with the weighted most load */
nextstage:
list_for_each_entry_continue(e, &set->list, list) {
- dest = rcu_dereference_protected(e->dest, 1);
+ dest = e->dest;
doh = ip_vs_dest_conn_overhead(dest);
/* moh/mw < doh/dw ==> moh*dw < doh*mw, where mw,dw>0 */
if ((moh * atomic_read(&dest->weight) <
@@ -819,7 +809,7 @@ static void __exit ip_vs_lblcr_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
unregister_pernet_subsys(&ip_vs_lblcr_ops);
- synchronize_rcu();
+ rcu_barrier();
}
--
1.7.3.4
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net 3/4] ipvs: make the service replacement more robust
2013-08-28 16:29 [PATCH net 0/4] IPVS fixes for corner cases Julian Anastasov
2013-08-28 16:29 ` [PATCH net 1/4] ipvs: do not use dest after ip_vs_dest_put in LBLC Julian Anastasov
2013-08-28 16:29 ` [PATCH net 2/4] ipvs: do not use dest after ip_vs_dest_put in LBLCR Julian Anastasov
@ 2013-08-28 16:29 ` Julian Anastasov
2013-09-10 19:28 ` Julian Anastasov
2013-08-28 16:29 ` [PATCH net 4/4] ipvs: stats should not depend on CPU 0 Julian Anastasov
3 siblings, 1 reply; 13+ messages in thread
From: Julian Anastasov @ 2013-08-28 16:29 UTC (permalink / raw)
To: Simon Horman; +Cc: lvs-devel
commit 578bc3ef1e473a ("ipvs: reorganize dest trash") added
IP_VS_DEST_STATE_REMOVING flag and RCU callback named
ip_vs_dest_wait_readers() to keep dests and services after
removal for at least a RCU grace period. But we have the
following corner cases:
- we can not reuse the same dest if its service is removed
while IP_VS_DEST_STATE_REMOVING is still set because another dest
removal in the first grace period can not extend this period.
It can happen when ipvsadm -C && ipvsadm -R is used.
- dest->svc can be replaced but ip_vs_in_stats() and
ip_vs_out_stats() have no explicit read memory barriers
when accessing dest->svc. It can happen that dest->svc
was just freed (replaced) while we use it to update
the stats.
We solve the problems as follows:
- IP_VS_DEST_STATE_REMOVING is removed and we ensure a fixed
idle period for the dest (IP_VS_DEST_TRASH_PERIOD). idle_start
will remember when for first time after deletion we noticed
dest->refcnt=0. Later, the connections can grab a reference
while in RCU grace period but if refcnt becomes 0 we can
safely free the dest and its svc.
- dest->svc becomes RCU pointer. As result, we add explicit
RCU locking in ip_vs_in_stats() and ip_vs_out_stats().
- __ip_vs_unbind_svc is renamed to __ip_vs_svc_put(), it
now can free the service immediately or after a RCU grace
period. dest->svc is not set to NULL anymore.
As result, unlinked dests and their services are
freed always after IP_VS_DEST_TRASH_PERIOD period, unused
services are freed after a RCU grace period.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
---
include/net/ip_vs.h | 6 +--
net/netfilter/ipvs/ip_vs_core.c | 12 ++++-
net/netfilter/ipvs/ip_vs_ctl.c | 90 +++++++++++++++------------------------
3 files changed, 47 insertions(+), 61 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index f0d70f0..ce3e942 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -723,8 +723,6 @@ struct ip_vs_dest_dst {
struct rcu_head rcu_head;
};
-/* In grace period after removing */
-#define IP_VS_DEST_STATE_REMOVING 0x01
/*
* The real server destination forwarding entry
* with ip address, port number, and so on.
@@ -742,7 +740,7 @@ struct ip_vs_dest {
atomic_t refcnt; /* reference counter */
struct ip_vs_stats stats; /* statistics */
- unsigned long state; /* state flags */
+ unsigned long idle_start; /* start time, jiffies */
/* connection counters and thresholds */
atomic_t activeconns; /* active connections */
@@ -756,7 +754,7 @@ struct ip_vs_dest {
struct ip_vs_dest_dst __rcu *dest_dst; /* cached dst info */
/* for virtual service */
- struct ip_vs_service *svc; /* service it belongs to */
+ struct ip_vs_service __rcu *svc; /* service it belongs to */
__u16 protocol; /* which protocol (TCP/UDP) */
__be16 vport; /* virtual port number */
union nf_inet_addr vaddr; /* virtual IP address */
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 4f69e83..74fd00c 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -116,6 +116,7 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
struct ip_vs_cpu_stats *s;
+ struct ip_vs_service *svc;
s = this_cpu_ptr(dest->stats.cpustats);
s->ustats.inpkts++;
@@ -123,11 +124,14 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
s->ustats.inbytes += skb->len;
u64_stats_update_end(&s->syncp);
- s = this_cpu_ptr(dest->svc->stats.cpustats);
+ rcu_read_lock();
+ svc = rcu_dereference(dest->svc);
+ s = this_cpu_ptr(svc->stats.cpustats);
s->ustats.inpkts++;
u64_stats_update_begin(&s->syncp);
s->ustats.inbytes += skb->len;
u64_stats_update_end(&s->syncp);
+ rcu_read_unlock();
s = this_cpu_ptr(ipvs->tot_stats.cpustats);
s->ustats.inpkts++;
@@ -146,6 +150,7 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
struct ip_vs_cpu_stats *s;
+ struct ip_vs_service *svc;
s = this_cpu_ptr(dest->stats.cpustats);
s->ustats.outpkts++;
@@ -153,11 +158,14 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
s->ustats.outbytes += skb->len;
u64_stats_update_end(&s->syncp);
- s = this_cpu_ptr(dest->svc->stats.cpustats);
+ rcu_read_lock();
+ svc = rcu_dereference(dest->svc);
+ s = this_cpu_ptr(svc->stats.cpustats);
s->ustats.outpkts++;
u64_stats_update_begin(&s->syncp);
s->ustats.outbytes += skb->len;
u64_stats_update_end(&s->syncp);
+ rcu_read_unlock();
s = this_cpu_ptr(ipvs->tot_stats.cpustats);
s->ustats.outpkts++;
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index c8148e4..98ad387 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -460,7 +460,7 @@ static inline void
__ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
{
atomic_inc(&svc->refcnt);
- dest->svc = svc;
+ rcu_assign_pointer(dest->svc, svc);
}
static void ip_vs_service_free(struct ip_vs_service *svc)
@@ -470,18 +470,25 @@ static void ip_vs_service_free(struct ip_vs_service *svc)
kfree(svc);
}
-static void
-__ip_vs_unbind_svc(struct ip_vs_dest *dest)
+static void ip_vs_service_rcu_free(struct rcu_head *head)
{
- struct ip_vs_service *svc = dest->svc;
+ struct ip_vs_service *svc;
- dest->svc = NULL;
+ svc = container_of(head, struct ip_vs_service, rcu_head);
+ ip_vs_service_free(svc);
+}
+
+static void __ip_vs_svc_put(struct ip_vs_service *svc, bool do_delay)
+{
if (atomic_dec_and_test(&svc->refcnt)) {
IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
svc->fwmark,
IP_VS_DBG_ADDR(svc->af, &svc->addr),
ntohs(svc->port));
- ip_vs_service_free(svc);
+ if (do_delay)
+ call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
+ else
+ ip_vs_service_free(svc);
}
}
@@ -667,11 +674,6 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
IP_VS_DBG_ADDR(svc->af, &dest->addr),
ntohs(dest->port),
atomic_read(&dest->refcnt));
- /* We can not reuse dest while in grace period
- * because conns still can use dest->svc
- */
- if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
- continue;
if (dest->af == svc->af &&
ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
dest->port == dport &&
@@ -697,8 +699,10 @@ out:
static void ip_vs_dest_free(struct ip_vs_dest *dest)
{
+ struct ip_vs_service *svc = rcu_dereference_protected(dest->svc, 1);
+
__ip_vs_dst_cache_reset(dest);
- __ip_vs_unbind_svc(dest);
+ __ip_vs_svc_put(svc, false);
free_percpu(dest->stats.cpustats);
kfree(dest);
}
@@ -771,6 +775,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
struct ip_vs_dest_user_kern *udest, int add)
{
struct netns_ipvs *ipvs = net_ipvs(svc->net);
+ struct ip_vs_service *old_svc;
struct ip_vs_scheduler *sched;
int conn_flags;
@@ -792,13 +797,14 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
atomic_set(&dest->conn_flags, conn_flags);
/* bind the service */
- if (!dest->svc) {
+ old_svc = rcu_dereference_protected(dest->svc, 1);
+ if (!old_svc) {
__ip_vs_bind_svc(dest, svc);
} else {
- if (dest->svc != svc) {
- __ip_vs_unbind_svc(dest);
+ if (old_svc != svc) {
ip_vs_zero_stats(&dest->stats);
__ip_vs_bind_svc(dest, svc);
+ __ip_vs_svc_put(old_svc, true);
}
}
@@ -998,16 +1004,6 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
return 0;
}
-static void ip_vs_dest_wait_readers(struct rcu_head *head)
-{
- struct ip_vs_dest *dest = container_of(head, struct ip_vs_dest,
- rcu_head);
-
- /* End of grace period after unlinking */
- clear_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
-}
-
-
/*
* Delete a destination (must be already unlinked from the service)
*/
@@ -1023,20 +1019,16 @@ static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest,
*/
ip_vs_rs_unhash(dest);
- if (!cleanup) {
- set_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
- call_rcu(&dest->rcu_head, ip_vs_dest_wait_readers);
- }
-
spin_lock_bh(&ipvs->dest_trash_lock);
IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
atomic_read(&dest->refcnt));
if (list_empty(&ipvs->dest_trash) && !cleanup)
mod_timer(&ipvs->dest_trash_timer,
- jiffies + IP_VS_DEST_TRASH_PERIOD);
+ jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
/* dest lives in trash without reference */
list_add(&dest->t_list, &ipvs->dest_trash);
+ dest->idle_start = 0;
spin_unlock_bh(&ipvs->dest_trash_lock);
ip_vs_dest_put(dest);
}
@@ -1108,24 +1100,30 @@ static void ip_vs_dest_trash_expire(unsigned long data)
struct net *net = (struct net *) data;
struct netns_ipvs *ipvs = net_ipvs(net);
struct ip_vs_dest *dest, *next;
+ unsigned long now = jiffies;
spin_lock(&ipvs->dest_trash_lock);
list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
- /* Skip if dest is in grace period */
- if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
- continue;
if (atomic_read(&dest->refcnt) > 0)
continue;
+ if (dest->idle_start) {
+ if (time_before(now, dest->idle_start +
+ IP_VS_DEST_TRASH_PERIOD))
+ continue;
+ } else {
+ dest->idle_start = max(1UL, now);
+ continue;
+ }
IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u from trash\n",
dest->vfwmark,
- IP_VS_DBG_ADDR(dest->svc->af, &dest->addr),
+ IP_VS_DBG_ADDR(dest->af, &dest->addr),
ntohs(dest->port));
list_del(&dest->t_list);
ip_vs_dest_free(dest);
}
if (!list_empty(&ipvs->dest_trash))
mod_timer(&ipvs->dest_trash_timer,
- jiffies + IP_VS_DEST_TRASH_PERIOD);
+ jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
spin_unlock(&ipvs->dest_trash_lock);
}
@@ -1320,14 +1318,6 @@ out:
return ret;
}
-static void ip_vs_service_rcu_free(struct rcu_head *head)
-{
- struct ip_vs_service *svc;
-
- svc = container_of(head, struct ip_vs_service, rcu_head);
- ip_vs_service_free(svc);
-}
-
/*
* Delete a service from the service list
* - The service must be unlinked, unlocked and not referenced!
@@ -1376,13 +1366,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
/*
* Free the service if nobody refers to it
*/
- if (atomic_dec_and_test(&svc->refcnt)) {
- IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
- svc->fwmark,
- IP_VS_DBG_ADDR(svc->af, &svc->addr),
- ntohs(svc->port));
- call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
- }
+ __ip_vs_svc_put(svc, true);
/* decrease the module use count */
ip_vs_use_count_dec();
@@ -3836,10 +3820,6 @@ void __net_exit ip_vs_control_net_cleanup(struct net *net)
{
struct netns_ipvs *ipvs = net_ipvs(net);
- /* Some dest can be in grace period even before cleanup, we have to
- * defer ip_vs_trash_cleanup until ip_vs_dest_wait_readers is called.
- */
- rcu_barrier();
ip_vs_trash_cleanup(net);
ip_vs_stop_estimator(net, &ipvs->tot_stats);
ip_vs_control_net_cleanup_sysctl(net);
--
1.7.3.4
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net 4/4] ipvs: stats should not depend on CPU 0
2013-08-28 16:29 [PATCH net 0/4] IPVS fixes for corner cases Julian Anastasov
` (2 preceding siblings ...)
2013-08-28 16:29 ` [PATCH net 3/4] ipvs: make the service replacement more robust Julian Anastasov
@ 2013-08-28 16:29 ` Julian Anastasov
2013-08-30 1:17 ` Simon Horman
2013-08-30 7:46 ` Hans Schillstrom
3 siblings, 2 replies; 13+ messages in thread
From: Julian Anastasov @ 2013-08-28 16:29 UTC (permalink / raw)
To: Simon Horman; +Cc: lvs-devel
When reading percpu stats we need to properly reset
the sum when CPU 0 is not present in the possible mask.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
---
net/netfilter/ipvs/ip_vs_est.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
index 6bee6d0..1425e9a 100644
--- a/net/netfilter/ipvs/ip_vs_est.c
+++ b/net/netfilter/ipvs/ip_vs_est.c
@@ -59,12 +59,13 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
struct ip_vs_cpu_stats __percpu *stats)
{
int i;
+ bool add = false;
for_each_possible_cpu(i) {
struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
unsigned int start;
__u64 inbytes, outbytes;
- if (i) {
+ if (add) {
sum->conns += s->ustats.conns;
sum->inpkts += s->ustats.inpkts;
sum->outpkts += s->ustats.outpkts;
@@ -76,6 +77,7 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
sum->inbytes += inbytes;
sum->outbytes += outbytes;
} else {
+ add = true;
sum->conns = s->ustats.conns;
sum->inpkts = s->ustats.inpkts;
sum->outpkts = s->ustats.outpkts;
--
1.7.3.4
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net 4/4] ipvs: stats should not depend on CPU 0
2013-08-28 16:29 ` [PATCH net 4/4] ipvs: stats should not depend on CPU 0 Julian Anastasov
@ 2013-08-30 1:17 ` Simon Horman
2013-08-30 7:31 ` Julian Anastasov
2013-08-30 7:46 ` Hans Schillstrom
1 sibling, 1 reply; 13+ messages in thread
From: Simon Horman @ 2013-08-30 1:17 UTC (permalink / raw)
To: Julian Anastasov; +Cc: lvs-devel, Hans Schillstrom
[ Cc: Hans Schillstrom ]
On Wed, Aug 28, 2013 at 07:29:36PM +0300, Julian Anastasov wrote:
> When reading percpu stats we need to properly reset
> the sum when CPU 0 is not present in the possible mask.
It seems reasonable to me that this condition could occur,
though I am not aware of a specific case where that is so.
Can I confirm that this problem was introduced by
b17fc9963f837ef1 ("IPVS: netns, ip_vs_stats and its procfs")?
>
> Signed-off-by: Julian Anastasov <ja@ssi.bg>
> ---
> net/netfilter/ipvs/ip_vs_est.c | 4 +++-
> 1 files changed, 3 insertions(+), 1 deletions(-)
>
> diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
> index 6bee6d0..1425e9a 100644
> --- a/net/netfilter/ipvs/ip_vs_est.c
> +++ b/net/netfilter/ipvs/ip_vs_est.c
> @@ -59,12 +59,13 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
> struct ip_vs_cpu_stats __percpu *stats)
> {
> int i;
> + bool add = false;
>
> for_each_possible_cpu(i) {
> struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
> unsigned int start;
> __u64 inbytes, outbytes;
> - if (i) {
> + if (add) {
> sum->conns += s->ustats.conns;
> sum->inpkts += s->ustats.inpkts;
> sum->outpkts += s->ustats.outpkts;
> @@ -76,6 +77,7 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
> sum->inbytes += inbytes;
> sum->outbytes += outbytes;
> } else {
> + add = true;
> sum->conns = s->ustats.conns;
> sum->inpkts = s->ustats.inpkts;
> sum->outpkts = s->ustats.outpkts;
> --
> 1.7.3.4
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 4/4] ipvs: stats should not depend on CPU 0
2013-08-30 1:17 ` Simon Horman
@ 2013-08-30 7:31 ` Julian Anastasov
2013-08-30 8:53 ` Simon Horman
0 siblings, 1 reply; 13+ messages in thread
From: Julian Anastasov @ 2013-08-30 7:31 UTC (permalink / raw)
To: Simon Horman; +Cc: lvs-devel, Hans Schillstrom
Hello,
On Fri, 30 Aug 2013, Simon Horman wrote:
> [ Cc: Hans Schillstrom ]
>
> On Wed, Aug 28, 2013 at 07:29:36PM +0300, Julian Anastasov wrote:
> > When reading percpu stats we need to properly reset
> > the sum when CPU 0 is not present in the possible mask.
>
> It seems reasonable to me that this condition could occur,
> though I am not aware of a specific case where that is so.
>
> Can I confirm that this problem was introduced by
> b17fc9963f837ef1 ("IPVS: netns, ip_vs_stats and its procfs")?
That is correct, I forgot to track the initial
commit, you can freely add such information before
applying.
Regards
--
Julian Anastasov <ja@ssi.bg>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 4/4] ipvs: stats should not depend on CPU 0
2013-08-28 16:29 ` [PATCH net 4/4] ipvs: stats should not depend on CPU 0 Julian Anastasov
2013-08-30 1:17 ` Simon Horman
@ 2013-08-30 7:46 ` Hans Schillstrom
1 sibling, 0 replies; 13+ messages in thread
From: Hans Schillstrom @ 2013-08-30 7:46 UTC (permalink / raw)
To: Julian Anastasov; +Cc: Simon Horman, lvs-devel
[-- Attachment #1: Type: text/plain, Size: 1413 bytes --]
On Wed, 2013-08-28 at 19:29 +0300, Julian Anastasov wrote:
> When reading percpu stats we need to properly reset
> the sum when CPU 0 is not present in the possible mask.
Not a very common case, but still possible.
> Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Hans Schillstrom <hans@schillstrom.com>
> ---
> net/netfilter/ipvs/ip_vs_est.c | 4 +++-
> 1 files changed, 3 insertions(+), 1 deletions(-)
>
> diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
> index 6bee6d0..1425e9a 100644
> --- a/net/netfilter/ipvs/ip_vs_est.c
> +++ b/net/netfilter/ipvs/ip_vs_est.c
> @@ -59,12 +59,13 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
> struct ip_vs_cpu_stats __percpu *stats)
> {
> int i;
> + bool add = false;
>
> for_each_possible_cpu(i) {
> struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
> unsigned int start;
> __u64 inbytes, outbytes;
> - if (i) {
> + if (add) {
> sum->conns += s->ustats.conns;
> sum->inpkts += s->ustats.inpkts;
> sum->outpkts += s->ustats.outpkts;
> @@ -76,6 +77,7 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
> sum->inbytes += inbytes;
> sum->outbytes += outbytes;
> } else {
> + add = true;
> sum->conns = s->ustats.conns;
> sum->inpkts = s->ustats.inpkts;
> sum->outpkts = s->ustats.outpkts;
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 6177 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 4/4] ipvs: stats should not depend on CPU 0
2013-08-30 7:31 ` Julian Anastasov
@ 2013-08-30 8:53 ` Simon Horman
2013-08-30 8:58 ` Simon Horman
0 siblings, 1 reply; 13+ messages in thread
From: Simon Horman @ 2013-08-30 8:53 UTC (permalink / raw)
To: Julian Anastasov, Hans Schillstrom; +Cc: lvs-devel
On Fri, Aug 30, 2013 at 10:31:57AM +0300, Julian Anastasov wrote:
>
> Hello,
>
> On Fri, 30 Aug 2013, Simon Horman wrote:
>
> > [ Cc: Hans Schillstrom ]
> >
> > On Wed, Aug 28, 2013 at 07:29:36PM +0300, Julian Anastasov wrote:
> > > When reading percpu stats we need to properly reset
> > > the sum when CPU 0 is not present in the possible mask.
> >
> > It seems reasonable to me that this condition could occur,
> > though I am not aware of a specific case where that is so.
> >
> > Can I confirm that this problem was introduced by
> > b17fc9963f837ef1 ("IPVS: netns, ip_vs_stats and its procfs")?
>
> That is correct, I forgot to track the initial
> commit, you can freely add such information before
> applying.
>
> Regards
>
> --
> Julian Anastasov <ja@ssi.bg>
>
On Fri, Aug 30, 2013 at 09:46:08AM +0200, Hans Schillstrom wrote:
>
> On Wed, 2013-08-28 at 19:29 +0300, Julian Anastasov wrote:
> > When reading percpu stats we need to properly reset
> > the sum when CPU 0 is not present in the possible mask.
>
> Not a very common case, but still possible.
>
> > Signed-off-by: Julian Anastasov <ja@ssi.bg>
>
> Acked-by: Hans Schillstrom <hans@schillstrom.com>
Thanks guys, I have queued up the following in the ipvs tree
along with the rest of this series.
From 056a057b581b7a98669e65745c9866d233f82a18 Mon Sep 17 00:00:00 2001
From: Julian Anastasov <ja@ssi.bg>
Date: Wed, 28 Aug 2013 19:29:36 +0300
Subject: [PATCH] ipvs: stats should not depend on CPU 0
When reading percpu stats we need to properly reset
the sum when CPU 0 is not present in the possible mask.
This problem was introduced by 17fc9963f837ef1
("IPVS: netns, ip_vs_stats and its procfs").
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Hans Schillstrom <hans@schillstrom.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_est.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
index 6bee6d0..1425e9a 100644
--- a/net/netfilter/ipvs/ip_vs_est.c
+++ b/net/netfilter/ipvs/ip_vs_est.c
@@ -59,12 +59,13 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
struct ip_vs_cpu_stats __percpu *stats)
{
int i;
+ bool add = false;
for_each_possible_cpu(i) {
struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
unsigned int start;
__u64 inbytes, outbytes;
- if (i) {
+ if (add) {
sum->conns += s->ustats.conns;
sum->inpkts += s->ustats.inpkts;
sum->outpkts += s->ustats.outpkts;
@@ -76,6 +77,7 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
sum->inbytes += inbytes;
sum->outbytes += outbytes;
} else {
+ add = true;
sum->conns = s->ustats.conns;
sum->inpkts = s->ustats.inpkts;
sum->outpkts = s->ustats.outpkts;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net 4/4] ipvs: stats should not depend on CPU 0
2013-08-30 8:53 ` Simon Horman
@ 2013-08-30 8:58 ` Simon Horman
2013-08-30 9:53 ` Julian Anastasov
0 siblings, 1 reply; 13+ messages in thread
From: Simon Horman @ 2013-08-30 8:58 UTC (permalink / raw)
To: Julian Anastasov, Hans Schillstrom; +Cc: lvs-devel
On Fri, Aug 30, 2013 at 05:53:32PM +0900, Simon Horman wrote:
> On Fri, Aug 30, 2013 at 10:31:57AM +0300, Julian Anastasov wrote:
> >
> > Hello,
> >
> > On Fri, 30 Aug 2013, Simon Horman wrote:
> >
> > > [ Cc: Hans Schillstrom ]
> > >
> > > On Wed, Aug 28, 2013 at 07:29:36PM +0300, Julian Anastasov wrote:
> > > > When reading percpu stats we need to properly reset
> > > > the sum when CPU 0 is not present in the possible mask.
> > >
> > > It seems reasonable to me that this condition could occur,
> > > though I am not aware of a specific case where that is so.
> > >
> > > Can I confirm that this problem was introduced by
> > > b17fc9963f837ef1 ("IPVS: netns, ip_vs_stats and its procfs")?
> >
> > That is correct, I forgot to track the initial
> > commit, you can freely add such information before
> > applying.
> >
> > Regards
> >
> > --
> > Julian Anastasov <ja@ssi.bg>
> >
>
> On Fri, Aug 30, 2013 at 09:46:08AM +0200, Hans Schillstrom wrote:
> >
> > On Wed, 2013-08-28 at 19:29 +0300, Julian Anastasov wrote:
> > > When reading percpu stats we need to properly reset
> > > the sum when CPU 0 is not present in the possible mask.
> >
> > Not a very common case, but still possible.
> >
> > > Signed-off-by: Julian Anastasov <ja@ssi.bg>
> >
> > Acked-by: Hans Schillstrom <hans@schillstrom.com>
>
>
> Thanks guys, I have queued up the following in the ipvs tree
> along with the rest of this series.
Bother, I messed up the commit-id in the changelog.
The corrected version, which I will queue up, is.
From 77f12c00cd6603e93dcb729aa6dc206cb8bb3a46 Mon Sep 17 00:00:00 2001
From: Julian Anastasov <ja@ssi.bg>
Date: Wed, 28 Aug 2013 19:29:36 +0300
Subject: [PATCH] ipvs: stats should not depend on CPU 0
When reading percpu stats we need to properly reset
the sum when CPU 0 is not present in the possible mask.
This problem was introduced by b17fc9963f837ef1
("IPVS: netns, ip_vs_stats and its procfs").
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Hans Schillstrom <hans@schillstrom.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_est.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
index 6bee6d0..1425e9a 100644
--- a/net/netfilter/ipvs/ip_vs_est.c
+++ b/net/netfilter/ipvs/ip_vs_est.c
@@ -59,12 +59,13 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
struct ip_vs_cpu_stats __percpu *stats)
{
int i;
+ bool add = false;
for_each_possible_cpu(i) {
struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
unsigned int start;
__u64 inbytes, outbytes;
- if (i) {
+ if (add) {
sum->conns += s->ustats.conns;
sum->inpkts += s->ustats.inpkts;
sum->outpkts += s->ustats.outpkts;
@@ -76,6 +77,7 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
sum->inbytes += inbytes;
sum->outbytes += outbytes;
} else {
+ add = true;
sum->conns = s->ustats.conns;
sum->inpkts = s->ustats.inpkts;
sum->outpkts = s->ustats.outpkts;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net 4/4] ipvs: stats should not depend on CPU 0
2013-08-30 8:58 ` Simon Horman
@ 2013-08-30 9:53 ` Julian Anastasov
0 siblings, 0 replies; 13+ messages in thread
From: Julian Anastasov @ 2013-08-30 9:53 UTC (permalink / raw)
To: Simon Horman; +Cc: Hans Schillstrom, lvs-devel
Hello,
On Fri, 30 Aug 2013, Simon Horman wrote:
> > > > Can I confirm that this problem was introduced by
> > > > b17fc9963f837ef1 ("IPVS: netns, ip_vs_stats and its procfs")?
> > >
> > > That is correct, I forgot to track the initial
> > > commit, you can freely add such information before
> > > applying.
> Bother, I messed up the commit-id in the changelog.
> The corrected version, which I will queue up, is.
OK, I noticed it too. Later you post pull request
with wrong commit, I hope Pablo will pull a fixed
patch because ipvs-fixes-for-v3.11 still has old commit.
> >From 77f12c00cd6603e93dcb729aa6dc206cb8bb3a46 Mon Sep 17 00:00:00 2001
> From: Julian Anastasov <ja@ssi.bg>
> Date: Wed, 28 Aug 2013 19:29:36 +0300
> Subject: [PATCH] ipvs: stats should not depend on CPU 0
>
> When reading percpu stats we need to properly reset
> the sum when CPU 0 is not present in the possible mask.
>
> This problem was introduced by b17fc9963f837ef1
> ("IPVS: netns, ip_vs_stats and its procfs").
Regards
--
Julian Anastasov <ja@ssi.bg>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 3/4] ipvs: make the service replacement more robust
2013-08-28 16:29 ` [PATCH net 3/4] ipvs: make the service replacement more robust Julian Anastasov
@ 2013-09-10 19:28 ` Julian Anastasov
2013-09-11 3:58 ` Simon Horman
0 siblings, 1 reply; 13+ messages in thread
From: Julian Anastasov @ 2013-09-10 19:28 UTC (permalink / raw)
To: Simon Horman; +Cc: lvs-devel
Hello,
On Wed, 28 Aug 2013, Julian Anastasov wrote:
> - /* Some dest can be in grace period even before cleanup, we have to
> - * defer ip_vs_trash_cleanup until ip_vs_dest_wait_readers is called.
> - */
> - rcu_barrier();
> ip_vs_trash_cleanup(net);
> ip_vs_stop_estimator(net, &ipvs->tot_stats);
> ip_vs_control_net_cleanup_sysctl(net);
Simon, I have to update this patch. rcu_barrier
can not simply disappear because LBLC[R] use RCU callbacks
and we have to wait them to put the final reference to dest
before calling ip_vs_trash_cleanup(). It needs different
solution, if possible without rcu_barrier. I'll send updated
patchset in next days.
Regards
--
Julian Anastasov <ja@ssi.bg>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 3/4] ipvs: make the service replacement more robust
2013-09-10 19:28 ` Julian Anastasov
@ 2013-09-11 3:58 ` Simon Horman
0 siblings, 0 replies; 13+ messages in thread
From: Simon Horman @ 2013-09-11 3:58 UTC (permalink / raw)
To: Julian Anastasov; +Cc: lvs-devel
On Tue, Sep 10, 2013 at 10:28:13PM +0300, Julian Anastasov wrote:
>
> Hello,
>
> On Wed, 28 Aug 2013, Julian Anastasov wrote:
>
> > - /* Some dest can be in grace period even before cleanup, we have to
> > - * defer ip_vs_trash_cleanup until ip_vs_dest_wait_readers is called.
> > - */
> > - rcu_barrier();
> > ip_vs_trash_cleanup(net);
> > ip_vs_stop_estimator(net, &ipvs->tot_stats);
> > ip_vs_control_net_cleanup_sysctl(net);
>
> Simon, I have to update this patch. rcu_barrier
> can not simply disappear because LBLC[R] use RCU callbacks
> and we have to wait them to put the final reference to dest
> before calling ip_vs_trash_cleanup(). It needs different
> solution, if possible without rcu_barrier. I'll send updated
> patchset in next days.
Thanks, noted.
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2013-09-11 3:58 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-28 16:29 [PATCH net 0/4] IPVS fixes for corner cases Julian Anastasov
2013-08-28 16:29 ` [PATCH net 1/4] ipvs: do not use dest after ip_vs_dest_put in LBLC Julian Anastasov
2013-08-28 16:29 ` [PATCH net 2/4] ipvs: do not use dest after ip_vs_dest_put in LBLCR Julian Anastasov
2013-08-28 16:29 ` [PATCH net 3/4] ipvs: make the service replacement more robust Julian Anastasov
2013-09-10 19:28 ` Julian Anastasov
2013-09-11 3:58 ` Simon Horman
2013-08-28 16:29 ` [PATCH net 4/4] ipvs: stats should not depend on CPU 0 Julian Anastasov
2013-08-30 1:17 ` Simon Horman
2013-08-30 7:31 ` Julian Anastasov
2013-08-30 8:53 ` Simon Horman
2013-08-30 8:58 ` Simon Horman
2013-08-30 9:53 ` Julian Anastasov
2013-08-30 7:46 ` Hans Schillstrom
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.