Commit abd1ec4efd82ca06127bce833ad8a4bbec8a0dcb
Committed by
J. Bruce Fields
1 parent
a75c5d01e4
Exists in
master
and in
7 other branches
lockd: close potential race with rapid lockd_up/lockd_down cycle
If lockd_down is called very rapidly after lockd_up returns, then there is a slim chance that lockd() will never be called. kthread() will return before calling the function, so we'll end up never actually calling the cleanup functions for the thread. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Showing 1 changed file with 13 additions and 20 deletions Side-by-side Diff
fs/lockd/svc.c
... | ... | @@ -50,7 +50,7 @@ |
50 | 50 | static DEFINE_MUTEX(nlmsvc_mutex); |
51 | 51 | static unsigned int nlmsvc_users; |
52 | 52 | static struct task_struct *nlmsvc_task; |
53 | -static struct svc_serv *nlmsvc_serv; | |
53 | +static struct svc_rqst *nlmsvc_rqst; | |
54 | 54 | int nlmsvc_grace_period; |
55 | 55 | unsigned long nlmsvc_timeout; |
56 | 56 | |
57 | 57 | |
58 | 58 | |
... | ... | @@ -194,20 +194,11 @@ |
194 | 194 | |
195 | 195 | svc_process(rqstp); |
196 | 196 | } |
197 | - | |
198 | 197 | flush_signals(current); |
199 | 198 | if (nlmsvc_ops) |
200 | 199 | nlmsvc_invalidate_all(); |
201 | 200 | nlm_shutdown_hosts(); |
202 | - | |
203 | 201 | unlock_kernel(); |
204 | - | |
205 | - nlmsvc_task = NULL; | |
206 | - nlmsvc_serv = NULL; | |
207 | - | |
208 | - /* Exit the RPC thread */ | |
209 | - svc_exit_thread(rqstp); | |
210 | - | |
211 | 202 | return 0; |
212 | 203 | } |
213 | 204 | |
214 | 205 | |
215 | 206 | |
... | ... | @@ -254,16 +245,15 @@ |
254 | 245 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ |
255 | 246 | { |
256 | 247 | struct svc_serv *serv; |
257 | - struct svc_rqst *rqstp; | |
258 | 248 | int error = 0; |
259 | 249 | |
260 | 250 | mutex_lock(&nlmsvc_mutex); |
261 | 251 | /* |
262 | 252 | * Check whether we're already up and running. |
263 | 253 | */ |
264 | - if (nlmsvc_serv) { | |
254 | + if (nlmsvc_rqst) { | |
265 | 255 | if (proto) |
266 | - error = make_socks(nlmsvc_serv, proto); | |
256 | + error = make_socks(nlmsvc_rqst->rq_server, proto); | |
267 | 257 | goto out; |
268 | 258 | } |
269 | 259 | |
... | ... | @@ -288,9 +278,10 @@ |
288 | 278 | /* |
289 | 279 | * Create the kernel thread and wait for it to start. |
290 | 280 | */ |
291 | - rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | |
292 | - if (IS_ERR(rqstp)) { | |
293 | - error = PTR_ERR(rqstp); | |
281 | + nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); | |
282 | + if (IS_ERR(nlmsvc_rqst)) { | |
283 | + error = PTR_ERR(nlmsvc_rqst); | |
284 | + nlmsvc_rqst = NULL; | |
294 | 285 | printk(KERN_WARNING |
295 | 286 | "lockd_up: svc_rqst allocation failed, error=%d\n", |
296 | 287 | error); |
297 | 288 | |
298 | 289 | |
299 | 290 | |
300 | 291 | |
... | ... | @@ -298,16 +289,15 @@ |
298 | 289 | } |
299 | 290 | |
300 | 291 | svc_sock_update_bufs(serv); |
301 | - nlmsvc_serv = rqstp->rq_server; | |
302 | 292 | |
303 | - nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name); | |
293 | + nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name); | |
304 | 294 | if (IS_ERR(nlmsvc_task)) { |
305 | 295 | error = PTR_ERR(nlmsvc_task); |
296 | + svc_exit_thread(nlmsvc_rqst); | |
306 | 297 | nlmsvc_task = NULL; |
307 | - nlmsvc_serv = NULL; | |
298 | + nlmsvc_rqst = NULL; | |
308 | 299 | printk(KERN_WARNING |
309 | 300 | "lockd_up: kthread_run failed, error=%d\n", error); |
310 | - svc_exit_thread(rqstp); | |
311 | 301 | goto destroy_and_out; |
312 | 302 | } |
313 | 303 | |
... | ... | @@ -346,6 +336,9 @@ |
346 | 336 | BUG(); |
347 | 337 | } |
348 | 338 | kthread_stop(nlmsvc_task); |
339 | + svc_exit_thread(nlmsvc_rqst); | |
340 | + nlmsvc_task = NULL; | |
341 | + nlmsvc_rqst = NULL; | |
349 | 342 | out: |
350 | 343 | mutex_unlock(&nlmsvc_mutex); |
351 | 344 | } |