From: Marc Eshel <eshel@xxxxxxxxxxxxxxx> - unquoted 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_TOO_LATE is set. with nlm_granted if B_GOT_CALLBACK is set. by dropping if neither B_TOO_LATE nor B_GOT_CALLBACK is set Signed-off-by: Marc Eshel <eshel@xxxxxxxxxxxxxxx> Signed-off-by: J. Bruce Fields <bfields@xxxxxxxxxxxxxx> --- fs/lockd/svclock.c | 61 ++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 50 insertions(+), 11 deletions(-) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 93f1bc8..91690e3 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -447,6 +447,9 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_lock *lock, struct nlm_lock *conflock, struct nlm_cookie *cookie) { + struct nlm_block *block = NULL; + int error; + dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", file->f_file->f_path.dentry->d_inode->i_sb->s_id, file->f_file->f_path.dentry->d_inode->i_ino, @@ -454,19 +457,55 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); - if (posix_test_lock(file->f_file, &lock->fl, &conflock->fl)) { - dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", - conflock->fl.fl_type, - (long long)conflock->fl.fl_start, - (long long)conflock->fl.fl_end); - conflock->caller = "somehost"; /* FIXME */ - conflock->len = strlen(conflock->caller); - conflock->oh.len = 0; /* don't return OH info */ - conflock->svid = conflock->fl.fl_pid; - return nlm_lck_denied; + /* Get existing block (in case client is busy-waiting) */ + block = nlmsvc_lookup_block(file, lock); + + if (block == NULL) { + block = nlmsvc_create_block(rqstp, file, lock, cookie); + if (block == NULL) + return nlm_granted; + } + if (block->b_flags & B_QUEUED) { + dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n", + block, block->b_flags, block->b_fl); + if (block->b_flags & B_TOO_LATE) { + nlmsvc_unlink_block(block); + return nlm_lck_denied; + } + if (block->b_flags & B_GOT_CALLBACK) { + if (block->b_fl != NULL) { + conflock->fl = *block->b_fl; + goto conf_lock; + } + else { + nlmsvc_unlink_block(block); + return nlm_granted; + } + } + return nlm_drop_reply; } - return nlm_granted; + error = vfs_test_lock(file->f_file, &lock->fl, &conflock->fl); + if (error == -EINPROGRESS) + return nlmsvc_defer_lock_rqst(rqstp, block); + if (error) + return nlm_lck_denied_nolocks; + if (conflock->fl.fl_type == F_UNLCK) { + nlmsvc_unlink_block(block); + return nlm_granted; + } + +conf_lock: + dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", + conflock->fl.fl_type, (long long)conflock->fl.fl_start, + (long long)conflock->fl.fl_end); + conflock->caller = "somehost"; /* FIXME */ + conflock->len = strlen(conflock->caller); + conflock->oh.len = 0; /* don't return OH info */ + conflock->svid = conflock->fl.fl_pid; + if (block) + nlmsvc_unlink_block(block); + return nlm_lck_denied; } /* -- 1.5.0.rc1.g72fe - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html