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