diff options
Diffstat (limited to 'fs/lockd')
-rw-r--r-- | fs/lockd/clntlock.c | 113 | ||||
-rw-r--r-- | fs/lockd/clntproc.c | 40 | ||||
-rw-r--r-- | fs/lockd/host.c | 8 | ||||
-rw-r--r-- | fs/lockd/mon.c | 7 |
4 files changed, 100 insertions, 68 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index ef7103b8c5bd..006bb9e14579 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -31,7 +31,7 @@ static int reclaimer(void *ptr); | |||
31 | * This is the representation of a blocked client lock. | 31 | * This is the representation of a blocked client lock. |
32 | */ | 32 | */ |
33 | struct nlm_wait { | 33 | struct nlm_wait { |
34 | struct nlm_wait * b_next; /* linked list */ | 34 | struct list_head b_list; /* linked list */ |
35 | wait_queue_head_t b_wait; /* where to wait on */ | 35 | wait_queue_head_t b_wait; /* where to wait on */ |
36 | struct nlm_host * b_host; | 36 | struct nlm_host * b_host; |
37 | struct file_lock * b_lock; /* local file lock */ | 37 | struct file_lock * b_lock; /* local file lock */ |
@@ -39,27 +39,54 @@ struct nlm_wait { | |||
39 | u32 b_status; /* grant callback status */ | 39 | u32 b_status; /* grant callback status */ |
40 | }; | 40 | }; |
41 | 41 | ||
42 | static struct nlm_wait * nlm_blocked; | 42 | static LIST_HEAD(nlm_blocked); |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Block on a lock | 45 | * Queue up a lock for blocking so that the GRANTED request can see it |
46 | */ | 46 | */ |
47 | int | 47 | int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl) |
48 | nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | 48 | { |
49 | struct nlm_wait *block; | ||
50 | |||
51 | BUG_ON(req->a_block != NULL); | ||
52 | block = kmalloc(sizeof(*block), GFP_KERNEL); | ||
53 | if (block == NULL) | ||
54 | return -ENOMEM; | ||
55 | block->b_host = host; | ||
56 | block->b_lock = fl; | ||
57 | init_waitqueue_head(&block->b_wait); | ||
58 | block->b_status = NLM_LCK_BLOCKED; | ||
59 | |||
60 | list_add(&block->b_list, &nlm_blocked); | ||
61 | req->a_block = block; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | void nlmclnt_finish_block(struct nlm_rqst *req) | ||
49 | { | 67 | { |
50 | struct nlm_wait block, **head; | 68 | struct nlm_wait *block = req->a_block; |
51 | int err; | ||
52 | u32 pstate; | ||
53 | 69 | ||
54 | block.b_host = host; | 70 | if (block == NULL) |
55 | block.b_lock = fl; | 71 | return; |
56 | init_waitqueue_head(&block.b_wait); | 72 | req->a_block = NULL; |
57 | block.b_status = NLM_LCK_BLOCKED; | 73 | list_del(&block->b_list); |
58 | block.b_next = nlm_blocked; | 74 | kfree(block); |
59 | nlm_blocked = █ | 75 | } |
76 | |||
77 | /* | ||
78 | * Block on a lock | ||
79 | */ | ||
80 | long nlmclnt_block(struct nlm_rqst *req, long timeout) | ||
81 | { | ||
82 | struct nlm_wait *block = req->a_block; | ||
83 | long ret; | ||
60 | 84 | ||
61 | /* Remember pseudo nsm state */ | 85 | /* A borken server might ask us to block even if we didn't |
62 | pstate = host->h_state; | 86 | * request it. Just say no! |
87 | */ | ||
88 | if (!req->a_args.block) | ||
89 | return -EAGAIN; | ||
63 | 90 | ||
64 | /* Go to sleep waiting for GRANT callback. Some servers seem | 91 | /* Go to sleep waiting for GRANT callback. Some servers seem |
65 | * to lose callbacks, however, so we're going to poll from | 92 | * to lose callbacks, however, so we're going to poll from |
@@ -69,28 +96,16 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | |||
69 | * a 1 minute timeout would do. See the comment before | 96 | * a 1 minute timeout would do. See the comment before |
70 | * nlmclnt_lock for an explanation. | 97 | * nlmclnt_lock for an explanation. |
71 | */ | 98 | */ |
72 | sleep_on_timeout(&block.b_wait, 30*HZ); | 99 | ret = wait_event_interruptible_timeout(block->b_wait, |
73 | 100 | block->b_status != NLM_LCK_BLOCKED, | |
74 | for (head = &nlm_blocked; *head; head = &(*head)->b_next) { | 101 | timeout); |
75 | if (*head == &block) { | ||
76 | *head = block.b_next; | ||
77 | break; | ||
78 | } | ||
79 | } | ||
80 | 102 | ||
81 | if (!signalled()) { | 103 | if (block->b_status != NLM_LCK_BLOCKED) { |
82 | *statp = block.b_status; | 104 | req->a_res.status = block->b_status; |
83 | return 0; | 105 | block->b_status = NLM_LCK_BLOCKED; |
84 | } | 106 | } |
85 | 107 | ||
86 | /* Okay, we were interrupted. Cancel the pending request | 108 | return ret; |
87 | * unless the server has rebooted. | ||
88 | */ | ||
89 | if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0) | ||
90 | printk(KERN_NOTICE | ||
91 | "lockd: CANCEL call failed (errno %d)\n", -err); | ||
92 | |||
93 | return -ERESTARTSYS; | ||
94 | } | 109 | } |
95 | 110 | ||
96 | /* | 111 | /* |
@@ -100,27 +115,23 @@ u32 | |||
100 | nlmclnt_grant(struct nlm_lock *lock) | 115 | nlmclnt_grant(struct nlm_lock *lock) |
101 | { | 116 | { |
102 | struct nlm_wait *block; | 117 | struct nlm_wait *block; |
118 | u32 res = nlm_lck_denied; | ||
103 | 119 | ||
104 | /* | 120 | /* |
105 | * Look up blocked request based on arguments. | 121 | * Look up blocked request based on arguments. |
106 | * Warning: must not use cookie to match it! | 122 | * Warning: must not use cookie to match it! |
107 | */ | 123 | */ |
108 | for (block = nlm_blocked; block; block = block->b_next) { | 124 | list_for_each_entry(block, &nlm_blocked, b_list) { |
109 | if (nlm_compare_locks(block->b_lock, &lock->fl)) | 125 | if (nlm_compare_locks(block->b_lock, &lock->fl)) { |
110 | break; | 126 | /* Alright, we found a lock. Set the return status |
127 | * and wake up the caller | ||
128 | */ | ||
129 | block->b_status = NLM_LCK_GRANTED; | ||
130 | wake_up(&block->b_wait); | ||
131 | res = nlm_granted; | ||
132 | } | ||
111 | } | 133 | } |
112 | 134 | return res; | |
113 | /* Ooops, no blocked request found. */ | ||
114 | if (block == NULL) | ||
115 | return nlm_lck_denied; | ||
116 | |||
117 | /* Alright, we found the lock. Set the return status and | ||
118 | * wake up the caller. | ||
119 | */ | ||
120 | block->b_status = NLM_LCK_GRANTED; | ||
121 | wake_up(&block->b_wait); | ||
122 | |||
123 | return nlm_granted; | ||
124 | } | 135 | } |
125 | 136 | ||
126 | /* | 137 | /* |
@@ -230,7 +241,7 @@ restart: | |||
230 | host->h_reclaiming = 0; | 241 | host->h_reclaiming = 0; |
231 | 242 | ||
232 | /* Now, wake up all processes that sleep on a blocked lock */ | 243 | /* Now, wake up all processes that sleep on a blocked lock */ |
233 | for (block = nlm_blocked; block; block = block->b_next) { | 244 | list_for_each_entry(block, &nlm_blocked, b_list) { |
234 | if (block->b_host == host) { | 245 | if (block->b_host == host) { |
235 | block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; | 246 | block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; |
236 | wake_up(&block->b_wait); | 247 | wake_up(&block->b_wait); |
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; |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 52707c5ad6ea..82c77df81c5f 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -189,17 +189,15 @@ nlm_bind_host(struct nlm_host *host) | |||
189 | goto forgetit; | 189 | goto forgetit; |
190 | 190 | ||
191 | xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); | 191 | xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); |
192 | xprt->nocong = 1; /* No congestion control for NLM */ | ||
193 | xprt->resvport = 1; /* NLM requires a reserved port */ | ||
192 | 194 | ||
193 | /* Existing NLM servers accept AUTH_UNIX only */ | 195 | /* Existing NLM servers accept AUTH_UNIX only */ |
194 | clnt = rpc_create_client(xprt, host->h_name, &nlm_program, | 196 | clnt = rpc_create_client(xprt, host->h_name, &nlm_program, |
195 | host->h_version, RPC_AUTH_UNIX); | 197 | host->h_version, RPC_AUTH_UNIX); |
196 | if (IS_ERR(clnt)) { | 198 | if (IS_ERR(clnt)) |
197 | xprt_destroy(xprt); | ||
198 | goto forgetit; | 199 | goto forgetit; |
199 | } | ||
200 | clnt->cl_autobind = 1; /* turn on pmap queries */ | 200 | clnt->cl_autobind = 1; /* turn on pmap queries */ |
201 | xprt->nocong = 1; /* No congestion control for NLM */ | ||
202 | xprt->resvport = 1; /* NLM requires a reserved port */ | ||
203 | 201 | ||
204 | host->h_rpcclnt = clnt; | 202 | host->h_rpcclnt = clnt; |
205 | } | 203 | } |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 6fc1bebeec1d..2d144abe84ad 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -115,20 +115,19 @@ nsm_create(void) | |||
115 | xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); | 115 | xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); |
116 | if (IS_ERR(xprt)) | 116 | if (IS_ERR(xprt)) |
117 | return (struct rpc_clnt *)xprt; | 117 | return (struct rpc_clnt *)xprt; |
118 | xprt->resvport = 1; /* NSM requires a reserved port */ | ||
118 | 119 | ||
119 | clnt = rpc_create_client(xprt, "localhost", | 120 | clnt = rpc_create_client(xprt, "localhost", |
120 | &nsm_program, SM_VERSION, | 121 | &nsm_program, SM_VERSION, |
121 | RPC_AUTH_NULL); | 122 | RPC_AUTH_NULL); |
122 | if (IS_ERR(clnt)) | 123 | if (IS_ERR(clnt)) |
123 | goto out_destroy; | 124 | goto out_err; |
124 | clnt->cl_softrtry = 1; | 125 | clnt->cl_softrtry = 1; |
125 | clnt->cl_chatty = 1; | 126 | clnt->cl_chatty = 1; |
126 | clnt->cl_oneshot = 1; | 127 | clnt->cl_oneshot = 1; |
127 | xprt->resvport = 1; /* NSM requires a reserved port */ | ||
128 | return clnt; | 128 | return clnt; |
129 | 129 | ||
130 | out_destroy: | 130 | out_err: |
131 | xprt_destroy(xprt); | ||
132 | return clnt; | 131 | return clnt; |
133 | } | 132 | } |
134 | 133 | ||