diff options
| author | Jeff Layton <jlayton@redhat.com> | 2008-06-11 10:03:12 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2008-06-23 13:02:50 -0400 |
| commit | abd1ec4efd82ca06127bce833ad8a4bbec8a0dcb (patch) | |
| tree | 4a740d45b37a8b6e034ebf7b7a5a325af0b1ec52 | |
| parent | a75c5d01e4235a7dd785548ac756f248b1b40107 (diff) | |
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>
| -rw-r--r-- | fs/lockd/svc.c | 33 |
1 files changed, 13 insertions, 20 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 2169af4d5455..5bd9bf0fa9df 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
| @@ -50,7 +50,7 @@ EXPORT_SYMBOL(nlmsvc_ops); | |||
| 50 | static DEFINE_MUTEX(nlmsvc_mutex); | 50 | static DEFINE_MUTEX(nlmsvc_mutex); |
| 51 | static unsigned int nlmsvc_users; | 51 | static unsigned int nlmsvc_users; |
| 52 | static struct task_struct *nlmsvc_task; | 52 | static struct task_struct *nlmsvc_task; |
| 53 | static struct svc_serv *nlmsvc_serv; | 53 | static struct svc_rqst *nlmsvc_rqst; |
| 54 | int nlmsvc_grace_period; | 54 | int nlmsvc_grace_period; |
| 55 | unsigned long nlmsvc_timeout; | 55 | unsigned long nlmsvc_timeout; |
| 56 | 56 | ||
| @@ -194,20 +194,11 @@ lockd(void *vrqstp) | |||
| 194 | 194 | ||
| 195 | svc_process(rqstp); | 195 | svc_process(rqstp); |
| 196 | } | 196 | } |
| 197 | |||
| 198 | flush_signals(current); | 197 | flush_signals(current); |
| 199 | if (nlmsvc_ops) | 198 | if (nlmsvc_ops) |
| 200 | nlmsvc_invalidate_all(); | 199 | nlmsvc_invalidate_all(); |
| 201 | nlm_shutdown_hosts(); | 200 | nlm_shutdown_hosts(); |
| 202 | |||
| 203 | unlock_kernel(); | 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 | return 0; | 202 | return 0; |
| 212 | } | 203 | } |
| 213 | 204 | ||
| @@ -254,16 +245,15 @@ int | |||
| 254 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | 245 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ |
| 255 | { | 246 | { |
| 256 | struct svc_serv *serv; | 247 | struct svc_serv *serv; |
| 257 | struct svc_rqst *rqstp; | ||
| 258 | int error = 0; | 248 | int error = 0; |
| 259 | 249 | ||
| 260 | mutex_lock(&nlmsvc_mutex); | 250 | mutex_lock(&nlmsvc_mutex); |
| 261 | /* | 251 | /* |
| 262 | * Check whether we're already up and running. | 252 | * Check whether we're already up and running. |
| 263 | */ | 253 | */ |
| 264 | if (nlmsvc_serv) { | 254 | if (nlmsvc_rqst) { |
| 265 | if (proto) | 255 | if (proto) |
| 266 | error = make_socks(nlmsvc_serv, proto); | 256 | error = make_socks(nlmsvc_rqst->rq_server, proto); |
| 267 | goto out; | 257 | goto out; |
| 268 | } | 258 | } |
| 269 | 259 | ||
| @@ -288,9 +278,10 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | |||
| 288 | /* | 278 | /* |
| 289 | * Create the kernel thread and wait for it to start. | 279 | * Create the kernel thread and wait for it to start. |
| 290 | */ | 280 | */ |
| 291 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | 281 | nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); |
| 292 | if (IS_ERR(rqstp)) { | 282 | if (IS_ERR(nlmsvc_rqst)) { |
| 293 | error = PTR_ERR(rqstp); | 283 | error = PTR_ERR(nlmsvc_rqst); |
| 284 | nlmsvc_rqst = NULL; | ||
| 294 | printk(KERN_WARNING | 285 | printk(KERN_WARNING |
| 295 | "lockd_up: svc_rqst allocation failed, error=%d\n", | 286 | "lockd_up: svc_rqst allocation failed, error=%d\n", |
| 296 | error); | 287 | error); |
| @@ -298,16 +289,15 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | |||
| 298 | } | 289 | } |
| 299 | 290 | ||
| 300 | svc_sock_update_bufs(serv); | 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 | if (IS_ERR(nlmsvc_task)) { | 294 | if (IS_ERR(nlmsvc_task)) { |
| 305 | error = PTR_ERR(nlmsvc_task); | 295 | error = PTR_ERR(nlmsvc_task); |
| 296 | svc_exit_thread(nlmsvc_rqst); | ||
| 306 | nlmsvc_task = NULL; | 297 | nlmsvc_task = NULL; |
| 307 | nlmsvc_serv = NULL; | 298 | nlmsvc_rqst = NULL; |
| 308 | printk(KERN_WARNING | 299 | printk(KERN_WARNING |
| 309 | "lockd_up: kthread_run failed, error=%d\n", error); | 300 | "lockd_up: kthread_run failed, error=%d\n", error); |
| 310 | svc_exit_thread(rqstp); | ||
| 311 | goto destroy_and_out; | 301 | goto destroy_and_out; |
| 312 | } | 302 | } |
| 313 | 303 | ||
| @@ -346,6 +336,9 @@ lockd_down(void) | |||
| 346 | BUG(); | 336 | BUG(); |
| 347 | } | 337 | } |
| 348 | kthread_stop(nlmsvc_task); | 338 | kthread_stop(nlmsvc_task); |
| 339 | svc_exit_thread(nlmsvc_rqst); | ||
| 340 | nlmsvc_task = NULL; | ||
| 341 | nlmsvc_rqst = NULL; | ||
| 349 | out: | 342 | out: |
| 350 | mutex_unlock(&nlmsvc_mutex); | 343 | mutex_unlock(&nlmsvc_mutex); |
| 351 | } | 344 | } |
