aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2011-12-09 16:07:55 +0100
committerMiklos Szeredi <mszeredi@suse.cz>2011-12-09 16:07:55 +0100
commitbfc49cefc4e03dee3888f2a04480c20f56a3fbfa (patch)
tree1557cb4e57547f10b4d11e5904ee84f9c29678dc
parent40a47ede7280c023495be97d54b08d60a932f4a7 (diff)
downloadandroid_external_fuse-bfc49cefc4e03dee3888f2a04480c20f56a3fbfa.tar.gz
android_external_fuse-bfc49cefc4e03dee3888f2a04480c20f56a3fbfa.tar.bz2
android_external_fuse-bfc49cefc4e03dee3888f2a04480c20f56a3fbfa.zip
Fix hang in wait_on_path()
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.
-rw-r--r--ChangeLog4
-rw-r--r--lib/fuse.c34
2 files changed, 35 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 828a181..ba1f5e2 100644
--- 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
diff --git a/lib/fuse.c b/lib/fuse.c
index 7f421b4..9073daf 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -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;