Fix hang in wait_on_path()
authorMiklos Szeredi <mszeredi@suse.cz>
Fri, 9 Dec 2011 15:07:55 +0000 (16:07 +0100)
committerMiklos Szeredi <mszeredi@suse.cz>
Fri, 9 Dec 2011 15:07:55 +0000 (16:07 +0100)
Ville Silventoinen reported that fs_racer in LTP triggered a hang in
wait_on_path().  This bug was caused by try_get_path() not resetting "ticket" on
permanent failure.

ChangeLog
lib/fuse.c

index 828a18196845e3ef1ed86cc865ec47f6e650be2d..ba1f5e27d70076d62c40284b27b7aa72e3ea68b2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2011-12-09  Miklos Szeredi <miklos@szeredi.hu>
+
+       * Fix hang in wait_on_path().  Reported by Ville Silventoinen
+
 2011-12-08  Miklos Szeredi <miklos@szeredi.hu>
 
        * Fix build if FUSE_NODE_SLAB is not defined.  Patch by Emmanuel
index 7f421b41f938fac9b40ba826fbe0f1b86badcccd..9073daf6b60522472303231d85bcf55d1171fe6a 100644 (file)
@@ -912,6 +912,26 @@ static void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode,
        }
 }
 
+static void release_tickets(struct fuse *f, fuse_ino_t nodeid,
+                           struct node *wnode, int ticket)
+{
+       struct node *node;
+
+       if (wnode) {
+               if (wnode->ticket != ticket)
+                       return;
+
+               wnode->ticket = 0;
+       }
+
+       for (node = get_node(f, nodeid);
+            node->nodeid != FUSE_ROOT_ID; node = node->parent) {
+               if (node->ticket != ticket)
+                       return;
+               node->ticket = 0;
+       }
+}
+
 static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
                        char **path, struct node **wnodep, int ticket)
 {
@@ -924,9 +944,10 @@ static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
 
        *path = NULL;
 
+       err = -ENOMEM;
        buf = malloc(bufsize);
        if (buf == NULL)
-               return -ENOMEM;
+               goto out_err;
 
        s = buf + bufsize - 1;
        *s = '\0';
@@ -993,6 +1014,10 @@ static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
  out_free:
        free(buf);
 
+ out_err:
+       if (ticket && err != -EAGAIN)
+               release_tickets(f, nodeid, wnode, ticket);
+
        return err;
 }
 
@@ -1133,9 +1158,12 @@ static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1,
        if (!err) {
                err = try_get_path(f, nodeid2, name2, path2, wnode2, ticket);
                if (err) {
-                       unlock_path(f, nodeid1, wnode1 ? *wnode1 : NULL, NULL,
-                                   ticket);
+                       struct node *wn1 = wnode1 ? *wnode1 : NULL;
+
+                       unlock_path(f, nodeid1, wn1, NULL, ticket);
                        free(path1);
+                       if (ticket && err != -EAGAIN)
+                               release_tickets(f, nodeid1, wn1, ticket);
                }
        }
        return err;