diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2011-12-09 16:07:55 +0100 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2011-12-09 16:07:55 +0100 |
commit | bfc49cefc4e03dee3888f2a04480c20f56a3fbfa (patch) | |
tree | 1557cb4e57547f10b4d11e5904ee84f9c29678dc | |
parent | 40a47ede7280c023495be97d54b08d60a932f4a7 (diff) | |
download | android_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-- | ChangeLog | 4 | ||||
-rw-r--r-- | lib/fuse.c | 34 |
2 files changed, 35 insertions, 3 deletions
@@ -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 @@ -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; |