summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Brown <neilb@cse.unsw.edu.au>2003-03-14 02:11:42 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2003-03-14 02:11:42 -0800
commit789d95e669710036adc1734938e57ceb3b3d46bb (patch)
treeeb6a49a118a7dcb56ed3d3ce1d99c94dfa72d698
parent7cb09575b27bd76531b414a947617c0090edc0d8 (diff)
[PATCH] kNFSd: Fix deadlock problem in lockd.
nlmsvc_lock calls nlmsvc_create_block with file->f_sema held. nlmsvc_create_block calls nlmclnt_lookup_host which might call nlm_gc_hosts which might, eventually, try to claim file->f_sema for the same file -> deadlock. nlmsvc_create_block does not need any protection under any lock as lockd is single-threaded and _create_block only plays with internal data structures. So we release the f_sema before calling in, and make sure it gets claimed again afterwards.
-rw-r--r--fs/lockd/svclock.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 8a827b109c93..dfb16a579c99 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -305,8 +305,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
(long long)lock->fl.fl_end,
wait);
- /* Lock file against concurrent access */
- down(&file->f_sema);
/* Get existing block (in case client is busy-waiting) */
block = nlmsvc_lookup_block(file, lock, 0);
@@ -314,6 +312,9 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
lock->fl.fl_flags |= FL_LOCKD;
again:
+ /* Lock file against concurrent access */
+ down(&file->f_sema);
+
if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
error = posix_lock_file(&file->f_file, &lock->fl);
@@ -346,7 +347,10 @@ again:
/* If we don't have a block, create and initialize it. Then
* retry because we may have slept in kmalloc. */
+ /* We have to release f_sema as nlmsvc_create_block may try to
+ * to claim it while doing host garbage collection */
if (block == NULL) {
+ up(&file->f_sema);
dprintk("lockd: blocking on this lock (allocating).\n");
if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
return nlm_lck_denied_nolocks;