LOCKD: Fix a deadlock in nlm_traverse_files()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 8 Sep 2006 00:09:41 +0000 (20:09 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 13 Oct 2006 18:50:10 +0000 (11:50 -0700)
nlm_traverse_files() is not allowed to hold the nlm_file_mutex while calling
nlm_inspect file, since it may end up calling nlm_release_file() when
releaseing the blocks.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
fs/lockd/svcsubs.c

index a570e5c8a930fe6525d8c65e96ebb32f285fbc83..ef9c9539727d7ac77747d1a4c71c645c571587c0 100644 (file)
@@ -238,19 +238,22 @@ static int
 nlm_traverse_files(struct nlm_host *host, int action)
 {
        struct nlm_file *file, **fp;
-       int             i;
+       int i, ret = 0;
 
        mutex_lock(&nlm_file_mutex);
        for (i = 0; i < FILE_NRHASH; i++) {
                fp = nlm_files + i;
                while ((file = *fp) != NULL) {
+                       file->f_count++;
+                       mutex_unlock(&nlm_file_mutex);
+
                        /* Traverse locks, blocks and shares of this file
                         * and update file->f_locks count */
-                       if (nlm_inspect_file(host, file, action)) {
-                               mutex_unlock(&nlm_file_mutex);
-                               return 1;
-                       }
+                       if (nlm_inspect_file(host, file, action))
+                               ret = 1;
 
+                       mutex_lock(&nlm_file_mutex);
+                       file->f_count--;
                        /* No more references to this file. Let go of it. */
                        if (!file->f_blocks && !file->f_locks
                         && !file->f_shares && !file->f_count) {
@@ -263,7 +266,7 @@ nlm_traverse_files(struct nlm_host *host, int action)
                }
        }
        mutex_unlock(&nlm_file_mutex);
-       return 0;
+       return ret;
 }
 
 /*