Commit 4ac63ad6c52e9cdefbcb54ec4575ab12b78b49d9
Committed by
David S. Miller
1 parent
a014bc8f0f
Exists in
master
and in
7 other branches
[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>
Showing 1 changed file with 14 additions and 13 deletions Side-by-side Diff
net/ipv4/ipvs/ip_vs_sched.c
... | ... | @@ -183,19 +183,6 @@ |
183 | 183 | /* increase the module use count */ |
184 | 184 | ip_vs_use_count_inc(); |
185 | 185 | |
186 | - /* | |
187 | - * Make sure that the scheduler with this name doesn't exist | |
188 | - * in the scheduler list. | |
189 | - */ | |
190 | - sched = ip_vs_sched_getbyname(scheduler->name); | |
191 | - if (sched) { | |
192 | - ip_vs_scheduler_put(sched); | |
193 | - ip_vs_use_count_dec(); | |
194 | - IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler " | |
195 | - "already existed in the system\n", scheduler->name); | |
196 | - return -EINVAL; | |
197 | - } | |
198 | - | |
199 | 186 | write_lock_bh(&__ip_vs_sched_lock); |
200 | 187 | |
201 | 188 | if (scheduler->n_list.next != &scheduler->n_list) { |
... | ... | @@ -206,6 +193,20 @@ |
206 | 193 | return -EINVAL; |
207 | 194 | } |
208 | 195 | |
196 | + /* | |
197 | + * Make sure that the scheduler with this name doesn't exist | |
198 | + * in the scheduler list. | |
199 | + */ | |
200 | + list_for_each_entry(sched, &ip_vs_schedulers, n_list) { | |
201 | + if (strcmp(scheduler->name, sched->name) == 0) { | |
202 | + write_unlock_bh(&__ip_vs_sched_lock); | |
203 | + ip_vs_use_count_dec(); | |
204 | + IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler " | |
205 | + "already existed in the system\n", | |
206 | + scheduler->name); | |
207 | + return -EINVAL; | |
208 | + } | |
209 | + } | |
209 | 210 | /* |
210 | 211 | * Add it into the d-linked scheduler list |
211 | 212 | */ |