diff options
Diffstat (limited to 'fs/lockd/svclock.c')
-rw-r--r-- | fs/lockd/svclock.c | 91 |
1 files changed, 87 insertions, 4 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index f2449265e2eb..6e748573e0c6 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -261,6 +261,7 @@ static void nlmsvc_free_block(struct kref *kref) | |||
261 | nlmsvc_freegrantargs(block->b_call); | 261 | nlmsvc_freegrantargs(block->b_call); |
262 | nlm_release_call(block->b_call); | 262 | nlm_release_call(block->b_call); |
263 | nlm_release_file(block->b_file); | 263 | nlm_release_file(block->b_file); |
264 | kfree(block->b_fl); | ||
264 | kfree(block); | 265 | kfree(block); |
265 | } | 266 | } |
266 | 267 | ||
@@ -528,6 +529,64 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | |||
528 | } | 529 | } |
529 | 530 | ||
530 | /* | 531 | /* |
532 | * This is a callback from the filesystem for VFS file lock requests. | ||
533 | * It will be used if fl_grant is defined and the filesystem can not | ||
534 | * respond to the request immediately. | ||
535 | * For GETLK request it will copy the reply to the nlm_block. | ||
536 | * For SETLK or SETLKW request it will get the local posix lock. | ||
537 | * In all cases it will move the block to the head of nlm_blocked q where | ||
538 | * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the | ||
539 | * deferred rpc for GETLK and SETLK. | ||
540 | */ | ||
541 | static void | ||
542 | nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf, | ||
543 | int result) | ||
544 | { | ||
545 | block->b_flags |= B_GOT_CALLBACK; | ||
546 | if (result == 0) | ||
547 | block->b_granted = 1; | ||
548 | else | ||
549 | block->b_flags |= B_TIMED_OUT; | ||
550 | if (conf) { | ||
551 | block->b_fl = kzalloc(sizeof(struct file_lock), GFP_KERNEL); | ||
552 | if (block->b_fl) | ||
553 | locks_copy_lock(block->b_fl, conf); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf, | ||
558 | int result) | ||
559 | { | ||
560 | struct nlm_block *block; | ||
561 | int rc = -ENOENT; | ||
562 | |||
563 | lock_kernel(); | ||
564 | list_for_each_entry(block, &nlm_blocked, b_list) { | ||
565 | if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) { | ||
566 | dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n", | ||
567 | block, block->b_flags); | ||
568 | if (block->b_flags & B_QUEUED) { | ||
569 | if (block->b_flags & B_TIMED_OUT) { | ||
570 | rc = -ENOLCK; | ||
571 | break; | ||
572 | } | ||
573 | nlmsvc_update_deferred_block(block, conf, result); | ||
574 | } else if (result == 0) | ||
575 | block->b_granted = 1; | ||
576 | |||
577 | nlmsvc_insert_block(block, 0); | ||
578 | svc_wake_up(block->b_daemon); | ||
579 | rc = 0; | ||
580 | break; | ||
581 | } | ||
582 | } | ||
583 | unlock_kernel(); | ||
584 | if (rc == -ENOENT) | ||
585 | printk(KERN_WARNING "lockd: grant for unknown block\n"); | ||
586 | return rc; | ||
587 | } | ||
588 | |||
589 | /* | ||
531 | * Unblock a blocked lock request. This is a callback invoked from the | 590 | * Unblock a blocked lock request. This is a callback invoked from the |
532 | * VFS layer when a lock on which we blocked is removed. | 591 | * VFS layer when a lock on which we blocked is removed. |
533 | * | 592 | * |
@@ -559,6 +618,7 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2) | |||
559 | struct lock_manager_operations nlmsvc_lock_operations = { | 618 | struct lock_manager_operations nlmsvc_lock_operations = { |
560 | .fl_compare_owner = nlmsvc_same_owner, | 619 | .fl_compare_owner = nlmsvc_same_owner, |
561 | .fl_notify = nlmsvc_notify_blocked, | 620 | .fl_notify = nlmsvc_notify_blocked, |
621 | .fl_grant = nlmsvc_grant_deferred, | ||
562 | }; | 622 | }; |
563 | 623 | ||
564 | /* | 624 | /* |
@@ -581,6 +641,8 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
581 | 641 | ||
582 | dprintk("lockd: grant blocked lock %p\n", block); | 642 | dprintk("lockd: grant blocked lock %p\n", block); |
583 | 643 | ||
644 | kref_get(&block->b_count); | ||
645 | |||
584 | /* Unlink block request from list */ | 646 | /* Unlink block request from list */ |
585 | nlmsvc_unlink_block(block); | 647 | nlmsvc_unlink_block(block); |
586 | 648 | ||
@@ -603,11 +665,13 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
603 | case -EAGAIN: | 665 | case -EAGAIN: |
604 | dprintk("lockd: lock still blocked\n"); | 666 | dprintk("lockd: lock still blocked\n"); |
605 | nlmsvc_insert_block(block, NLM_NEVER); | 667 | nlmsvc_insert_block(block, NLM_NEVER); |
668 | nlmsvc_release_block(block); | ||
606 | return; | 669 | return; |
607 | default: | 670 | default: |
608 | printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", | 671 | printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", |
609 | -error, __FUNCTION__); | 672 | -error, __FUNCTION__); |
610 | nlmsvc_insert_block(block, 10 * HZ); | 673 | nlmsvc_insert_block(block, 10 * HZ); |
674 | nlmsvc_release_block(block); | ||
611 | return; | 675 | return; |
612 | } | 676 | } |
613 | 677 | ||
@@ -620,7 +684,6 @@ callback: | |||
620 | nlmsvc_insert_block(block, 30 * HZ); | 684 | nlmsvc_insert_block(block, 30 * HZ); |
621 | 685 | ||
622 | /* Call the client */ | 686 | /* Call the client */ |
623 | kref_get(&block->b_count); | ||
624 | nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops); | 687 | nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops); |
625 | } | 688 | } |
626 | 689 | ||
@@ -693,6 +756,23 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status) | |||
693 | nlmsvc_release_block(block); | 756 | nlmsvc_release_block(block); |
694 | } | 757 | } |
695 | 758 | ||
759 | /* Helper function to handle retry of a deferred block. | ||
760 | * If it is a blocking lock, call grant_blocked. | ||
761 | * For a non-blocking lock or test lock, revisit the request. | ||
762 | */ | ||
763 | static void | ||
764 | retry_deferred_block(struct nlm_block *block) | ||
765 | { | ||
766 | if (!(block->b_flags & B_GOT_CALLBACK)) | ||
767 | block->b_flags |= B_TIMED_OUT; | ||
768 | nlmsvc_insert_block(block, NLM_TIMEOUT); | ||
769 | dprintk("revisit block %p flags %d\n", block, block->b_flags); | ||
770 | if (block->b_deferred_req) { | ||
771 | block->b_deferred_req->revisit(block->b_deferred_req, 0); | ||
772 | block->b_deferred_req = NULL; | ||
773 | } | ||
774 | } | ||
775 | |||
696 | /* | 776 | /* |
697 | * Retry all blocked locks that have been notified. This is where lockd | 777 | * Retry all blocked locks that have been notified. This is where lockd |
698 | * picks up locks that can be granted, or grant notifications that must | 778 | * picks up locks that can be granted, or grant notifications that must |
@@ -716,9 +796,12 @@ nlmsvc_retry_blocked(void) | |||
716 | 796 | ||
717 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", | 797 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", |
718 | block, block->b_when); | 798 | block, block->b_when); |
719 | kref_get(&block->b_count); | 799 | if (block->b_flags & B_QUEUED) { |
720 | nlmsvc_grant_blocked(block); | 800 | dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n", |
721 | nlmsvc_release_block(block); | 801 | block, block->b_granted, block->b_flags); |
802 | retry_deferred_block(block); | ||
803 | } else | ||
804 | nlmsvc_grant_blocked(block); | ||
722 | } | 805 | } |
723 | 806 | ||
724 | return timeout; | 807 | return timeout; |