diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 13:16:31 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 16:07:42 -0400 |
commit | ecdbf769b2cb8903e07cd482334c714d89fd1146 (patch) | |
tree | 9d02ce4daee662c2711762564662cebc521e3da3 /fs/lockd/clntproc.c | |
parent | 4f15e2b1f4f3a56e46201714b39436c32218d547 (diff) |
[PATCH] NLM: fix a client-side race on blocking locks.
If the lock blocks, the server may send us a GRANTED message that
races with the reply to our LOCK request. Make sure that we catch
the GRANTED by queueing up our request on the nlm_blocked list
before we send off the first LOCK rpc call.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/lockd/clntproc.c')
-rw-r--r-- | fs/lockd/clntproc.c | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index a4407619b1f1..fd77ed1d710d 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #define NLMDBG_FACILITY NLMDBG_CLIENT | 22 | #define NLMDBG_FACILITY NLMDBG_CLIENT |
23 | #define NLMCLNT_GRACE_WAIT (5*HZ) | 23 | #define NLMCLNT_GRACE_WAIT (5*HZ) |
24 | #define NLMCLNT_POLL_TIMEOUT (30*HZ) | ||
24 | 25 | ||
25 | static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); | 26 | static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); |
26 | static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); | 27 | static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); |
@@ -553,7 +554,8 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
553 | { | 554 | { |
554 | struct nlm_host *host = req->a_host; | 555 | struct nlm_host *host = req->a_host; |
555 | struct nlm_res *resp = &req->a_res; | 556 | struct nlm_res *resp = &req->a_res; |
556 | int status; | 557 | long timeout; |
558 | int status; | ||
557 | 559 | ||
558 | if (!host->h_monitored && nsm_monitor(host) < 0) { | 560 | if (!host->h_monitored && nsm_monitor(host) < 0) { |
559 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", | 561 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", |
@@ -562,15 +564,32 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
562 | goto out; | 564 | goto out; |
563 | } | 565 | } |
564 | 566 | ||
565 | do { | 567 | if (req->a_args.block) { |
566 | if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) { | 568 | status = nlmclnt_prepare_block(req, host, fl); |
567 | if (resp->status != NLM_LCK_BLOCKED) | ||
568 | break; | ||
569 | status = nlmclnt_block(host, fl, &resp->status); | ||
570 | } | ||
571 | if (status < 0) | 569 | if (status < 0) |
572 | goto out; | 570 | goto out; |
573 | } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); | 571 | } |
572 | for(;;) { | ||
573 | status = nlmclnt_call(req, NLMPROC_LOCK); | ||
574 | if (status < 0) | ||
575 | goto out_unblock; | ||
576 | if (resp->status != NLM_LCK_BLOCKED) | ||
577 | break; | ||
578 | /* Wait on an NLM blocking lock */ | ||
579 | timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT); | ||
580 | /* Did a reclaimer thread notify us of a server reboot? */ | ||
581 | if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) | ||
582 | continue; | ||
583 | if (resp->status != NLM_LCK_BLOCKED) | ||
584 | break; | ||
585 | if (timeout >= 0) | ||
586 | continue; | ||
587 | /* We were interrupted. Send a CANCEL request to the server | ||
588 | * and exit | ||
589 | */ | ||
590 | status = (int)timeout; | ||
591 | goto out_unblock; | ||
592 | } | ||
574 | 593 | ||
575 | if (resp->status == NLM_LCK_GRANTED) { | 594 | if (resp->status == NLM_LCK_GRANTED) { |
576 | fl->fl_u.nfs_fl.state = host->h_state; | 595 | fl->fl_u.nfs_fl.state = host->h_state; |
@@ -579,6 +598,11 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
579 | do_vfs_lock(fl); | 598 | do_vfs_lock(fl); |
580 | } | 599 | } |
581 | status = nlm_stat_to_errno(resp->status); | 600 | status = nlm_stat_to_errno(resp->status); |
601 | out_unblock: | ||
602 | nlmclnt_finish_block(req); | ||
603 | /* Cancel the blocked request if it is still pending */ | ||
604 | if (resp->status == NLM_LCK_BLOCKED) | ||
605 | nlmclnt_cancel(host, fl); | ||
582 | out: | 606 | out: |
583 | nlmclnt_release_lockargs(req); | 607 | nlmclnt_release_lockargs(req); |
584 | return status; | 608 | return status; |