All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.