diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:34:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:34:24 -0400 |
commit | 2d56d3c43cc97ae48586745556f5a5b564d61582 (patch) | |
tree | 28f2edc1e69b79e94d99023041dd0358861b6956 /fs/lockd | |
parent | 0f9008ef38d5a6305d94bbdd8f20d68fc75c63b6 (diff) | |
parent | 586759f03e2e9031ac5589912a51a909ed53c30a (diff) |
Merge branch 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux
* 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux:
gfs2: nfs lock support for gfs2
lockd: add code to handle deferred lock requests
lockd: always preallocate block in nlmsvc_lock()
lockd: handle test_lock deferrals
lockd: pass cookie in nlmsvc_testlock
lockd: handle fl_grant callbacks
lockd: save lock state on deferral
locks: add fl_grant callback for asynchronous lock return
nfsd4: Convert NFSv4 to new lock interface
locks: add lock cancel command
locks: allow {vfs,posix}_lock_file to return conflicting lock
locks: factor out generic/filesystem switch from setlock code
locks: factor out generic/filesystem switch from test_lock
locks: give posix_test_lock same interface as ->lock
locks: make ->lock release private data before returning in GETLK case
locks: create posix-to-flock helper functions
locks: trivial removal of unnecessary parentheses
Diffstat (limited to 'fs/lockd')
-rw-r--r-- | fs/lockd/svc4proc.c | 6 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 275 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 7 | ||||
-rw-r--r-- | fs/lockd/svcsubs.c | 2 |
4 files changed, 240 insertions, 50 deletions
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 47a66aa5d55b..bf27b6c6cb6b 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -99,7 +99,9 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
99 | return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; | 99 | return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; |
100 | 100 | ||
101 | /* Now check for conflicting locks */ | 101 | /* Now check for conflicting locks */ |
102 | resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock); | 102 | resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie); |
103 | if (resp->status == nlm_drop_reply) | ||
104 | return rpc_drop_reply; | ||
103 | 105 | ||
104 | dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); | 106 | dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); |
105 | nlm_release_host(host); | 107 | nlm_release_host(host); |
@@ -143,6 +145,8 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
143 | /* Now try to lock the file */ | 145 | /* Now try to lock the file */ |
144 | resp->status = nlmsvc_lock(rqstp, file, &argp->lock, | 146 | resp->status = nlmsvc_lock(rqstp, file, &argp->lock, |
145 | argp->block, &argp->cookie); | 147 | argp->block, &argp->cookie); |
148 | if (resp->status == nlm_drop_reply) | ||
149 | return rpc_drop_reply; | ||
146 | 150 | ||
147 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); | 151 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); |
148 | nlm_release_host(host); | 152 | nlm_release_host(host); |
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 | */ |
174 | static inline struct nlm_block * | 174 | static inline struct nlm_block * |
175 | nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | 175 | nlmsvc_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 | */ | ||
338 | static u32 | ||
339 | nlmsvc_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 | |||
338 | nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, | 365 | nlmsvc_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; | ||
355 | again: | ||
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); |
407 | out: | 449 | out: |
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 |
419 | nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, | 460 | nlmsvc_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 | |||
523 | conf_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; | ||
535 | out: | ||
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 | */ | ||
611 | static void | ||
612 | nlmsvc_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 | |||
626 | static 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) | |||
531 | struct lock_manager_operations nlmsvc_lock_operations = { | 687 | struct 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 | */ | ||
833 | static void | ||
834 | retry_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; |
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 31cb48425733..9cd5c8b37593 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
@@ -33,6 +33,7 @@ cast_to_nlm(__be32 status, u32 vers) | |||
33 | case nlm_lck_denied_nolocks: | 33 | case nlm_lck_denied_nolocks: |
34 | case nlm_lck_blocked: | 34 | case nlm_lck_blocked: |
35 | case nlm_lck_denied_grace_period: | 35 | case nlm_lck_denied_grace_period: |
36 | case nlm_drop_reply: | ||
36 | break; | 37 | break; |
37 | case nlm4_deadlock: | 38 | case nlm4_deadlock: |
38 | status = nlm_lck_denied; | 39 | status = nlm_lck_denied; |
@@ -127,7 +128,9 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
127 | return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; | 128 | return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; |
128 | 129 | ||
129 | /* Now check for conflicting locks */ | 130 | /* Now check for conflicting locks */ |
130 | resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock)); | 131 | resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie)); |
132 | if (resp->status == nlm_drop_reply) | ||
133 | return rpc_drop_reply; | ||
131 | 134 | ||
132 | dprintk("lockd: TEST status %d vers %d\n", | 135 | dprintk("lockd: TEST status %d vers %d\n", |
133 | ntohl(resp->status), rqstp->rq_vers); | 136 | ntohl(resp->status), rqstp->rq_vers); |
@@ -172,6 +175,8 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
172 | /* Now try to lock the file */ | 175 | /* Now try to lock the file */ |
173 | resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock, | 176 | resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock, |
174 | argp->block, &argp->cookie)); | 177 | argp->block, &argp->cookie)); |
178 | if (resp->status == nlm_drop_reply) | ||
179 | return rpc_drop_reply; | ||
175 | 180 | ||
176 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); | 181 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); |
177 | nlm_release_host(host); | 182 | nlm_release_host(host); |
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index c0df00c74ce3..84ebba33b98d 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -182,7 +182,7 @@ again: | |||
182 | lock.fl_type = F_UNLCK; | 182 | lock.fl_type = F_UNLCK; |
183 | lock.fl_start = 0; | 183 | lock.fl_start = 0; |
184 | lock.fl_end = OFFSET_MAX; | 184 | lock.fl_end = OFFSET_MAX; |
185 | if (posix_lock_file(file->f_file, &lock) < 0) { | 185 | if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) { |
186 | printk("lockd: unlock failure in %s:%d\n", | 186 | printk("lockd: unlock failure in %s:%d\n", |
187 | __FILE__, __LINE__); | 187 | __FILE__, __LINE__); |
188 | return 1; | 188 | return 1; |