diff options
author | J. Bruce Fields <bfields@fieldses.org> | 2006-01-03 03:55:46 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-06 14:58:54 -0500 |
commit | 64a318ee2af9000df482d7a125c3b3e1f1007404 (patch) | |
tree | 7b39e558cccce484635dc847a016bbcb5e83abdb /fs/lockd | |
parent | 2c5acd2e1a73cad59203a1bace21e6b03f2920a9 (diff) |
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 <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/lockd')
-rw-r--r-- | fs/lockd/svclock.c | 15 |
1 files changed, 10 insertions, 5 deletions
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: | |||
227 | * It is the caller's responsibility to check whether the file | 227 | * It is the caller's responsibility to check whether the file |
228 | * can be closed hereafter. | 228 | * can be closed hereafter. |
229 | */ | 229 | */ |
230 | static void | 230 | static int |
231 | nlmsvc_delete_block(struct nlm_block *block, int unlock) | 231 | nlmsvc_delete_block(struct nlm_block *block, int unlock) |
232 | { | 232 | { |
233 | struct file_lock *fl = &block->b_call.a_args.lock.fl; | 233 | struct file_lock *fl = &block->b_call.a_args.lock.fl; |
234 | struct nlm_file *file = block->b_file; | 234 | struct nlm_file *file = block->b_file; |
235 | struct nlm_block **bp; | 235 | struct nlm_block **bp; |
236 | int status = 0; | ||
236 | 237 | ||
237 | dprintk("lockd: deleting block %p...\n", block); | 238 | dprintk("lockd: deleting block %p...\n", block); |
238 | 239 | ||
239 | /* Remove block from list */ | 240 | /* Remove block from list */ |
240 | nlmsvc_remove_block(block); | 241 | nlmsvc_remove_block(block); |
241 | posix_unblock_lock(file->f_file, fl); | 242 | if (unlock) |
243 | status = posix_unblock_lock(file->f_file, fl); | ||
242 | 244 | ||
243 | /* If the block is in the middle of a GRANT callback, | 245 | /* If the block is in the middle of a GRANT callback, |
244 | * don't kill it yet. */ | 246 | * don't kill it yet. */ |
245 | if (block->b_incall) { | 247 | if (block->b_incall) { |
246 | nlmsvc_insert_block(block, NLM_NEVER); | 248 | nlmsvc_insert_block(block, NLM_NEVER); |
247 | block->b_done = 1; | 249 | block->b_done = 1; |
248 | return; | 250 | return status; |
249 | } | 251 | } |
250 | 252 | ||
251 | /* Remove block from file's list of blocks */ | 253 | /* Remove block from file's list of blocks */ |
@@ -260,6 +262,7 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock) | |||
260 | nlm_release_host(block->b_host); | 262 | nlm_release_host(block->b_host); |
261 | nlmclnt_freegrantargs(&block->b_call); | 263 | nlmclnt_freegrantargs(&block->b_call); |
262 | kfree(block); | 264 | kfree(block); |
265 | return status; | ||
263 | } | 266 | } |
264 | 267 | ||
265 | /* | 268 | /* |
@@ -270,6 +273,7 @@ int | |||
270 | nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) | 273 | nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) |
271 | { | 274 | { |
272 | struct nlm_block *block, *next; | 275 | struct nlm_block *block, *next; |
276 | /* XXX: Will everything get cleaned up if we don't unlock here? */ | ||
273 | 277 | ||
274 | down(&file->f_sema); | 278 | down(&file->f_sema); |
275 | for (block = file->f_blocks; block; block = next) { | 279 | for (block = file->f_blocks; block; block = next) { |
@@ -439,6 +443,7 @@ u32 | |||
439 | nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | 443 | nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) |
440 | { | 444 | { |
441 | struct nlm_block *block; | 445 | struct nlm_block *block; |
446 | int status = 0; | ||
442 | 447 | ||
443 | dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", | 448 | dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", |
444 | file->f_file->f_dentry->d_inode->i_sb->s_id, | 449 | 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) | |||
449 | 454 | ||
450 | down(&file->f_sema); | 455 | down(&file->f_sema); |
451 | if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) | 456 | if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) |
452 | nlmsvc_delete_block(block, 1); | 457 | status = nlmsvc_delete_block(block, 1); |
453 | up(&file->f_sema); | 458 | up(&file->f_sema); |
454 | return nlm_granted; | 459 | return status ? nlm_lck_denied : nlm_granted; |
455 | } | 460 | } |
456 | 461 | ||
457 | /* | 462 | /* |