diff options
author | Marc Eshel <eshel@almaden.ibm.com> | 2006-11-28 16:27:06 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2007-05-06 20:38:50 -0400 |
commit | 5ea0d75037b93baa453b4d326c6319968fe91cea (patch) | |
tree | 661d15750a689daec2dca0f81a16c75a930df741 | |
parent | 85f3f1b3f7a6197b51a2ab98d927517df730214c (diff) |
lockd: handle test_lock deferrals
Rewrite nlmsvc_testlock() to use the new asynchronous interface: instead of
immediately doing a posix_test_lock(), we first look for a matching block.
If the subsequent test_lock returns anything other than -EINPROGRESS, we
then remove the block we've found and return the results.
If it returns -EINPROGRESS, then we defer the lock request.
In the case where the block we find in the first step has B_QUEUED set,
we bypass the vfs_test_lock entirely, instead using the block to decide how
to respond:
with nlm_lck_denied if B_TIMED_OUT is set.
with nlm_granted if B_GOT_CALLBACK is set.
by dropping if neither B_TIMED_OUT nor B_GOT_CALLBACK is set
Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | fs/lockd/svc4proc.c | 2 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 84 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 3 |
3 files changed, 73 insertions, 16 deletions
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index a1bccad7ebd3..205d8befbf1b 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -100,6 +100,8 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
100 | 100 | ||
101 | /* Now check for conflicting locks */ | 101 | /* Now check for conflicting locks */ |
102 | resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie); | 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); |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 7ab2e60c51f7..b7a8174fd1dc 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 */ |
@@ -446,6 +447,10 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, | |||
446 | struct nlm_lock *lock, struct nlm_lock *conflock, | 447 | struct nlm_lock *lock, struct nlm_lock *conflock, |
447 | struct nlm_cookie *cookie) | 448 | struct nlm_cookie *cookie) |
448 | { | 449 | { |
450 | struct nlm_block *block = NULL; | ||
451 | int error; | ||
452 | __be32 ret; | ||
453 | |||
449 | dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", | 454 | dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", |
450 | file->f_file->f_path.dentry->d_inode->i_sb->s_id, | 455 | file->f_file->f_path.dentry->d_inode->i_sb->s_id, |
451 | file->f_file->f_path.dentry->d_inode->i_ino, | 456 | file->f_file->f_path.dentry->d_inode->i_ino, |
@@ -453,22 +458,70 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, | |||
453 | (long long)lock->fl.fl_start, | 458 | (long long)lock->fl.fl_start, |
454 | (long long)lock->fl.fl_end); | 459 | (long long)lock->fl.fl_end); |
455 | 460 | ||
456 | if (posix_test_lock(file->f_file, &lock->fl)) { | 461 | /* Get existing block (in case client is busy-waiting) */ |
457 | dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", | 462 | block = nlmsvc_lookup_block(file, lock); |
458 | lock->fl.fl_type, | 463 | |
459 | (long long)lock->fl.fl_start, | 464 | if (block == NULL) { |
460 | (long long)lock->fl.fl_end); | 465 | struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL); |
461 | conflock->caller = "somehost"; /* FIXME */ | 466 | |
462 | conflock->len = strlen(conflock->caller); | 467 | if (conf == NULL) |
463 | conflock->oh.len = 0; /* don't return OH info */ | 468 | return nlm_granted; |
464 | conflock->svid = lock->fl.fl_pid; | 469 | block = nlmsvc_create_block(rqstp, file, lock, cookie); |
465 | conflock->fl.fl_type = lock->fl.fl_type; | 470 | if (block == NULL) { |
466 | conflock->fl.fl_start = lock->fl.fl_start; | 471 | kfree(conf); |
467 | conflock->fl.fl_end = lock->fl.fl_end; | 472 | return nlm_granted; |
468 | return nlm_lck_denied; | 473 | } |
474 | block->b_fl = conf; | ||
475 | } | ||
476 | if (block->b_flags & B_QUEUED) { | ||
477 | dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n", | ||
478 | block, block->b_flags, block->b_fl); | ||
479 | if (block->b_flags & B_TIMED_OUT) { | ||
480 | nlmsvc_unlink_block(block); | ||
481 | return nlm_lck_denied; | ||
482 | } | ||
483 | if (block->b_flags & B_GOT_CALLBACK) { | ||
484 | if (block->b_fl != NULL | ||
485 | && block->b_fl->fl_type != F_UNLCK) { | ||
486 | lock->fl = *block->b_fl; | ||
487 | goto conf_lock; | ||
488 | } | ||
489 | else { | ||
490 | nlmsvc_unlink_block(block); | ||
491 | return nlm_granted; | ||
492 | } | ||
493 | } | ||
494 | return nlm_drop_reply; | ||
495 | } | ||
496 | |||
497 | error = vfs_test_lock(file->f_file, &lock->fl); | ||
498 | if (error == -EINPROGRESS) | ||
499 | return nlmsvc_defer_lock_rqst(rqstp, block); | ||
500 | if (error) { | ||
501 | ret = nlm_lck_denied_nolocks; | ||
502 | goto out; | ||
503 | } | ||
504 | if (lock->fl.fl_type == F_UNLCK) { | ||
505 | ret = nlm_granted; | ||
506 | goto out; | ||
469 | } | 507 | } |
470 | 508 | ||
471 | return nlm_granted; | 509 | conf_lock: |
510 | dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", | ||
511 | lock->fl.fl_type, (long long)lock->fl.fl_start, | ||
512 | (long long)lock->fl.fl_end); | ||
513 | conflock->caller = "somehost"; /* FIXME */ | ||
514 | conflock->len = strlen(conflock->caller); | ||
515 | conflock->oh.len = 0; /* don't return OH info */ | ||
516 | conflock->svid = lock->fl.fl_pid; | ||
517 | conflock->fl.fl_type = lock->fl.fl_type; | ||
518 | conflock->fl.fl_start = lock->fl.fl_start; | ||
519 | conflock->fl.fl_end = lock->fl.fl_end; | ||
520 | ret = nlm_lck_denied; | ||
521 | out: | ||
522 | if (block) | ||
523 | nlmsvc_release_block(block); | ||
524 | return ret; | ||
472 | } | 525 | } |
473 | 526 | ||
474 | /* | 527 | /* |
@@ -549,7 +602,6 @@ nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf, | |||
549 | else | 602 | else |
550 | block->b_flags |= B_TIMED_OUT; | 603 | block->b_flags |= B_TIMED_OUT; |
551 | if (conf) { | 604 | if (conf) { |
552 | block->b_fl = kzalloc(sizeof(struct file_lock), GFP_KERNEL); | ||
553 | if (block->b_fl) | 605 | if (block->b_fl) |
554 | locks_copy_lock(block->b_fl, conf); | 606 | locks_copy_lock(block->b_fl, conf); |
555 | } | 607 | } |
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index d13b827dfd34..40b5cf496b51 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; |
@@ -128,6 +129,8 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
128 | 129 | ||
129 | /* Now check for conflicting locks */ | 130 | /* Now check for conflicting locks */ |
130 | resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie)); | 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); |