aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/lockd/svclock.c94
-rw-r--r--include/linux/lockd/lockd.h3
2 files changed, 47 insertions, 50 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 1d3a74df93f3..20caeceffb14 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -39,6 +39,7 @@
39#define nlm_deadlock nlm_lck_denied 39#define nlm_deadlock nlm_lck_denied
40#endif 40#endif
41 41
42static void nlmsvc_release_block(struct nlm_block *block);
42static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); 43static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
43static int nlmsvc_remove_block(struct nlm_block *block); 44static int nlmsvc_remove_block(struct nlm_block *block);
44 45
@@ -58,6 +59,7 @@ nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
58 struct nlm_block **bp, *b; 59 struct nlm_block **bp, *b;
59 60
60 dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); 61 dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
62 kref_get(&block->b_count);
61 if (block->b_queued) 63 if (block->b_queued)
62 nlmsvc_remove_block(block); 64 nlmsvc_remove_block(block);
63 bp = &nlm_blocked; 65 bp = &nlm_blocked;
@@ -90,6 +92,7 @@ nlmsvc_remove_block(struct nlm_block *block)
90 if (b == block) { 92 if (b == block) {
91 *bp = block->b_next; 93 *bp = block->b_next;
92 block->b_queued = 0; 94 block->b_queued = 0;
95 nlmsvc_release_block(block);
93 return 1; 96 return 1;
94 } 97 }
95 } 98 }
@@ -123,6 +126,7 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
123 *head = block->b_next; 126 *head = block->b_next;
124 block->b_queued = 0; 127 block->b_queued = 0;
125 } 128 }
129 kref_get(&block->b_count);
126 return block; 130 return block;
127 } 131 }
128 } 132 }
@@ -155,6 +159,8 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
155 break; 159 break;
156 } 160 }
157 161
162 if (block != NULL)
163 kref_get(&block->b_count);
158 return block; 164 return block;
159} 165}
160 166
@@ -188,6 +194,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
188 memset(block, 0, sizeof(*block)); 194 memset(block, 0, sizeof(*block));
189 locks_init_lock(&block->b_call.a_args.lock.fl); 195 locks_init_lock(&block->b_call.a_args.lock.fl);
190 locks_init_lock(&block->b_call.a_res.lock.fl); 196 locks_init_lock(&block->b_call.a_res.lock.fl);
197 kref_init(&block->b_count);
191 198
192 if (!nlmclnt_setgrantargs(&block->b_call, lock)) 199 if (!nlmclnt_setgrantargs(&block->b_call, lock))
193 goto failed_free; 200 goto failed_free;
@@ -228,27 +235,24 @@ failed:
228 * It is the caller's responsibility to check whether the file 235 * It is the caller's responsibility to check whether the file
229 * can be closed hereafter. 236 * can be closed hereafter.
230 */ 237 */
231static int 238static int nlmsvc_unlink_block(struct nlm_block *block)
232nlmsvc_delete_block(struct nlm_block *block)
233{ 239{
234 struct file_lock *fl = &block->b_call.a_args.lock.fl;
235 struct nlm_file *file = block->b_file;
236 struct nlm_block **bp;
237 int status; 240 int status;
238 241 dprintk("lockd: unlinking block %p...\n", block);
239 dprintk("lockd: deleting block %p...\n", block);
240 242
241 /* Remove block from list */ 243 /* Remove block from list */
244 status = posix_unblock_lock(block->b_file->f_file, &block->b_call.a_args.lock.fl);
242 nlmsvc_remove_block(block); 245 nlmsvc_remove_block(block);
243 status = posix_unblock_lock(file->f_file, fl); 246 return status;
247}
244 248
245 /* If the block is in the middle of a GRANT callback, 249static void nlmsvc_free_block(struct kref *kref)
246 * don't kill it yet. */ 250{
247 if (block->b_incall) { 251 struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
248 nlmsvc_insert_block(block, NLM_NEVER); 252 struct nlm_file *file = block->b_file;
249 block->b_done = 1; 253 struct nlm_block **bp;
250 return status; 254
251 } 255 dprintk("lockd: freeing block %p...\n", block);
252 256
253 /* Remove block from file's list of blocks */ 257 /* Remove block from file's list of blocks */
254 for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) { 258 for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
@@ -262,7 +266,12 @@ nlmsvc_delete_block(struct nlm_block *block)
262 nlm_release_host(block->b_host); 266 nlm_release_host(block->b_host);
263 nlmclnt_freegrantargs(&block->b_call); 267 nlmclnt_freegrantargs(&block->b_call);
264 kfree(block); 268 kfree(block);
265 return status; 269}
270
271static void nlmsvc_release_block(struct nlm_block *block)
272{
273 if (block != NULL)
274 kref_put(&block->b_count, nlmsvc_free_block);
266} 275}
267 276
268/* 277/*
@@ -282,7 +291,7 @@ nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
282 block->b_host->h_inuse = 1; 291 block->b_host->h_inuse = 1;
283 else if (action == NLM_ACT_UNLOCK) { 292 else if (action == NLM_ACT_UNLOCK) {
284 if (host == NULL || host == block->b_host) 293 if (host == NULL || host == block->b_host)
285 nlmsvc_delete_block(block); 294 nlmsvc_unlink_block(block);
286 } 295 }
287 } 296 }
288 up(&file->f_sema); 297 up(&file->f_sema);
@@ -318,9 +327,9 @@ again:
318 block = nlmsvc_lookup_block(file, lock, 0); 327 block = nlmsvc_lookup_block(file, lock, 0);
319 if (block == NULL) { 328 if (block == NULL) {
320 if (newblock != NULL) 329 if (newblock != NULL)
321 lock = &newblock->b_call.a_args.lock.fl; 330 lock = &newblock->b_call.a_args.lock;
322 } else 331 } else
323 lock = &block->b_call.a_args.lock.fl; 332 lock = &block->b_call.a_args.lock;
324 333
325 error = posix_lock_file(file->f_file, &lock->fl); 334 error = posix_lock_file(file->f_file, &lock->fl);
326 lock->fl.fl_flags &= ~FL_SLEEP; 335 lock->fl.fl_flags &= ~FL_SLEEP;
@@ -363,12 +372,10 @@ again:
363 372
364 /* Append to list of blocked */ 373 /* Append to list of blocked */
365 nlmsvc_insert_block(newblock, NLM_NEVER); 374 nlmsvc_insert_block(newblock, NLM_NEVER);
366 newblock = NULL;
367
368out: 375out:
369 up(&file->f_sema); 376 up(&file->f_sema);
370 if (newblock != NULL) 377 nlmsvc_release_block(newblock);
371 nlmsvc_delete_block(newblock); 378 nlmsvc_release_block(block);
372 dprintk("lockd: nlmsvc_lock returned %u\n", ret); 379 dprintk("lockd: nlmsvc_lock returned %u\n", ret);
373 return ret; 380 return ret;
374} 381}
@@ -450,8 +457,10 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
450 (long long)lock->fl.fl_end); 457 (long long)lock->fl.fl_end);
451 458
452 down(&file->f_sema); 459 down(&file->f_sema);
453 if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) 460 if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) {
454 status = nlmsvc_delete_block(block); 461 status = nlmsvc_unlink_block(block);
462 nlmsvc_release_block(block);
463 }
455 up(&file->f_sema); 464 up(&file->f_sema);
456 return status ? nlm_lck_denied : nlm_granted; 465 return status ? nlm_lck_denied : nlm_granted;
457} 466}
@@ -514,7 +523,7 @@ nlmsvc_grant_blocked(struct nlm_block *block)
514 down(&file->f_sema); 523 down(&file->f_sema);
515 524
516 /* Unlink block request from list */ 525 /* Unlink block request from list */
517 nlmsvc_remove_block(block); 526 nlmsvc_unlink_block(block);
518 527
519 /* If b_granted is true this means we've been here before. 528 /* If b_granted is true this means we've been here before.
520 * Just retry the grant callback, possibly refreshing the RPC 529 * Just retry the grant callback, possibly refreshing the RPC
@@ -525,7 +534,6 @@ nlmsvc_grant_blocked(struct nlm_block *block)
525 } 534 }
526 535
527 /* Try the lock operation again */ 536 /* Try the lock operation again */
528 posix_unblock_lock(file->f_file, &lock->fl);
529 lock->fl.fl_flags |= FL_SLEEP; 537 lock->fl.fl_flags |= FL_SLEEP;
530 error = posix_lock_file(file->f_file, &lock->fl); 538 error = posix_lock_file(file->f_file, &lock->fl);
531 lock->fl.fl_flags &= ~FL_SLEEP; 539 lock->fl.fl_flags &= ~FL_SLEEP;
@@ -548,16 +556,15 @@ callback:
548 /* Lock was granted by VFS. */ 556 /* Lock was granted by VFS. */
549 dprintk("lockd: GRANTing blocked lock.\n"); 557 dprintk("lockd: GRANTing blocked lock.\n");
550 block->b_granted = 1; 558 block->b_granted = 1;
551 block->b_incall = 1;
552 559
553 /* Schedule next grant callback in 30 seconds */ 560 /* Schedule next grant callback in 30 seconds */
554 nlmsvc_insert_block(block, 30 * HZ); 561 nlmsvc_insert_block(block, 30 * HZ);
555 562
556 /* Call the client */ 563 /* Call the client */
557 nlm_get_host(block->b_call.a_host); 564 kref_get(&block->b_count);
558 if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG, 565 if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
559 &nlmsvc_grant_ops) < 0) 566 &nlmsvc_grant_ops) < 0)
560 nlm_release_host(block->b_call.a_host); 567 nlmsvc_release_block(block);
561out_unlock: 568out_unlock:
562 up(&file->f_sema); 569 up(&file->f_sema);
563} 570}
@@ -573,20 +580,10 @@ out_unlock:
573static void nlmsvc_grant_callback(struct rpc_task *task, void *data) 580static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
574{ 581{
575 struct nlm_rqst *call = data; 582 struct nlm_rqst *call = data;
576 struct nlm_block *block; 583 struct nlm_block *block = container_of(call, struct nlm_block, b_call);
577 unsigned long timeout; 584 unsigned long timeout;
578 struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client);
579 585
580 dprintk("lockd: GRANT_MSG RPC callback\n"); 586 dprintk("lockd: GRANT_MSG RPC callback\n");
581 dprintk("callback: looking for cookie %s, host (%u.%u.%u.%u)\n",
582 nlmdbg_cookie2a(&call->a_args.cookie),
583 NIPQUAD(peer_addr->sin_addr.s_addr));
584 if (!(block = nlmsvc_find_block(&call->a_args.cookie, peer_addr))) {
585 dprintk("lockd: no block for cookie %s, host (%u.%u.%u.%u)\n",
586 nlmdbg_cookie2a(&call->a_args.cookie),
587 NIPQUAD(peer_addr->sin_addr.s_addr));
588 return;
589 }
590 587
591 /* Technically, we should down the file semaphore here. Since we 588 /* Technically, we should down the file semaphore here. Since we
592 * move the block towards the head of the queue only, no harm 589 * move the block towards the head of the queue only, no harm
@@ -603,9 +600,7 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
603 } 600 }
604 nlmsvc_insert_block(block, timeout); 601 nlmsvc_insert_block(block, timeout);
605 svc_wake_up(block->b_daemon); 602 svc_wake_up(block->b_daemon);
606 block->b_incall = 0; 603 nlmsvc_release_block(block);
607
608 nlm_release_host(call->a_host);
609} 604}
610 605
611static const struct rpc_call_ops nlmsvc_grant_ops = { 606static const struct rpc_call_ops nlmsvc_grant_ops = {
@@ -631,20 +626,19 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
631 626
632 file->f_count++; 627 file->f_count++;
633 down(&file->f_sema); 628 down(&file->f_sema);
634 block = nlmsvc_find_block(cookie, &rqstp->rq_addr);
635 if (block) { 629 if (block) {
636 if (status == NLM_LCK_DENIED_GRACE_PERIOD) { 630 if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
637 /* Try again in a couple of seconds */ 631 /* Try again in a couple of seconds */
638 nlmsvc_insert_block(block, 10 * HZ); 632 nlmsvc_insert_block(block, 10 * HZ);
639 up(&file->f_sema);
640 } else { 633 } else {
641 /* Lock is now held by client, or has been rejected. 634 /* Lock is now held by client, or has been rejected.
642 * In both cases, the block should be removed. */ 635 * In both cases, the block should be removed. */
643 nlmsvc_delete_block(block); 636 nlmsvc_unlink_block(block);
644 up(&file->f_sema);
645 } 637 }
646 } 638 }
639 up(&file->f_sema);
647 nlm_release_file(file); 640 nlm_release_file(file);
641 nlmsvc_release_block(block);
648} 642}
649 643
650/* 644/*
@@ -667,10 +661,12 @@ nlmsvc_retry_blocked(void)
667 break; 661 break;
668 dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", 662 dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
669 block, block->b_when, block->b_done); 663 block, block->b_when, block->b_done);
664 kref_get(&block->b_count);
670 if (block->b_done) 665 if (block->b_done)
671 nlmsvc_delete_block(block); 666 nlmsvc_unlink_block(block);
672 else 667 else
673 nlmsvc_grant_blocked(block); 668 nlmsvc_grant_blocked(block);
669 nlmsvc_release_block(block);
674 } 670 }
675 671
676 if ((block = nlm_blocked) && block->b_when != NLM_NEVER) 672 if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index ef21ed296039..08ab9773f762 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -14,6 +14,7 @@
14#include <linux/config.h> 14#include <linux/config.h>
15#include <linux/in.h> 15#include <linux/in.h>
16#include <linux/fs.h> 16#include <linux/fs.h>
17#include <linux/kref.h>
17#include <linux/utsname.h> 18#include <linux/utsname.h>
18#include <linux/nfsd/nfsfh.h> 19#include <linux/nfsd/nfsfh.h>
19#include <linux/lockd/bind.h> 20#include <linux/lockd/bind.h>
@@ -110,6 +111,7 @@ struct nlm_file {
110 */ 111 */
111#define NLM_NEVER (~(unsigned long) 0) 112#define NLM_NEVER (~(unsigned long) 0)
112struct nlm_block { 113struct nlm_block {
114 struct kref b_count; /* Reference count */
113 struct nlm_block * b_next; /* linked list (all blocks) */ 115 struct nlm_block * b_next; /* linked list (all blocks) */
114 struct nlm_block * b_fnext; /* linked list (per file) */ 116 struct nlm_block * b_fnext; /* linked list (per file) */
115 struct nlm_rqst b_call; /* RPC args & callback info */ 117 struct nlm_rqst b_call; /* RPC args & callback info */
@@ -119,7 +121,6 @@ struct nlm_block {
119 unsigned int b_id; /* block id */ 121 unsigned int b_id; /* block id */
120 unsigned char b_queued; /* re-queued */ 122 unsigned char b_queued; /* re-queued */
121 unsigned char b_granted; /* VFS granted lock */ 123 unsigned char b_granted; /* VFS granted lock */
122 unsigned char b_incall; /* doing callback */
123 unsigned char b_done; /* callback complete */ 124 unsigned char b_done; /* callback complete */
124 struct nlm_file * b_file; /* file in question */ 125 struct nlm_file * b_file; /* file in question */
125}; 126};