aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd/clntlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/lockd/clntlock.c')
-rw-r--r--fs/lockd/clntlock.c113
1 files changed, 62 insertions, 51 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 */
33struct nlm_wait { 33struct 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
42static struct nlm_wait * nlm_blocked; 42static 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 */
47int 47int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl)
48nlmclnt_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
66void 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 */
80long 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
100nlmclnt_grant(struct nlm_lock *lock) 115nlmclnt_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);