[IPVS]: Fix sched registration race when checking for name collision.
The register_ip_vs_scheduler() checks for the scheduler with the same name under the read-locked __ip_vs_sched_lock, then drops, takes it for writing and puts the scheduler in list. This is racy, since we can have a race window between the lock being re-locked for writing. The fix is to search the scheduler with the given name right under the write-locked __ip_vs_sched_lock. Signed-off-by: Pavel Emelyanov <xemul@openvz.org> Acked-by: Simon Horman <horms@verge.net.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a014bc8f0f
commit
4ac63ad6c5
1 changed files with 14 additions and 13 deletions
|
@ -183,19 +183,6 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
|
||||||
/* increase the module use count */
|
/* increase the module use count */
|
||||||
ip_vs_use_count_inc();
|
ip_vs_use_count_inc();
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure that the scheduler with this name doesn't exist
|
|
||||||
* in the scheduler list.
|
|
||||||
*/
|
|
||||||
sched = ip_vs_sched_getbyname(scheduler->name);
|
|
||||||
if (sched) {
|
|
||||||
ip_vs_scheduler_put(sched);
|
|
||||||
ip_vs_use_count_dec();
|
|
||||||
IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
|
|
||||||
"already existed in the system\n", scheduler->name);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
write_lock_bh(&__ip_vs_sched_lock);
|
write_lock_bh(&__ip_vs_sched_lock);
|
||||||
|
|
||||||
if (scheduler->n_list.next != &scheduler->n_list) {
|
if (scheduler->n_list.next != &scheduler->n_list) {
|
||||||
|
@ -206,6 +193,20 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure that the scheduler with this name doesn't exist
|
||||||
|
* in the scheduler list.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
|
||||||
|
if (strcmp(scheduler->name, sched->name) == 0) {
|
||||||
|
write_unlock_bh(&__ip_vs_sched_lock);
|
||||||
|
ip_vs_use_count_dec();
|
||||||
|
IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
|
||||||
|
"already existed in the system\n",
|
||||||
|
scheduler->name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Add it into the d-linked scheduler list
|
* Add it into the d-linked scheduler list
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue