diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-06-09 09:40:27 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-06-09 09:40:27 -0400 |
commit | 28df955a2ad484d602314b30183ea8496a9aa34a (patch) | |
tree | c62632b2a0a49df114283f10764244c1b1b5f506 /fs/lockd/clntproc.c | |
parent | 5046791417dcac1ba126b77b8062af15a2f0b8e1 (diff) |
NLM: Fix reclaim races
Currently it is possible for a task to remove its locks at the same time as
the NLM recovery thread is trying to recover them. This quickly leads to an
Oops.
Protect the locks using an rw semaphore while they are being recovered.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/lockd/clntproc.c')
-rw-r--r-- | fs/lockd/clntproc.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index f96e38155b5c..4db62098d3f4 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -508,7 +508,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
508 | } | 508 | } |
509 | 509 | ||
510 | block = nlmclnt_prepare_block(host, fl); | 510 | block = nlmclnt_prepare_block(host, fl); |
511 | again: | ||
511 | for(;;) { | 512 | for(;;) { |
513 | /* Reboot protection */ | ||
514 | fl->fl_u.nfs_fl.state = host->h_state; | ||
512 | status = nlmclnt_call(req, NLMPROC_LOCK); | 515 | status = nlmclnt_call(req, NLMPROC_LOCK); |
513 | if (status < 0) | 516 | if (status < 0) |
514 | goto out_unblock; | 517 | goto out_unblock; |
@@ -531,10 +534,16 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
531 | } | 534 | } |
532 | 535 | ||
533 | if (resp->status == NLM_LCK_GRANTED) { | 536 | if (resp->status == NLM_LCK_GRANTED) { |
534 | fl->fl_u.nfs_fl.state = host->h_state; | 537 | down_read(&host->h_rwsem); |
538 | /* Check whether or not the server has rebooted */ | ||
539 | if (fl->fl_u.nfs_fl.state != host->h_state) { | ||
540 | up_read(&host->h_rwsem); | ||
541 | goto again; | ||
542 | } | ||
535 | fl->fl_flags |= FL_SLEEP; | 543 | fl->fl_flags |= FL_SLEEP; |
536 | /* Ensure the resulting lock will get added to granted list */ | 544 | /* Ensure the resulting lock will get added to granted list */ |
537 | do_vfs_lock(fl); | 545 | do_vfs_lock(fl); |
546 | up_read(&host->h_rwsem); | ||
538 | } | 547 | } |
539 | status = nlm_stat_to_errno(resp->status); | 548 | status = nlm_stat_to_errno(resp->status); |
540 | out_unblock: | 549 | out_unblock: |
@@ -596,6 +605,7 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl) | |||
596 | static int | 605 | static int |
597 | nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | 606 | nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) |
598 | { | 607 | { |
608 | struct nlm_host *host = req->a_host; | ||
599 | struct nlm_res *resp = &req->a_res; | 609 | struct nlm_res *resp = &req->a_res; |
600 | int status; | 610 | int status; |
601 | 611 | ||
@@ -604,7 +614,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
604 | * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either | 614 | * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either |
605 | * case, we want to unlock. | 615 | * case, we want to unlock. |
606 | */ | 616 | */ |
617 | down_read(&host->h_rwsem); | ||
607 | do_vfs_lock(fl); | 618 | do_vfs_lock(fl); |
619 | up_read(&host->h_rwsem); | ||
608 | 620 | ||
609 | if (req->a_flags & RPC_TASK_ASYNC) | 621 | if (req->a_flags & RPC_TASK_ASYNC) |
610 | return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | 622 | return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); |