diff options
| author | Neil Brown <neilb@cse.unsw.edu.au> | 2003-03-14 02:11:42 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-03-14 02:11:42 -0800 |
| commit | 789d95e669710036adc1734938e57ceb3b3d46bb (patch) | |
| tree | eb6a49a118a7dcb56ed3d3ce1d99c94dfa72d698 | |
| parent | 7cb09575b27bd76531b414a947617c0090edc0d8 (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.c | 8 |
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; |
