From 963d8fe53339128ee46a7701f2e36305f0ccff8c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 3 Jan 2006 09:55:04 +0100 Subject: RPC: Clean up RPC task structure Shrink the RPC task structure. Instead of storing separate pointers for task->tk_exit and task->tk_release, put them in a structure. Also pass the user data pointer as a parameter instead of passing it via task->tk_calldata. This enables us to nest callbacks. Signed-off-by: Trond Myklebust --- fs/lockd/svclock.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'fs/lockd/svclock.c') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 49f959796b66..87d09a0d8f64 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -41,7 +41,8 @@ static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); static int nlmsvc_remove_block(struct nlm_block *block); -static void nlmsvc_grant_callback(struct rpc_task *task); + +static const struct rpc_call_ops nlmsvc_grant_ops; /* * The list of blocked locks to retry @@ -562,7 +563,7 @@ callback: /* Call the client */ nlm_get_host(block->b_call.a_host); if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG, - nlmsvc_grant_callback) < 0) + &nlmsvc_grant_ops) < 0) nlm_release_host(block->b_call.a_host); up(&file->f_sema); } @@ -575,10 +576,9 @@ callback: * chain once more in order to have it removed by lockd itself (which can * then sleep on the file semaphore without disrupting e.g. the nfs client). */ -static void -nlmsvc_grant_callback(struct rpc_task *task) +static void nlmsvc_grant_callback(struct rpc_task *task, void *data) { - struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; + struct nlm_rqst *call = data; struct nlm_block *block; unsigned long timeout; struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client); @@ -614,6 +614,10 @@ nlmsvc_grant_callback(struct rpc_task *task) nlm_release_host(call->a_host); } +static const struct rpc_call_ops nlmsvc_grant_ops = { + .rpc_call_done = nlmsvc_grant_callback, +}; + /* * We received a GRANT_RES callback. Try to find the corresponding * block. -- cgit v1.2.1 From f232142cc21127c829559923eb405d1bcb2e2278 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 3 Jan 2006 09:55:42 +0100 Subject: NLM: Clean up nlmsvc_grant_reply locking Slightly simpler logic here makes it more trivial to verify that the up's and down's are balanced here. Break out an assignment from a conditional while we're at it. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- fs/lockd/svclock.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'fs/lockd/svclock.c') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 87d09a0d8f64..e42f0cc6c450 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -637,11 +637,12 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status file->f_count++; down(&file->f_sema); - if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) { + block = nlmsvc_find_block(cookie, &rqstp->rq_addr); + if (block) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) { /* Try again in a couple of seconds */ nlmsvc_insert_block(block, 10 * HZ); - block = NULL; + up(&file->f_sema); } else { /* Lock is now held by client, or has been rejected. * In both cases, the block should be removed. */ @@ -652,8 +653,6 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status nlmsvc_delete_block(block, 1); } } - if (!block) - up(&file->f_sema); nlm_release_file(file); } -- cgit v1.2.1 From 5996a298da43a03081e9ba2116983d173001c862 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 3 Jan 2006 09:55:44 +0100 Subject: NLM: don't unlock on cancel requests Currently when lockd gets an NLM_CANCEL request, it also does an unlock for the same range. This is incorrect. The Open Group documentation says that "This procedure cancels an *outstanding* blocked lock request." (Emphasis mine.) Also, consider a client that holds a lock on the first byte of a file, and requests a lock on the entire file. If the client cancels that request (perhaps because the requesting process is signalled), the server shouldn't apply perform an unlock on the entire file, since that will also remove the previous lock that the client was already granted. Or consider a lock request that actually *downgraded* an exclusive lock to a shared lock. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- fs/lockd/svclock.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'fs/lockd/svclock.c') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index e42f0cc6c450..5fb48b4390bd 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -240,11 +240,6 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock) nlmsvc_remove_block(block); if (fl->fl_next) posix_unblock_lock(file->f_file, fl); - if (unlock) { - fl->fl_type = F_UNLCK; - posix_lock_file(file->f_file, fl); - block->b_granted = 0; - } /* If the block is in the middle of a GRANT callback, * don't kill it yet. */ -- cgit v1.2.1 From 2c5acd2e1a73cad59203a1bace21e6b03f2920a9 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 3 Jan 2006 09:55:45 +0100 Subject: NLM: clean up nlmsvc_delete_block The fl_next check here is superfluous (and possibly a layering violation). Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- fs/lockd/svclock.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs/lockd/svclock.c') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 5fb48b4390bd..b56d439bad82 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -238,8 +238,7 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock) /* Remove block from list */ nlmsvc_remove_block(block); - if (fl->fl_next) - posix_unblock_lock(file->f_file, fl); + posix_unblock_lock(file->f_file, fl); /* If the block is in the middle of a GRANT callback, * don't kill it yet. */ -- cgit v1.2.1 From 64a318ee2af9000df482d7a125c3b3e1f1007404 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 3 Jan 2006 09:55:46 +0100 Subject: NLM: Further cancel fixes If the server receives an NLM cancel call and finds no waiting lock to cancel, then chances are the lock has already been applied, and the client just hadn't yet processed the NLM granted callback before it sent the cancel. The Open Group text, for example, perimts a server to return either success (LCK_GRANTED) or failure (LCK_DENIED) in this case. But returning an error seems more helpful; the client may be able to use it to recognize that a race has occurred and to recover from the race. So, modify the relevant functions to return an error in this case. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- fs/lockd/svclock.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'fs/lockd/svclock.c') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index b56d439bad82..9cfced65d4a2 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -227,25 +227,27 @@ failed: * It is the caller's responsibility to check whether the file * can be closed hereafter. */ -static void +static int nlmsvc_delete_block(struct nlm_block *block, int unlock) { struct file_lock *fl = &block->b_call.a_args.lock.fl; struct nlm_file *file = block->b_file; struct nlm_block **bp; + int status = 0; dprintk("lockd: deleting block %p...\n", block); /* Remove block from list */ nlmsvc_remove_block(block); - posix_unblock_lock(file->f_file, fl); + if (unlock) + status = posix_unblock_lock(file->f_file, fl); /* If the block is in the middle of a GRANT callback, * don't kill it yet. */ if (block->b_incall) { nlmsvc_insert_block(block, NLM_NEVER); block->b_done = 1; - return; + return status; } /* Remove block from file's list of blocks */ @@ -260,6 +262,7 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock) nlm_release_host(block->b_host); nlmclnt_freegrantargs(&block->b_call); kfree(block); + return status; } /* @@ -270,6 +273,7 @@ int nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) { struct nlm_block *block, *next; + /* XXX: Will everything get cleaned up if we don't unlock here? */ down(&file->f_sema); for (block = file->f_blocks; block; block = next) { @@ -439,6 +443,7 @@ u32 nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) { struct nlm_block *block; + int status = 0; dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", file->f_file->f_dentry->d_inode->i_sb->s_id, @@ -449,9 +454,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) down(&file->f_sema); if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) - nlmsvc_delete_block(block, 1); + status = nlmsvc_delete_block(block, 1); up(&file->f_sema); - return nlm_granted; + return status ? nlm_lck_denied : nlm_granted; } /* -- cgit v1.2.1