|
@@ -842,15 +842,16 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
|
|
__ip_vs_dst_cache_reset(dest);
|
|
__ip_vs_dst_cache_reset(dest);
|
|
spin_unlock_bh(&dest->dst_lock);
|
|
spin_unlock_bh(&dest->dst_lock);
|
|
|
|
|
|
- sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
|
|
if (add) {
|
|
if (add) {
|
|
ip_vs_start_estimator(svc->net, &dest->stats);
|
|
ip_vs_start_estimator(svc->net, &dest->stats);
|
|
list_add_rcu(&dest->n_list, &svc->destinations);
|
|
list_add_rcu(&dest->n_list, &svc->destinations);
|
|
svc->num_dests++;
|
|
svc->num_dests++;
|
|
- if (sched->add_dest)
|
|
|
|
|
|
+ sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
|
|
+ if (sched && sched->add_dest)
|
|
sched->add_dest(svc, dest);
|
|
sched->add_dest(svc, dest);
|
|
} else {
|
|
} else {
|
|
- if (sched->upd_dest)
|
|
|
|
|
|
+ sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
|
|
+ if (sched && sched->upd_dest)
|
|
sched->upd_dest(svc, dest);
|
|
sched->upd_dest(svc, dest);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1084,7 +1085,7 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
|
|
struct ip_vs_scheduler *sched;
|
|
struct ip_vs_scheduler *sched;
|
|
|
|
|
|
sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
- if (sched->del_dest)
|
|
|
|
|
|
+ if (sched && sched->del_dest)
|
|
sched->del_dest(svc, dest);
|
|
sched->del_dest(svc, dest);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1175,11 +1176,14 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
|
|
ip_vs_use_count_inc();
|
|
ip_vs_use_count_inc();
|
|
|
|
|
|
/* Lookup the scheduler by 'u->sched_name' */
|
|
/* Lookup the scheduler by 'u->sched_name' */
|
|
- sched = ip_vs_scheduler_get(u->sched_name);
|
|
|
|
- if (sched == NULL) {
|
|
|
|
- pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
|
|
|
|
- ret = -ENOENT;
|
|
|
|
- goto out_err;
|
|
|
|
|
|
+ if (strcmp(u->sched_name, "none")) {
|
|
|
|
+ sched = ip_vs_scheduler_get(u->sched_name);
|
|
|
|
+ if (!sched) {
|
|
|
|
+ pr_info("Scheduler module ip_vs_%s not found\n",
|
|
|
|
+ u->sched_name);
|
|
|
|
+ ret = -ENOENT;
|
|
|
|
+ goto out_err;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if (u->pe_name && *u->pe_name) {
|
|
if (u->pe_name && *u->pe_name) {
|
|
@@ -1240,10 +1244,12 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
|
|
spin_lock_init(&svc->stats.lock);
|
|
spin_lock_init(&svc->stats.lock);
|
|
|
|
|
|
/* Bind the scheduler */
|
|
/* Bind the scheduler */
|
|
- ret = ip_vs_bind_scheduler(svc, sched);
|
|
|
|
- if (ret)
|
|
|
|
- goto out_err;
|
|
|
|
- sched = NULL;
|
|
|
|
|
|
+ if (sched) {
|
|
|
|
+ ret = ip_vs_bind_scheduler(svc, sched);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto out_err;
|
|
|
|
+ sched = NULL;
|
|
|
|
+ }
|
|
|
|
|
|
/* Bind the ct retriever */
|
|
/* Bind the ct retriever */
|
|
RCU_INIT_POINTER(svc->pe, pe);
|
|
RCU_INIT_POINTER(svc->pe, pe);
|
|
@@ -1291,17 +1297,20 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
|
|
static int
|
|
static int
|
|
ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
|
|
ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
|
|
{
|
|
{
|
|
- struct ip_vs_scheduler *sched, *old_sched;
|
|
|
|
|
|
+ struct ip_vs_scheduler *sched = NULL, *old_sched;
|
|
struct ip_vs_pe *pe = NULL, *old_pe = NULL;
|
|
struct ip_vs_pe *pe = NULL, *old_pe = NULL;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Lookup the scheduler, by 'u->sched_name'
|
|
* Lookup the scheduler, by 'u->sched_name'
|
|
*/
|
|
*/
|
|
- sched = ip_vs_scheduler_get(u->sched_name);
|
|
|
|
- if (sched == NULL) {
|
|
|
|
- pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
|
|
|
|
- return -ENOENT;
|
|
|
|
|
|
+ if (strcmp(u->sched_name, "none")) {
|
|
|
|
+ sched = ip_vs_scheduler_get(u->sched_name);
|
|
|
|
+ if (!sched) {
|
|
|
|
+ pr_info("Scheduler module ip_vs_%s not found\n",
|
|
|
|
+ u->sched_name);
|
|
|
|
+ return -ENOENT;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
old_sched = sched;
|
|
old_sched = sched;
|
|
|
|
|
|
@@ -1329,14 +1338,20 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
|
|
|
|
|
|
old_sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
old_sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
if (sched != old_sched) {
|
|
if (sched != old_sched) {
|
|
|
|
+ if (old_sched) {
|
|
|
|
+ ip_vs_unbind_scheduler(svc, old_sched);
|
|
|
|
+ RCU_INIT_POINTER(svc->scheduler, NULL);
|
|
|
|
+ /* Wait all svc->sched_data users */
|
|
|
|
+ synchronize_rcu();
|
|
|
|
+ }
|
|
/* Bind the new scheduler */
|
|
/* Bind the new scheduler */
|
|
- ret = ip_vs_bind_scheduler(svc, sched);
|
|
|
|
- if (ret) {
|
|
|
|
- old_sched = sched;
|
|
|
|
- goto out;
|
|
|
|
|
|
+ if (sched) {
|
|
|
|
+ ret = ip_vs_bind_scheduler(svc, sched);
|
|
|
|
+ if (ret) {
|
|
|
|
+ ip_vs_scheduler_put(sched);
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- /* Unbind the old scheduler on success */
|
|
|
|
- ip_vs_unbind_scheduler(svc, old_sched);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1982,6 +1997,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
|
|
const struct ip_vs_iter *iter = seq->private;
|
|
const struct ip_vs_iter *iter = seq->private;
|
|
const struct ip_vs_dest *dest;
|
|
const struct ip_vs_dest *dest;
|
|
struct ip_vs_scheduler *sched = rcu_dereference(svc->scheduler);
|
|
struct ip_vs_scheduler *sched = rcu_dereference(svc->scheduler);
|
|
|
|
+ char *sched_name = sched ? sched->name : "none";
|
|
|
|
|
|
if (iter->table == ip_vs_svc_table) {
|
|
if (iter->table == ip_vs_svc_table) {
|
|
#ifdef CONFIG_IP_VS_IPV6
|
|
#ifdef CONFIG_IP_VS_IPV6
|
|
@@ -1990,18 +2006,18 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
|
|
ip_vs_proto_name(svc->protocol),
|
|
ip_vs_proto_name(svc->protocol),
|
|
&svc->addr.in6,
|
|
&svc->addr.in6,
|
|
ntohs(svc->port),
|
|
ntohs(svc->port),
|
|
- sched->name);
|
|
|
|
|
|
+ sched_name);
|
|
else
|
|
else
|
|
#endif
|
|
#endif
|
|
seq_printf(seq, "%s %08X:%04X %s %s ",
|
|
seq_printf(seq, "%s %08X:%04X %s %s ",
|
|
ip_vs_proto_name(svc->protocol),
|
|
ip_vs_proto_name(svc->protocol),
|
|
ntohl(svc->addr.ip),
|
|
ntohl(svc->addr.ip),
|
|
ntohs(svc->port),
|
|
ntohs(svc->port),
|
|
- sched->name,
|
|
|
|
|
|
+ sched_name,
|
|
(svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
|
|
(svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
|
|
} else {
|
|
} else {
|
|
seq_printf(seq, "FWM %08X %s %s",
|
|
seq_printf(seq, "FWM %08X %s %s",
|
|
- svc->fwmark, sched->name,
|
|
|
|
|
|
+ svc->fwmark, sched_name,
|
|
(svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
|
|
(svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2427,13 +2443,15 @@ ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
|
|
{
|
|
{
|
|
struct ip_vs_scheduler *sched;
|
|
struct ip_vs_scheduler *sched;
|
|
struct ip_vs_kstats kstats;
|
|
struct ip_vs_kstats kstats;
|
|
|
|
+ char *sched_name;
|
|
|
|
|
|
sched = rcu_dereference_protected(src->scheduler, 1);
|
|
sched = rcu_dereference_protected(src->scheduler, 1);
|
|
|
|
+ sched_name = sched ? sched->name : "none";
|
|
dst->protocol = src->protocol;
|
|
dst->protocol = src->protocol;
|
|
dst->addr = src->addr.ip;
|
|
dst->addr = src->addr.ip;
|
|
dst->port = src->port;
|
|
dst->port = src->port;
|
|
dst->fwmark = src->fwmark;
|
|
dst->fwmark = src->fwmark;
|
|
- strlcpy(dst->sched_name, sched->name, sizeof(dst->sched_name));
|
|
|
|
|
|
+ strlcpy(dst->sched_name, sched_name, sizeof(dst->sched_name));
|
|
dst->flags = src->flags;
|
|
dst->flags = src->flags;
|
|
dst->timeout = src->timeout / HZ;
|
|
dst->timeout = src->timeout / HZ;
|
|
dst->netmask = src->netmask;
|
|
dst->netmask = src->netmask;
|
|
@@ -2892,6 +2910,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
|
|
struct ip_vs_flags flags = { .flags = svc->flags,
|
|
struct ip_vs_flags flags = { .flags = svc->flags,
|
|
.mask = ~0 };
|
|
.mask = ~0 };
|
|
struct ip_vs_kstats kstats;
|
|
struct ip_vs_kstats kstats;
|
|
|
|
+ char *sched_name;
|
|
|
|
|
|
nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE);
|
|
nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE);
|
|
if (!nl_service)
|
|
if (!nl_service)
|
|
@@ -2910,8 +2929,9 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
|
|
}
|
|
}
|
|
|
|
|
|
sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
sched = rcu_dereference_protected(svc->scheduler, 1);
|
|
|
|
+ sched_name = sched ? sched->name : "none";
|
|
pe = rcu_dereference_protected(svc->pe, 1);
|
|
pe = rcu_dereference_protected(svc->pe, 1);
|
|
- if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, sched->name) ||
|
|
|
|
|
|
+ if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, sched_name) ||
|
|
(pe && nla_put_string(skb, IPVS_SVC_ATTR_PE_NAME, pe->name)) ||
|
|
(pe && nla_put_string(skb, IPVS_SVC_ATTR_PE_NAME, pe->name)) ||
|
|
nla_put(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags) ||
|
|
nla_put(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags) ||
|
|
nla_put_u32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ) ||
|
|
nla_put_u32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ) ||
|