aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Eshel <eshel@almaden.ibm.com>2006-11-28 16:27:06 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2007-05-06 20:38:50 -0400
commit5ea0d75037b93baa453b4d326c6319968fe91cea (patch)
tree661d15750a689daec2dca0f81a16c75a930df741
parent85f3f1b3f7a6197b51a2ab98d927517df730214c (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.c2
-rw-r--r--fs/lockd/svclock.c84
-rw-r--r--fs/lockd/svcproc.c3
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 */
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 */
@@ -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; 509conf_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;
521out:
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);