aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/lockd/svclock.c91
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 */
541static void
542nlmsvc_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
557static 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)
559struct lock_manager_operations nlmsvc_lock_operations = { 618struct 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 */
763static void
764retry_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;