Patch from Neil Brown <neilb@cse.unsw.edu.au>

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.



 fs/lockd/svclock.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff -puN fs/lockd/svclock.c~lockd-lockup-fix-2 fs/lockd/svclock.c
--- 25/fs/lockd/svclock.c~lockd-lockup-fix-2	2003-02-25 20:02:34.000000000 -0800
+++ 25-akpm/fs/lockd/svclock.c	2003-02-25 20:02:34.000000000 -0800
@@ -305,8 +305,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, stru
 				(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, stru
 	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;

_