diff options
| -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; | 
