]> git.hungrycats.org Git - linux/commitdiff
[PATCH] kNFSd: Fix deadlock problem in lockd.
authorNeil Brown <neilb@cse.unsw.edu.au>
Fri, 14 Mar 2003 10:11:42 +0000 (02:11 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Fri, 14 Mar 2003 10:11:42 +0000 (02:11 -0800)
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

index 8a827b109c9370ae09a9b856a2d76424e89ccc9a..dfb16a579c995f68ddfbe221faca821876926bfe 100644 (file)
@@ -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;