aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/lockd')
-rw-r--r--fs/lockd/svclock.c119
-rw-r--r--fs/lockd/svcsubs.c5
2 files changed, 59 insertions, 65 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 3127ae9e435c..7209712f3832 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -40,7 +40,7 @@
40 40
41static void nlmsvc_release_block(struct nlm_block *block); 41static void nlmsvc_release_block(struct nlm_block *block);
42static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); 42static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
43static int nlmsvc_remove_block(struct nlm_block *block); 43static void nlmsvc_remove_block(struct nlm_block *block);
44 44
45static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); 45static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
46static void nlmsvc_freegrantargs(struct nlm_rqst *call); 46static void nlmsvc_freegrantargs(struct nlm_rqst *call);
@@ -49,7 +49,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops;
49/* 49/*
50 * The list of blocked locks to retry 50 * The list of blocked locks to retry
51 */ 51 */
52static struct nlm_block * nlm_blocked; 52static LIST_HEAD(nlm_blocked);
53 53
54/* 54/*
55 * Insert a blocked lock into the global list 55 * Insert a blocked lock into the global list
@@ -57,48 +57,44 @@ static struct nlm_block * nlm_blocked;
57static void 57static void
58nlmsvc_insert_block(struct nlm_block *block, unsigned long when) 58nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
59{ 59{
60 struct nlm_block **bp, *b; 60 struct nlm_block *b;
61 struct list_head *pos;
61 62
62 dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); 63 dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
63 kref_get(&block->b_count); 64 if (list_empty(&block->b_list)) {
64 if (block->b_queued) 65 kref_get(&block->b_count);
65 nlmsvc_remove_block(block); 66 } else {
66 bp = &nlm_blocked; 67 list_del_init(&block->b_list);
68 }
69
70 pos = &nlm_blocked;
67 if (when != NLM_NEVER) { 71 if (when != NLM_NEVER) {
68 if ((when += jiffies) == NLM_NEVER) 72 if ((when += jiffies) == NLM_NEVER)
69 when ++; 73 when ++;
70 while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER) 74 list_for_each(pos, &nlm_blocked) {
71 bp = &b->b_next; 75 b = list_entry(pos, struct nlm_block, b_list);
72 } else 76 if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
73 while ((b = *bp) != 0) 77 break;
74 bp = &b->b_next; 78 }
79 /* On normal exit from the loop, pos == &nlm_blocked,
80 * so we will be adding to the end of the list - good
81 */
82 }
75 83
76 block->b_queued = 1; 84 list_add_tail(&block->b_list, pos);
77 block->b_when = when; 85 block->b_when = when;
78 block->b_next = b;
79 *bp = block;
80} 86}
81 87
82/* 88/*
83 * Remove a block from the global list 89 * Remove a block from the global list
84 */ 90 */
85static int 91static inline void
86nlmsvc_remove_block(struct nlm_block *block) 92nlmsvc_remove_block(struct nlm_block *block)
87{ 93{
88 struct nlm_block **bp, *b; 94 if (!list_empty(&block->b_list)) {
89 95 list_del_init(&block->b_list);
90 if (!block->b_queued) 96 nlmsvc_release_block(block);
91 return 1;
92 for (bp = &nlm_blocked; (b = *bp) != 0; bp = &b->b_next) {
93 if (b == block) {
94 *bp = block->b_next;
95 block->b_queued = 0;
96 nlmsvc_release_block(block);
97 return 1;
98 }
99 } 97 }
100
101 return 0;
102} 98}
103 99
104/* 100/*
@@ -107,14 +103,14 @@ nlmsvc_remove_block(struct nlm_block *block)
107static struct nlm_block * 103static struct nlm_block *
108nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock) 104nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
109{ 105{
110 struct nlm_block **head, *block; 106 struct nlm_block *block;
111 struct file_lock *fl; 107 struct file_lock *fl;
112 108
113 dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n", 109 dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
114 file, lock->fl.fl_pid, 110 file, lock->fl.fl_pid,
115 (long long)lock->fl.fl_start, 111 (long long)lock->fl.fl_start,
116 (long long)lock->fl.fl_end, lock->fl.fl_type); 112 (long long)lock->fl.fl_end, lock->fl.fl_type);
117 for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) { 113 list_for_each_entry(block, &nlm_blocked, b_list) {
118 fl = &block->b_call->a_args.lock.fl; 114 fl = &block->b_call->a_args.lock.fl;
119 dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n", 115 dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
120 block->b_file, fl->fl_pid, 116 block->b_file, fl->fl_pid,
@@ -147,16 +143,16 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
147{ 143{
148 struct nlm_block *block; 144 struct nlm_block *block;
149 145
150 for (block = nlm_blocked; block; block = block->b_next) { 146 list_for_each_entry(block, &nlm_blocked, b_list) {
151 dprintk("cookie: head of blocked queue %p, block %p\n",
152 nlm_blocked, block);
153 if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie) 147 if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)
154 && nlm_cmp_addr(sin, &block->b_host->h_addr)) 148 && nlm_cmp_addr(sin, &block->b_host->h_addr))
155 break; 149 goto found;
156 } 150 }
157 151
158 if (block != NULL) 152 return NULL;
159 kref_get(&block->b_count); 153
154found:
155 kref_get(&block->b_count);
160 return block; 156 return block;
161} 157}
162 158
@@ -192,6 +188,8 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
192 if (block == NULL) 188 if (block == NULL)
193 goto failed; 189 goto failed;
194 kref_init(&block->b_count); 190 kref_init(&block->b_count);
191 INIT_LIST_HEAD(&block->b_list);
192 INIT_LIST_HEAD(&block->b_flist);
195 193
196 if (!nlmsvc_setgrantargs(call, lock)) 194 if (!nlmsvc_setgrantargs(call, lock))
197 goto failed_free; 195 goto failed_free;
@@ -210,8 +208,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
210 file->f_count++; 208 file->f_count++;
211 209
212 /* Add to file's list of blocks */ 210 /* Add to file's list of blocks */
213 block->b_fnext = file->f_blocks; 211 list_add(&block->b_flist, &file->f_blocks);
214 file->f_blocks = block;
215 212
216 /* Set up RPC arguments for callback */ 213 /* Set up RPC arguments for callback */
217 block->b_call = call; 214 block->b_call = call;
@@ -248,18 +245,12 @@ static void nlmsvc_free_block(struct kref *kref)
248{ 245{
249 struct nlm_block *block = container_of(kref, struct nlm_block, b_count); 246 struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
250 struct nlm_file *file = block->b_file; 247 struct nlm_file *file = block->b_file;
251 struct nlm_block **bp;
252 248
253 dprintk("lockd: freeing block %p...\n", block); 249 dprintk("lockd: freeing block %p...\n", block);
254 250
255 down(&file->f_sema);
256 /* Remove block from file's list of blocks */ 251 /* Remove block from file's list of blocks */
257 for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) { 252 down(&file->f_sema);
258 if (*bp == block) { 253 list_del_init(&block->b_flist);
259 *bp = block->b_fnext;
260 break;
261 }
262 }
263 up(&file->f_sema); 254 up(&file->f_sema);
264 255
265 nlmsvc_freegrantargs(block->b_call); 256 nlmsvc_freegrantargs(block->b_call);
@@ -279,21 +270,23 @@ static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file)
279 struct nlm_block *block; 270 struct nlm_block *block;
280 271
281 down(&file->f_sema); 272 down(&file->f_sema);
282 for (block = file->f_blocks; block != NULL; block = block->b_fnext) 273 list_for_each_entry(block, &file->f_blocks, b_flist)
283 block->b_host->h_inuse = 1; 274 block->b_host->h_inuse = 1;
284 up(&file->f_sema); 275 up(&file->f_sema);
285} 276}
286 277
287static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file) 278static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file)
288{ 279{
289 struct nlm_block *block; 280 struct nlm_block *block, *next;
290 281
291restart: 282restart:
292 down(&file->f_sema); 283 down(&file->f_sema);
293 for (block = file->f_blocks; block != NULL; block = block->b_fnext) { 284 list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
294 if (host != NULL && host != block->b_host) 285 if (host != NULL && host != block->b_host)
295 continue; 286 continue;
296 if (!block->b_queued) 287 /* Do not destroy blocks that are not on
288 * the global retry list - why? */
289 if (list_empty(&block->b_list))
297 continue; 290 continue;
298 kref_get(&block->b_count); 291 kref_get(&block->b_count);
299 up(&file->f_sema); 292 up(&file->f_sema);
@@ -528,10 +521,10 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
528static void 521static void
529nlmsvc_notify_blocked(struct file_lock *fl) 522nlmsvc_notify_blocked(struct file_lock *fl)
530{ 523{
531 struct nlm_block **bp, *block; 524 struct nlm_block *block;
532 525
533 dprintk("lockd: VFS unblock notification for block %p\n", fl); 526 dprintk("lockd: VFS unblock notification for block %p\n", fl);
534 for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) { 527 list_for_each_entry(block, &nlm_blocked, b_list) {
535 if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) { 528 if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
536 nlmsvc_insert_block(block, 0); 529 nlmsvc_insert_block(block, 0);
537 svc_wake_up(block->b_daemon); 530 svc_wake_up(block->b_daemon);
@@ -697,16 +690,19 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
697unsigned long 690unsigned long
698nlmsvc_retry_blocked(void) 691nlmsvc_retry_blocked(void)
699{ 692{
700 struct nlm_block *block; 693 unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
694 struct nlm_block *block;
695
696 while (!list_empty(&nlm_blocked)) {
697 block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
701 698
702 dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
703 nlm_blocked,
704 nlm_blocked? nlm_blocked->b_when : 0);
705 while ((block = nlm_blocked) != 0) {
706 if (block->b_when == NLM_NEVER) 699 if (block->b_when == NLM_NEVER)
707 break; 700 break;
708 if (time_after(block->b_when,jiffies)) 701 if (time_after(block->b_when,jiffies)) {
702 timeout = block->b_when - jiffies;
709 break; 703 break;
704 }
705
710 dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", 706 dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
711 block, block->b_when); 707 block, block->b_when);
712 kref_get(&block->b_count); 708 kref_get(&block->b_count);
@@ -714,8 +710,5 @@ nlmsvc_retry_blocked(void)
714 nlmsvc_release_block(block); 710 nlmsvc_release_block(block);
715 } 711 }
716 712
717 if ((block = nlm_blocked) && block->b_when != NLM_NEVER) 713 return timeout;
718 return (block->b_when - jiffies);
719
720 return MAX_SCHEDULE_TIMEOUT;
721} 714}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index c8308bccd319..a92fc5813144 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -107,6 +107,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
107 memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); 107 memcpy(&file->f_handle, f, sizeof(struct nfs_fh));
108 file->f_hash = hash; 108 file->f_hash = hash;
109 init_MUTEX(&file->f_sema); 109 init_MUTEX(&file->f_sema);
110 INIT_LIST_HEAD(&file->f_blocks);
110 111
111 /* Open the file. Note that this must not sleep for too long, else 112 /* Open the file. Note that this must not sleep for too long, else
112 * we would lock up lockd:-) So no NFS re-exports, folks. 113 * we would lock up lockd:-) So no NFS re-exports, folks.
@@ -220,7 +221,7 @@ nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action)
220{ 221{
221 if (action == NLM_ACT_CHECK) { 222 if (action == NLM_ACT_CHECK) {
222 /* Fast path for mark and sweep garbage collection */ 223 /* Fast path for mark and sweep garbage collection */
223 if (file->f_count || file->f_blocks || file->f_shares) 224 if (file->f_count || list_empty(&file->f_blocks) || file->f_shares)
224 return 1; 225 return 1;
225 } else { 226 } else {
226 nlmsvc_traverse_blocks(host, file, action); 227 nlmsvc_traverse_blocks(host, file, action);
@@ -253,7 +254,7 @@ nlm_traverse_files(struct nlm_host *host, int action)
253 mutex_lock(&nlm_file_mutex); 254 mutex_lock(&nlm_file_mutex);
254 file->f_count--; 255 file->f_count--;
255 /* No more references to this file. Let go of it. */ 256 /* No more references to this file. Let go of it. */
256 if (!file->f_blocks && !file->f_locks 257 if (list_empty(&file->f_blocks) && !file->f_locks
257 && !file->f_shares && !file->f_count) { 258 && !file->f_shares && !file->f_count) {
258 *fp = file->f_next; 259 *fp = file->f_next;
259 nlmsvc_ops->fclose(file->f_file); 260 nlmsvc_ops->fclose(file->f_file);