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 47a66aa5d5..bf27b6c6cb 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 cf51f849e7..b3efa4536c 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 31cb484257..9cd5c8b375 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 c0df00c74c..84ebba33b9 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; |
