Patch from Neil Brown 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; _