aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@fieldses.org>2006-01-03 03:55:46 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-01-06 14:58:54 -0500
commit64a318ee2af9000df482d7a125c3b3e1f1007404 (patch)
tree7b39e558cccce484635dc847a016bbcb5e83abdb
parent2c5acd2e1a73cad59203a1bace21e6b03f2920a9 (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>
-rw-r--r--fs/lockd/svclock.c15
-rw-r--r--fs/locks.c7
-rw-r--r--include/linux/fs.h2
3 files changed, 17 insertions, 7 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 */
230static void 230static int
231nlmsvc_delete_block(struct nlm_block *block, int unlock) 231nlmsvc_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
270nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) 273nlmsvc_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
439nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) 443nlmsvc_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/*
diff --git a/fs/locks.c b/fs/locks.c
index 75650d52fe60..fb32d6218e21 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1958,13 +1958,18 @@ EXPORT_SYMBOL(posix_block_lock);
1958 * 1958 *
1959 * lockd needs to block waiting for locks. 1959 * lockd needs to block waiting for locks.
1960 */ 1960 */
1961void 1961int
1962posix_unblock_lock(struct file *filp, struct file_lock *waiter) 1962posix_unblock_lock(struct file *filp, struct file_lock *waiter)
1963{ 1963{
1964 int status = 0;
1965
1964 lock_kernel(); 1966 lock_kernel();
1965 if (waiter->fl_next) 1967 if (waiter->fl_next)
1966 __locks_delete_block(waiter); 1968 __locks_delete_block(waiter);
1969 else
1970 status = -ENOENT;
1967 unlock_kernel(); 1971 unlock_kernel();
1972 return status;
1968} 1973}
1969 1974
1970EXPORT_SYMBOL(posix_unblock_lock); 1975EXPORT_SYMBOL(posix_unblock_lock);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 115e72be25d0..2c9c48d65630 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -760,7 +760,7 @@ extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
760extern int posix_lock_file(struct file *, struct file_lock *); 760extern int posix_lock_file(struct file *, struct file_lock *);
761extern int posix_lock_file_wait(struct file *, struct file_lock *); 761extern int posix_lock_file_wait(struct file *, struct file_lock *);
762extern void posix_block_lock(struct file_lock *, struct file_lock *); 762extern void posix_block_lock(struct file_lock *, struct file_lock *);
763extern void posix_unblock_lock(struct file *, struct file_lock *); 763extern int posix_unblock_lock(struct file *, struct file_lock *);
764extern int posix_locks_deadlock(struct file_lock *, struct file_lock *); 764extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
765extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); 765extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
766extern int __break_lease(struct inode *inode, unsigned int flags); 766extern int __break_lease(struct inode *inode, unsigned int flags);