aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd/svclock.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/lockd/svclock.c')
-rw-r--r--fs/lockd/svclock.c275
1 files changed, 228 insertions, 47 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index cf51f849e76c..b3efa4536cc5 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -173,7 +173,7 @@ found:
173 */ 173 */
174static inline struct nlm_block * 174static inline struct nlm_block *
175nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, 175nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
176 struct nlm_lock *lock, struct nlm_cookie *cookie) 176 struct nlm_lock *lock, struct nlm_cookie *cookie)
177{ 177{
178 struct nlm_block *block; 178 struct nlm_block *block;
179 struct nlm_host *host; 179 struct nlm_host *host;
@@ -210,6 +210,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
210 block->b_daemon = rqstp->rq_server; 210 block->b_daemon = rqstp->rq_server;
211 block->b_host = host; 211 block->b_host = host;
212 block->b_file = file; 212 block->b_file = file;
213 block->b_fl = NULL;
213 file->f_count++; 214 file->f_count++;
214 215
215 /* Add to file's list of blocks */ 216 /* Add to file's list of blocks */
@@ -261,6 +262,7 @@ static void nlmsvc_free_block(struct kref *kref)
261 nlmsvc_freegrantargs(block->b_call); 262 nlmsvc_freegrantargs(block->b_call);
262 nlm_release_call(block->b_call); 263 nlm_release_call(block->b_call);
263 nlm_release_file(block->b_file); 264 nlm_release_file(block->b_file);
265 kfree(block->b_fl);
264 kfree(block); 266 kfree(block);
265} 267}
266 268
@@ -331,6 +333,31 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call)
331} 333}
332 334
333/* 335/*
336 * Deferred lock request handling for non-blocking lock
337 */
338static u32
339nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
340{
341 u32 status = nlm_lck_denied_nolocks;
342
343 block->b_flags |= B_QUEUED;
344
345 nlmsvc_insert_block(block, NLM_TIMEOUT);
346
347 block->b_cache_req = &rqstp->rq_chandle;
348 if (rqstp->rq_chandle.defer) {
349 block->b_deferred_req =
350 rqstp->rq_chandle.defer(block->b_cache_req);
351 if (block->b_deferred_req != NULL)
352 status = nlm_drop_reply;
353 }
354 dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n",
355 block, block->b_flags, status);
356
357 return status;
358}
359
360/*
334 * Attempt to establish a lock, and if it can't be granted, block it 361 * Attempt to establish a lock, and if it can't be granted, block it
335 * if required. 362 * if required.
336 */ 363 */
@@ -338,7 +365,7 @@ __be32
338nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, 365nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
339 struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) 366 struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
340{ 367{
341 struct nlm_block *block, *newblock = NULL; 368 struct nlm_block *block = NULL;
342 int error; 369 int error;
343 __be32 ret; 370 __be32 ret;
344 371
@@ -351,29 +378,58 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
351 wait); 378 wait);
352 379
353 380
354 lock->fl.fl_flags &= ~FL_SLEEP;
355again:
356 /* Lock file against concurrent access */ 381 /* Lock file against concurrent access */
357 mutex_lock(&file->f_mutex); 382 mutex_lock(&file->f_mutex);
358 /* Get existing block (in case client is busy-waiting) */ 383 /* Get existing block (in case client is busy-waiting)
384 * or create new block
385 */
359 block = nlmsvc_lookup_block(file, lock); 386 block = nlmsvc_lookup_block(file, lock);
360 if (block == NULL) { 387 if (block == NULL) {
361 if (newblock != NULL) 388 block = nlmsvc_create_block(rqstp, file, lock, cookie);
362 lock = &newblock->b_call->a_args.lock; 389 ret = nlm_lck_denied_nolocks;
363 } else 390 if (block == NULL)
391 goto out;
364 lock = &block->b_call->a_args.lock; 392 lock = &block->b_call->a_args.lock;
393 } else
394 lock->fl.fl_flags &= ~FL_SLEEP;
365 395
366 error = posix_lock_file(file->f_file, &lock->fl); 396 if (block->b_flags & B_QUEUED) {
367 lock->fl.fl_flags &= ~FL_SLEEP; 397 dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
398 block, block->b_flags);
399 if (block->b_granted) {
400 nlmsvc_unlink_block(block);
401 ret = nlm_granted;
402 goto out;
403 }
404 if (block->b_flags & B_TIMED_OUT) {
405 nlmsvc_unlink_block(block);
406 ret = nlm_lck_denied;
407 goto out;
408 }
409 ret = nlm_drop_reply;
410 goto out;
411 }
368 412
369 dprintk("lockd: posix_lock_file returned %d\n", error); 413 if (!wait)
414 lock->fl.fl_flags &= ~FL_SLEEP;
415 error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
416 lock->fl.fl_flags &= ~FL_SLEEP;
370 417
418 dprintk("lockd: vfs_lock_file returned %d\n", error);
371 switch(error) { 419 switch(error) {
372 case 0: 420 case 0:
373 ret = nlm_granted; 421 ret = nlm_granted;
374 goto out; 422 goto out;
375 case -EAGAIN: 423 case -EAGAIN:
424 ret = nlm_lck_denied;
376 break; 425 break;
426 case -EINPROGRESS:
427 if (wait)
428 break;
429 /* Filesystem lock operation is in progress
430 Add it to the queue waiting for callback */
431 ret = nlmsvc_defer_lock_rqst(rqstp, block);
432 goto out;
377 case -EDEADLK: 433 case -EDEADLK:
378 ret = nlm_deadlock; 434 ret = nlm_deadlock;
379 goto out; 435 goto out;
@@ -387,26 +443,11 @@ again:
387 goto out; 443 goto out;
388 444
389 ret = nlm_lck_blocked; 445 ret = nlm_lck_blocked;
390 if (block != NULL)
391 goto out;
392
393 /* If we don't have a block, create and initialize it. Then
394 * retry because we may have slept in kmalloc. */
395 /* We have to release f_mutex as nlmsvc_create_block may try to
396 * to claim it while doing host garbage collection */
397 if (newblock == NULL) {
398 mutex_unlock(&file->f_mutex);
399 dprintk("lockd: blocking on this lock (allocating).\n");
400 if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
401 return nlm_lck_denied_nolocks;
402 goto again;
403 }
404 446
405 /* Append to list of blocked */ 447 /* Append to list of blocked */
406 nlmsvc_insert_block(newblock, NLM_NEVER); 448 nlmsvc_insert_block(block, NLM_NEVER);
407out: 449out:
408 mutex_unlock(&file->f_mutex); 450 mutex_unlock(&file->f_mutex);
409 nlmsvc_release_block(newblock);
410 nlmsvc_release_block(block); 451 nlmsvc_release_block(block);
411 dprintk("lockd: nlmsvc_lock returned %u\n", ret); 452 dprintk("lockd: nlmsvc_lock returned %u\n", ret);
412 return ret; 453 return ret;
@@ -416,9 +457,14 @@ out:
416 * Test for presence of a conflicting lock. 457 * Test for presence of a conflicting lock.
417 */ 458 */
418__be32 459__be32
419nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, 460nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
420 struct nlm_lock *conflock) 461 struct nlm_lock *lock, struct nlm_lock *conflock,
462 struct nlm_cookie *cookie)
421{ 463{
464 struct nlm_block *block = NULL;
465 int error;
466 __be32 ret;
467
422 dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", 468 dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
423 file->f_file->f_path.dentry->d_inode->i_sb->s_id, 469 file->f_file->f_path.dentry->d_inode->i_sb->s_id,
424 file->f_file->f_path.dentry->d_inode->i_ino, 470 file->f_file->f_path.dentry->d_inode->i_ino,
@@ -426,19 +472,70 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
426 (long long)lock->fl.fl_start, 472 (long long)lock->fl.fl_start,
427 (long long)lock->fl.fl_end); 473 (long long)lock->fl.fl_end);
428 474
429 if (posix_test_lock(file->f_file, &lock->fl, &conflock->fl)) { 475 /* Get existing block (in case client is busy-waiting) */
430 dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", 476 block = nlmsvc_lookup_block(file, lock);
431 conflock->fl.fl_type, 477
432 (long long)conflock->fl.fl_start, 478 if (block == NULL) {
433 (long long)conflock->fl.fl_end); 479 struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
434 conflock->caller = "somehost"; /* FIXME */ 480
435 conflock->len = strlen(conflock->caller); 481 if (conf == NULL)
436 conflock->oh.len = 0; /* don't return OH info */ 482 return nlm_granted;
437 conflock->svid = conflock->fl.fl_pid; 483 block = nlmsvc_create_block(rqstp, file, lock, cookie);
438 return nlm_lck_denied; 484 if (block == NULL) {
485 kfree(conf);
486 return nlm_granted;
487 }
488 block->b_fl = conf;
489 }
490 if (block->b_flags & B_QUEUED) {
491 dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n",
492 block, block->b_flags, block->b_fl);
493 if (block->b_flags & B_TIMED_OUT) {
494 nlmsvc_unlink_block(block);
495 return nlm_lck_denied;
496 }
497 if (block->b_flags & B_GOT_CALLBACK) {
498 if (block->b_fl != NULL
499 && block->b_fl->fl_type != F_UNLCK) {
500 lock->fl = *block->b_fl;
501 goto conf_lock;
502 }
503 else {
504 nlmsvc_unlink_block(block);
505 return nlm_granted;
506 }
507 }
508 return nlm_drop_reply;
439 } 509 }
440 510
441 return nlm_granted; 511 error = vfs_test_lock(file->f_file, &lock->fl);
512 if (error == -EINPROGRESS)
513 return nlmsvc_defer_lock_rqst(rqstp, block);
514 if (error) {
515 ret = nlm_lck_denied_nolocks;
516 goto out;
517 }
518 if (lock->fl.fl_type == F_UNLCK) {
519 ret = nlm_granted;
520 goto out;
521 }
522
523conf_lock:
524 dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
525 lock->fl.fl_type, (long long)lock->fl.fl_start,
526 (long long)lock->fl.fl_end);
527 conflock->caller = "somehost"; /* FIXME */
528 conflock->len = strlen(conflock->caller);
529 conflock->oh.len = 0; /* don't return OH info */
530 conflock->svid = lock->fl.fl_pid;
531 conflock->fl.fl_type = lock->fl.fl_type;
532 conflock->fl.fl_start = lock->fl.fl_start;
533 conflock->fl.fl_end = lock->fl.fl_end;
534 ret = nlm_lck_denied;
535out:
536 if (block)
537 nlmsvc_release_block(block);
538 return ret;
442} 539}
443 540
444/* 541/*
@@ -464,7 +561,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
464 nlmsvc_cancel_blocked(file, lock); 561 nlmsvc_cancel_blocked(file, lock);
465 562
466 lock->fl.fl_type = F_UNLCK; 563 lock->fl.fl_type = F_UNLCK;
467 error = posix_lock_file(file->f_file, &lock->fl); 564 error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
468 565
469 return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; 566 return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
470} 567}
@@ -493,6 +590,8 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
493 block = nlmsvc_lookup_block(file, lock); 590 block = nlmsvc_lookup_block(file, lock);
494 mutex_unlock(&file->f_mutex); 591 mutex_unlock(&file->f_mutex);
495 if (block != NULL) { 592 if (block != NULL) {
593 vfs_cancel_lock(block->b_file->f_file,
594 &block->b_call->a_args.lock.fl);
496 status = nlmsvc_unlink_block(block); 595 status = nlmsvc_unlink_block(block);
497 nlmsvc_release_block(block); 596 nlmsvc_release_block(block);
498 } 597 }
@@ -500,6 +599,63 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
500} 599}
501 600
502/* 601/*
602 * This is a callback from the filesystem for VFS file lock requests.
603 * It will be used if fl_grant is defined and the filesystem can not
604 * respond to the request immediately.
605 * For GETLK request it will copy the reply to the nlm_block.
606 * For SETLK or SETLKW request it will get the local posix lock.
607 * In all cases it will move the block to the head of nlm_blocked q where
608 * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
609 * deferred rpc for GETLK and SETLK.
610 */
611static void
612nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
613 int result)
614{
615 block->b_flags |= B_GOT_CALLBACK;
616 if (result == 0)
617 block->b_granted = 1;
618 else
619 block->b_flags |= B_TIMED_OUT;
620 if (conf) {
621 if (block->b_fl)
622 locks_copy_lock(block->b_fl, conf);
623 }
624}
625
626static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
627 int result)
628{
629 struct nlm_block *block;
630 int rc = -ENOENT;
631
632 lock_kernel();
633 list_for_each_entry(block, &nlm_blocked, b_list) {
634 if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
635 dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
636 block, block->b_flags);
637 if (block->b_flags & B_QUEUED) {
638 if (block->b_flags & B_TIMED_OUT) {
639 rc = -ENOLCK;
640 break;
641 }
642 nlmsvc_update_deferred_block(block, conf, result);
643 } else if (result == 0)
644 block->b_granted = 1;
645
646 nlmsvc_insert_block(block, 0);
647 svc_wake_up(block->b_daemon);
648 rc = 0;
649 break;
650 }
651 }
652 unlock_kernel();
653 if (rc == -ENOENT)
654 printk(KERN_WARNING "lockd: grant for unknown block\n");
655 return rc;
656}
657
658/*
503 * Unblock a blocked lock request. This is a callback invoked from the 659 * Unblock a blocked lock request. This is a callback invoked from the
504 * VFS layer when a lock on which we blocked is removed. 660 * VFS layer when a lock on which we blocked is removed.
505 * 661 *
@@ -531,6 +687,7 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
531struct lock_manager_operations nlmsvc_lock_operations = { 687struct lock_manager_operations nlmsvc_lock_operations = {
532 .fl_compare_owner = nlmsvc_same_owner, 688 .fl_compare_owner = nlmsvc_same_owner,
533 .fl_notify = nlmsvc_notify_blocked, 689 .fl_notify = nlmsvc_notify_blocked,
690 .fl_grant = nlmsvc_grant_deferred,
534}; 691};
535 692
536/* 693/*
@@ -553,6 +710,8 @@ nlmsvc_grant_blocked(struct nlm_block *block)
553 710
554 dprintk("lockd: grant blocked lock %p\n", block); 711 dprintk("lockd: grant blocked lock %p\n", block);
555 712
713 kref_get(&block->b_count);
714
556 /* Unlink block request from list */ 715 /* Unlink block request from list */
557 nlmsvc_unlink_block(block); 716 nlmsvc_unlink_block(block);
558 717
@@ -566,20 +725,23 @@ nlmsvc_grant_blocked(struct nlm_block *block)
566 725
567 /* Try the lock operation again */ 726 /* Try the lock operation again */
568 lock->fl.fl_flags |= FL_SLEEP; 727 lock->fl.fl_flags |= FL_SLEEP;
569 error = posix_lock_file(file->f_file, &lock->fl); 728 error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
570 lock->fl.fl_flags &= ~FL_SLEEP; 729 lock->fl.fl_flags &= ~FL_SLEEP;
571 730
572 switch (error) { 731 switch (error) {
573 case 0: 732 case 0:
574 break; 733 break;
575 case -EAGAIN: 734 case -EAGAIN:
576 dprintk("lockd: lock still blocked\n"); 735 case -EINPROGRESS:
736 dprintk("lockd: lock still blocked error %d\n", error);
577 nlmsvc_insert_block(block, NLM_NEVER); 737 nlmsvc_insert_block(block, NLM_NEVER);
738 nlmsvc_release_block(block);
578 return; 739 return;
579 default: 740 default:
580 printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", 741 printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
581 -error, __FUNCTION__); 742 -error, __FUNCTION__);
582 nlmsvc_insert_block(block, 10 * HZ); 743 nlmsvc_insert_block(block, 10 * HZ);
744 nlmsvc_release_block(block);
583 return; 745 return;
584 } 746 }
585 747
@@ -592,7 +754,6 @@ callback:
592 nlmsvc_insert_block(block, 30 * HZ); 754 nlmsvc_insert_block(block, 30 * HZ);
593 755
594 /* Call the client */ 756 /* Call the client */
595 kref_get(&block->b_count);
596 nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops); 757 nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops);
597} 758}
598 759
@@ -665,6 +826,23 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
665 nlmsvc_release_block(block); 826 nlmsvc_release_block(block);
666} 827}
667 828
829/* Helper function to handle retry of a deferred block.
830 * If it is a blocking lock, call grant_blocked.
831 * For a non-blocking lock or test lock, revisit the request.
832 */
833static void
834retry_deferred_block(struct nlm_block *block)
835{
836 if (!(block->b_flags & B_GOT_CALLBACK))
837 block->b_flags |= B_TIMED_OUT;
838 nlmsvc_insert_block(block, NLM_TIMEOUT);
839 dprintk("revisit block %p flags %d\n", block, block->b_flags);
840 if (block->b_deferred_req) {
841 block->b_deferred_req->revisit(block->b_deferred_req, 0);
842 block->b_deferred_req = NULL;
843 }
844}
845
668/* 846/*
669 * Retry all blocked locks that have been notified. This is where lockd 847 * Retry all blocked locks that have been notified. This is where lockd
670 * picks up locks that can be granted, or grant notifications that must 848 * picks up locks that can be granted, or grant notifications that must
@@ -688,9 +866,12 @@ nlmsvc_retry_blocked(void)
688 866
689 dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", 867 dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
690 block, block->b_when); 868 block, block->b_when);
691 kref_get(&block->b_count); 869 if (block->b_flags & B_QUEUED) {
692 nlmsvc_grant_blocked(block); 870 dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n",
693 nlmsvc_release_block(block); 871 block, block->b_granted, block->b_flags);
872 retry_deferred_block(block);
873 } else
874 nlmsvc_grant_blocked(block);
694 } 875 }
695 876
696 return timeout; 877 return timeout;