If del_dest returns non-zero, restore flags and the counts in services and
ipvs and leave things as they were.
Signed-off-by: Alex Gartrell <agartrell@xxxxxx>
---
net/netfilter/ipvs/ip_vs_ctl.c | 42 +++++++++++++++++++++++++-----------------
1 file changed, 25 insertions(+), 17 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index d384b7f..2e9deb4 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1068,10 +1068,13 @@ static void __ip_vs_del_dest(struct net *net, struct
ip_vs_dest *dest,
/*
* Unlink a destination from the given service
*/
-static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
- struct ip_vs_dest *dest,
- int svcupd)
+static int __ip_vs_unlink_dest(struct ip_vs_service *svc,
+ struct ip_vs_dest *dest,
+ int svcupd)
{
+ int ret = 0;
+ int old_flags = dest->flags;
+
dest->flags &= ~IP_VS_DEST_F_AVAILABLE;
/*
@@ -1080,16 +1083,25 @@ static void __ip_vs_unlink_dest(struct ip_vs_service
*svc,
list_del_rcu(&dest->n_list);
svc->num_dests--;
- if (dest->af != svc->af)
- net_ipvs(svc->net)->mixed_address_family_dests--;
if (svcupd) {
struct ip_vs_scheduler *sched;
sched = rcu_dereference_protected(svc->scheduler, 1);
- if (sched->del_dest)
- sched->del_dest(svc, dest);
+ if (sched->del_dest) {
+ ret = sched->del_dest(svc, dest);
+ if (ret) {
+ list_add_rcu(&dest->n_list, &svc->destinations);
+ dest->flags = old_flags;
+ svc->num_dests++;
+ }
+ }
}
+
+ if (!ret && dest->af != svc->af)
+ net_ipvs(svc->net)->mixed_address_family_dests--;
+
+ return ret;
}
@@ -1101,6 +1113,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct
ip_vs_dest_user_kern *udest)
{
struct ip_vs_dest *dest;
__be16 dport = udest->port;
+ int ret;
EnterFunction(2);
@@ -1114,19 +1127,14 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct
ip_vs_dest_user_kern *udest)
return -ENOENT;
}
- /*
- * Unlink dest from the service
- */
- __ip_vs_unlink_dest(svc, dest, 1);
-
- /*
- * Delete the destination
- */
- __ip_vs_del_dest(svc->net, dest, false);
+ /* First unlink, and then delete if the unlink worked */
+ ret = __ip_vs_unlink_dest(svc, dest, 1);
+ if (!ret)
+ __ip_vs_del_dest(svc->net, dest, false);
LeaveFunction(2);
- return 0;
+ return ret;
}
static void ip_vs_dest_trash_expire(unsigned long data)
--
Alex Gartrell <agartrell@xxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
|