From: Neil Brown Date: Fri, 14 Mar 2003 10:11:42 +0000 (-0800) Subject: [PATCH] kNFSd: Fix deadlock problem in lockd. X-Git-Tag: v2.5.65~39^2^2~3^2^2~4 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=789d95e669710036adc1734938e57ceb3b3d46bb;p=history.git [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. --- 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;