diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:39 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:39 -0500 |
commit | 6849c0cab69f5d1a0fc7b05fa5bfb3dec53f86df (patch) | |
tree | 8bf595be663cc641b000846737c3ba1b6419eb6a /fs | |
parent | 09c7938c5640a6f22bef074ca6b803dccfdb93e3 (diff) |
lockd: Add refcounting to struct nlm_block
Otherwise, the block may disappear from underneath us when in
nlmsvc_retry_blocked.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/lockd/svclock.c | 94 |
1 files changed, 45 insertions, 49 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 | ||
42 | static void nlmsvc_release_block(struct nlm_block *block); | ||
42 | static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); | 43 | static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); |
43 | static int nlmsvc_remove_block(struct nlm_block *block); | 44 | static 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 | */ |
231 | static int | 238 | static int nlmsvc_unlink_block(struct nlm_block *block) |
232 | nlmsvc_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, | 249 | static 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 | |||
271 | static 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 | |||
368 | out: | 375 | out: |
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); |
561 | out_unlock: | 568 | out_unlock: |
562 | up(&file->f_sema); | 569 | up(&file->f_sema); |
563 | } | 570 | } |
@@ -573,20 +580,10 @@ out_unlock: | |||
573 | static void nlmsvc_grant_callback(struct rpc_task *task, void *data) | 580 | static 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 | ||
611 | static const struct rpc_call_ops nlmsvc_grant_ops = { | 606 | static 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) |