From: Bargav Y. <by...@gm...> - 2007-11-14 04:33:49
|
Hi Miklos, so far the patch is doing good and certainly doing its intent. Should I be worried about the " /* FIXME: locking two paths needs deadlock checking */" comment in get_path2? On 11/13/07, Miklos Szeredi <mi...@sz...> wrote: > Sure. > > Index: fuse/lib/fuse.c > =================================================================== > --- fuse.orig/lib/fuse.c 2007-10-08 19:42:55.000000000 +0200 > +++ fuse/lib/fuse.c 2007-10-08 20:21:24.000000000 +0200 > @@ -86,10 +86,10 @@ struct fuse { > unsigned int generation; > unsigned int hidectr; > pthread_mutex_t lock; > - pthread_rwlock_t tree_lock; > struct fuse_config conf; > int intr_installed; > struct fuse_fs *fs; > + pthread_cond_t treecond; > }; > > struct lock { > @@ -111,12 +111,13 @@ struct node { > char *name; > uint64_t nlookup; > int open_count; > - int is_hidden; > struct timespec stat_updated; > struct timespec mtime; > off_t size; > - int cache_valid; > struct lock *locks; > + unsigned int is_hidden : 1; > + unsigned int cache_valid : 1; > + int treelock; > }; > > struct fuse_dh { > @@ -351,6 +352,7 @@ static void delete_node(struct fuse *f, > if (f->conf.debug) > fprintf(stderr, "delete: %llu\n", (unsigned long long) node->nodeid); > > + assert(node->treelock == 0); > assert(!node->name); > unhash_id(f, node); > free_node(node); > @@ -402,9 +404,10 @@ static struct node *find_node(struct fus > > node->refctr = 1; > node->nodeid = next_id(f); > + node->generation = f->generation; > node->open_count = 0; > node->is_hidden = 0; > - node->generation = f->generation; > + node->treelock = 0; > if (hash_name(f, node, parent, name) == -1) { > free(node); > node = NULL; > @@ -433,45 +436,181 @@ static char *add_name(char *buf, char *s > return s; > } > > -static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name) > +static void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode, > + struct node *end) > +{ > + struct node *node; > + > + if (wnode) { > + assert(wnode->treelock == -1); > + wnode->treelock = 0; > + } > + > + for (node = get_node(f, nodeid); > + node != end && node->nodeid != FUSE_ROOT_ID; > + node = node->parent) { > + assert(node->treelock > 0); > + node->treelock--; > + } > +} > + > +static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name, > + int lock, char **path, struct node **wnodep) > { > char buf[FUSE_MAX_PATH]; > char *s = buf + FUSE_MAX_PATH - 1; > struct node *node; > + struct node *wnode = NULL; > + int err; > > *s = '\0'; > > if (name != NULL) { > s = add_name(buf, s, name); > if (s == NULL) > - return NULL; > + return -ENAMETOOLONG; > } > > - pthread_mutex_lock(&f->lock); > - for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID; > + if (wnodep) { > + assert(lock); > + wnode = lookup_node(f, nodeid, name); > + if (wnode) { > + if (wnode->treelock != 0) > + return -EAGAIN; > + > + wnode->treelock = -1; > + } > + } > + > + err = 0; > + for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID; > node = node->parent) { > - if (node->name == NULL) { > - s = NULL; > + err = -ENOENT; > + if (node->name == NULL || node->parent == NULL) > break; > - } > > + err = -ENAMETOOLONG; > s = add_name(buf, s, node->name); > if (s == NULL) > break; > + > + if (lock) { > + err = -EAGAIN; > + if (node->treelock == -1) > + break; > + node->treelock++; > + } > + err = 0; > + } > + > + if (!err) { > + s = strdup(s[0] ? s : "/"); > + if (s != NULL) > + *path = s; > + else > + err = -ENOMEM; > + } > + > + if (err && lock) > + unlock_path(f, nodeid, wnode, node); > + > + if (wnodep && !err) > + *wnodep = wnode; > + > + return err; > +} > + > +static int get_path_common(struct fuse *f, fuse_ino_t nodeid, const char *name, > + char **path, struct node **wnode) > +{ > + int err; > + > + pthread_mutex_lock(&f->lock); > + while (1) { > + err = try_get_path(f, nodeid, name, 1, path, wnode); > + if (err != -EAGAIN) > + break; > + > + pthread_cond_wait(&f->treecond, &f->lock); > } > pthread_mutex_unlock(&f->lock); > > - if (node == NULL || s == NULL) > - return NULL; > - else if (*s == '\0') > - return strdup("/"); > - else > - return strdup(s); > + return err; > +} > + > +static int get_path(struct fuse *f, fuse_ino_t nodeid, char **path) > +{ > + return get_path_common(f, nodeid, NULL, path, NULL); > } > > -static char *get_path(struct fuse *f, fuse_ino_t nodeid) > +static int get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name, > + char **path) > { > - return get_path_name(f, nodeid, NULL); > + return get_path_common(f, nodeid, name, path, NULL); > +} > + > +static int get_path_wrlock(struct fuse *f, fuse_ino_t nodeid, const char *name, > + char **path, struct node **wnode) > +{ > + return get_path_common(f, nodeid, name, path, wnode); > +} > + > +static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, > + fuse_ino_t nodeid2, const char *name2, > + char **path1, char **path2, > + struct node **wnode1, struct node **wnode2) > +{ > + int err; > + > + pthread_mutex_lock(&f->lock); > + while (1) { > + char *tmppath; > + > + /* FIXME: locking two paths needs deadlock checking */ > + err = try_get_path(f, nodeid1, name1, 1, &tmppath, wnode1); > + if (!err) { > + err = try_get_path(f, nodeid2, name2, 1, path2, wnode2); > + if (!err) > + *path1 = tmppath; > + else > + unlock_path(f, nodeid1, wnode1 ? *wnode1 : NULL, NULL); > + } > + if (err != -EAGAIN) > + break; > + > + pthread_cond_wait(&f->treecond, &f->lock); > + } > + pthread_mutex_unlock(&f->lock); > + > + return err; > +} > + > +static void free_path_wrlock(struct fuse *f, fuse_ino_t nodeid, > + struct node *wnode, char *path) > +{ > + pthread_mutex_lock(&f->lock); > + unlock_path(f, nodeid, wnode, NULL); > + pthread_cond_broadcast(&f->treecond); > + pthread_mutex_unlock(&f->lock); > + free(path); > +} > + > +static void free_path(struct fuse *f, fuse_ino_t nodeid, char *path) > +{ > + free_path_wrlock(f, nodeid, NULL, path); > +} > + > +static void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2, > + struct node *wnode1, struct node *wnode2, > + char *path1, char *path2) > +{ > + pthread_mutex_lock(&f->lock); > + unlock_path(f, nodeid1, wnode1, NULL); > + unlock_path(f, nodeid2, wnode2, NULL); > + pthread_cond_broadcast(&f->treecond); > + pthread_mutex_unlock(&f->lock); > + free(path1); > + free(path2); > } > > static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup) > @@ -481,6 +620,14 @@ static void forget_node(struct fuse *f, > return; > pthread_mutex_lock(&f->lock); > node = get_node(f, nodeid); > + > + /* > + * Node may still be locked due to interrupt idiocy in open, > + * create and opendir > + */ > + while (node->nlookup == nlookup && node->treelock) > + pthread_cond_wait(&f->treecond, &f->lock); > + > assert(node->nlookup >= nlookup); > node->nlookup -= nlookup; > if (!node->nlookup) { > @@ -1128,9 +1275,11 @@ static char *hidden_name(struct fuse *f, > (unsigned int) node->nodeid, f->hidectr); > newnode = lookup_node(f, dir, newname); > } while(newnode); > + > + newpath = NULL; > + try_get_path(f, dir, newname, 0, &newpath, NULL); > pthread_mutex_unlock(&f->lock); > > - newpath = get_path_name(f, dir, newname); > if (!newpath) > break; > > @@ -1240,7 +1389,7 @@ static struct fuse_context_i *fuse_get_c > if (c == NULL) { > /* This is hard to deal with properly, so just abort. If > memory is so low that the context cannot be allocated, > - there's not much hope for the filesystem anyway */ > + there's not much hope for the filesystem anyway */ > fprintf(stderr, "fuse: failed to allocate thread specific data\n"); > abort(); > } > @@ -1358,14 +1507,12 @@ static void fuse_lib_lookup(fuse_req_t r > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path_name(f, parent, name); > - if (path != NULL) { > + err = get_path_name(f, parent, name, &path); > + if (!err) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "LOOKUP %s\n", path); > - fuse_prepare_interrupt(f, req, &d); > + fuse_prepare_interrupt(f, req, &d); > err = lookup_path(f, parent, name, path, &e, NULL); > if (err == -ENOENT && f->conf.negative_timeout != 0.0) { > e.ino = 0; > @@ -1373,9 +1520,8 @@ static void fuse_lib_lookup(fuse_req_t r > err = 0; > } > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, parent, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_entry(req, &e, err); > } > > @@ -1400,17 +1546,14 @@ static void fuse_lib_getattr(fuse_req_t > (void) fi; > memset(&buf, 0, sizeof(buf)); > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_getattr(f->fs, path, &buf); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > if (!err) { > if (f->conf.auto_cache) { > pthread_mutex_lock(&f->lock); > @@ -1440,19 +1583,17 @@ static void fuse_lib_setattr(fuse_req_t > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = 0; > if (!err && (valid & FUSE_SET_ATTR_MODE)) > err = fuse_fs_chmod(f->fs, path, attr->st_mode); > if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) { > - uid_t uid = > + uid_t uid = > (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1; > - gid_t gid = > + gid_t gid = > (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1; > err = fuse_fs_chown(f->fs, path, uid, gid); > } > @@ -1474,9 +1615,8 @@ static void fuse_lib_setattr(fuse_req_t > if (!err) > err = fuse_fs_getattr(f->fs, path, &buf); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > if (!err) { > if (f->conf.auto_cache) { > pthread_mutex_lock(&f->lock); > @@ -1495,19 +1635,16 @@ static void fuse_lib_access(fuse_req_t r > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "ACCESS %s 0%o\n", path, mask); > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_access(f->fs, path, mask); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_err(req, err); > } > > @@ -1518,17 +1655,14 @@ static void fuse_lib_readlink(fuse_req_t > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > if (!err) { > linkname[PATH_MAX] = '\0'; > fuse_reply_readlink(req, linkname); > @@ -1544,10 +1678,8 @@ static void fuse_lib_mknod(fuse_req_t re > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path_name(f, parent, name); > - if (path) { > + err = get_path_name(f, parent, name, &path); > + if (!err) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "MKNOD %s\n", path); > @@ -1570,9 +1702,8 @@ static void fuse_lib_mknod(fuse_req_t re > err = lookup_path(f, parent, name, path, &e, NULL); > } > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, parent, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_entry(req, &e, err); > } > > @@ -1584,10 +1715,8 @@ static void fuse_lib_mkdir(fuse_req_t re > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path_name(f, parent, name); > - if (path != NULL) { > + err = get_path_name(f, parent, name, &path); > + if (!err) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "MKDIR %s\n", path); > @@ -1596,9 +1725,8 @@ static void fuse_lib_mkdir(fuse_req_t re > if (!err) > err = lookup_path(f, parent, name, path, &e, NULL); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, parent, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_entry(req, &e, err); > } > > @@ -1606,41 +1734,38 @@ static void fuse_lib_unlink(fuse_req_t r > const char *name) > { > struct fuse *f = req_fuse_prepare(req); > + struct node *wnode; > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_wrlock(&f->tree_lock); > - path = get_path_name(f, parent, name); > - if (path != NULL) { > + err = get_path_wrlock(f, parent, name, &path, &wnode); > + if (!err) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "UNLINK %s\n", path); > fuse_prepare_interrupt(f, req, &d); > - if (!f->conf.hard_remove && is_open(f, parent, name)) > + if (!f->conf.hard_remove && is_open(f, parent, name)) { > err = hide_node(f, path, parent, name); > - else { > + } else { > err = fuse_fs_unlink(f->fs, path); > if (!err) > remove_node(f, parent, name); > } > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path_wrlock(f, parent, wnode, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_err(req, err); > } > > static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) > { > struct fuse *f = req_fuse_prepare(req); > + struct node *wnode; > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_wrlock(&f->tree_lock); > - path = get_path_name(f, parent, name); > - if (path != NULL) { > + err = get_path_wrlock(f, parent, name, &path, &wnode); > + if (!err) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "RMDIR %s\n", path); > @@ -1649,9 +1774,8 @@ static void fuse_lib_rmdir(fuse_req_t re > fuse_finish_interrupt(f, req, &d); > if (!err) > remove_node(f, parent, name); > - free(path); > + free_path_wrlock(f, parent, wnode, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_err(req, err); > } > > @@ -1663,10 +1787,8 @@ static void fuse_lib_symlink(fuse_req_t > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path_name(f, parent, name); > - if (path != NULL) { > + err = get_path_name(f, parent, name, &path); > + if (!err) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "SYMLINK %s\n", path); > @@ -1675,9 +1797,8 @@ static void fuse_lib_symlink(fuse_req_t > if (!err) > err = lookup_path(f, parent, name, path, &e, NULL); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, parent, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_entry(req, &e, err); > } > > @@ -1688,32 +1809,28 @@ static void fuse_lib_rename(fuse_req_t r > struct fuse *f = req_fuse_prepare(req); > char *oldpath; > char *newpath; > + struct node *wnode1; > + struct node *wnode2; > int err; > > - err = -ENOENT; > - pthread_rwlock_wrlock(&f->tree_lock); > - oldpath = get_path_name(f, olddir, oldname); > - if (oldpath != NULL) { > - newpath = get_path_name(f, newdir, newname); > - if (newpath != NULL) { > - struct fuse_intr_data d; > - if (f->conf.debug) > - fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath); > - err = 0; > - fuse_prepare_interrupt(f, req, &d); > - if (!f->conf.hard_remove && is_open(f, newdir, newname)) > - err = hide_node(f, newpath, newdir, newname); > - if (!err) { > - err = fuse_fs_rename(f->fs, oldpath, newpath); > - if (!err) > - err = rename_node(f, olddir, oldname, newdir, newname, 0); > - } > - fuse_finish_interrupt(f, req, &d); > - free(newpath); > + err = get_path2(f, olddir, oldname, newdir, newname, > + &oldpath, &newpath, &wnode1, &wnode2); > + if (!err) { > + struct fuse_intr_data d; > + if (f->conf.debug) > + fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath); > + err = 0; > + fuse_prepare_interrupt(f, req, &d); > + if (!f->conf.hard_remove && is_open(f, newdir, newname)) > + err = hide_node(f, newpath, newdir, newname); > + if (!err) { > + err = fuse_fs_rename(f->fs, oldpath, newpath); > + if (!err) > + err = rename_node(f, olddir, oldname, newdir, newname, 0); > } > - free(oldpath); > + fuse_finish_interrupt(f, req, &d); > + free_path2(f, olddir, newdir, wnode1, wnode2, oldpath, newpath); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_err(req, err); > } > > @@ -1726,25 +1843,19 @@ static void fuse_lib_link(fuse_req_t req > char *newpath; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - oldpath = get_path(f, ino); > - if (oldpath != NULL) { > - newpath = get_path_name(f, newparent, newname); > - if (newpath != NULL) { > - struct fuse_intr_data d; > - if (f->conf.debug) > - fprintf(stderr, "LINK %s\n", newpath); > - fuse_prepare_interrupt(f, req, &d); > - err = fuse_fs_link(f->fs, oldpath, newpath); > - if (!err) > - err = lookup_path(f, newparent, newname, newpath, &e, NULL); > - fuse_finish_interrupt(f, req, &d); > - free(newpath); > - } > - free(oldpath); > + err = get_path2(f, ino, NULL, newparent, newname, > + &oldpath, &newpath, NULL, NULL); > + if (!err) { > + struct fuse_intr_data d; > + if (f->conf.debug) > + fprintf(stderr, "LINK %s\n", newpath); > + fuse_prepare_interrupt(f, req, &d); > + err = fuse_fs_link(f->fs, oldpath, newpath); > + if (!err) > + err = lookup_path(f, newparent, newname, newpath, &e, NULL); > + fuse_finish_interrupt(f, req, &d); > + free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_entry(req, &e, err); > } > > @@ -1777,13 +1888,11 @@ static void fuse_lib_create(fuse_req_t r > struct fuse *f = req_fuse_prepare(req); > struct fuse_intr_data d; > struct fuse_entry_param e; > - char *path; > + char *path = NULL; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path_name(f, parent, name); > - if (path) { > + err = get_path_name(f, parent, name, &path); > + if (!err) { > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_create(f->fs, path, mode, fi); > if (!err) { > @@ -1821,16 +1930,14 @@ static void fuse_lib_create(fuse_req_t r > } else > reply_err(req, err); > > - if (path) > - free(path); > - > - pthread_rwlock_unlock(&f->tree_lock); > + if (path != NULL) > + free_path(f, parent, path); > } > > static double diff_timespec(const struct timespec *t1, > const struct timespec *t2) > { > - return (t1->tv_sec - t2->tv_sec) + > + return (t1->tv_sec - t2->tv_sec) + > ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; > } > > @@ -1870,12 +1977,10 @@ static void fuse_lib_open(fuse_req_t req > struct fuse *f = req_fuse_prepare(req); > struct fuse_intr_data d; > char *path = NULL; > - int err = 0; > + int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path) { > + err = get_path(f, ino, &path); > + if (!err) { > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_open(f->fs, path, fi); > if (!err) { > @@ -1905,9 +2010,8 @@ static void fuse_lib_open(fuse_req_t req > } else > reply_err(req, err); > > - if (path) > - free(path); > - pthread_rwlock_unlock(&f->tree_lock); > + if (path != NULL) > + free_path(f, ino, path); > } > > static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size, > @@ -1924,10 +2028,8 @@ static void fuse_lib_read(fuse_req_t req > return; > } > > - res = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + res = get_path(f, ino, &path); > + if (res == 0) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "READ[%llu] %lu bytes from %llu\n", > @@ -1937,9 +2039,8 @@ static void fuse_lib_read(fuse_req_t req > fuse_prepare_interrupt(f, req, &d); > res = fuse_fs_read(f->fs, path, buf, size, off, fi); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > > if (res >= 0) { > if (f->conf.debug) > @@ -1961,10 +2062,8 @@ static void fuse_lib_write(fuse_req_t re > char *path; > int res; > > - res = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + res = get_path(f, ino, &path); > + if (res == 0) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n", > @@ -1974,9 +2073,8 @@ static void fuse_lib_write(fuse_req_t re > fuse_prepare_interrupt(f, req, &d); > res = fuse_fs_write(f->fs, path, buf, size, off, fi); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > > if (res >= 0) { > if (f->conf.debug) > @@ -1997,19 +2095,16 @@ static void fuse_lib_fsync(fuse_req_t re > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > if (f->conf.debug) > fprintf(stderr, "FSYNC[%llu]\n", (unsigned long long) fi->fh); > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_fsync(f->fs, path, datasync, fi); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_err(req, err); > } > > @@ -2030,7 +2125,7 @@ static void fuse_lib_opendir(fuse_req_t > struct fuse_intr_data d; > struct fuse_dh *dh; > struct fuse_file_info fi; > - char *path; > + char *path = NULL; > int err; > > dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh)); > @@ -2051,10 +2146,8 @@ static void fuse_lib_opendir(fuse_req_t > memset(&fi, 0, sizeof(fi)); > fi.flags = llfi->flags; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_opendir(f->fs, path, &fi); > fuse_finish_interrupt(f, req, &d); > @@ -2073,8 +2166,8 @@ static void fuse_lib_opendir(fuse_req_t > reply_err(req, err); > free(dh); > } > - free(path); > - pthread_rwlock_unlock(&f->tree_lock); > + if (path != NULL) > + free_path(f, ino, path); > } > > static int extend_contents(struct fuse_dh *dh, unsigned minsize) > @@ -2150,11 +2243,11 @@ static int readdir_fill(struct fuse *f, > size_t size, off_t off, struct fuse_dh *dh, > struct fuse_file_info *fi) > { > - int err = -ENOENT; > char *path; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + int err; > + > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > > dh->len = 0; > @@ -2170,9 +2263,8 @@ static int readdir_fill(struct fuse *f, > err = dh->error; > if (err) > dh->filled = 0; > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > return err; > } > > @@ -2218,16 +2310,15 @@ static void fuse_lib_releasedir(fuse_req > struct fuse_intr_data d; > struct fuse_file_info fi; > struct fuse_dh *dh = get_dirhandle(llfi, &fi); > - char *path; > + char *path = NULL; > > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > + get_path(f, ino, &path); > fuse_prepare_interrupt(f, req, &d); > fuse_fs_releasedir(f->fs, path ? path : "-", &fi); > fuse_finish_interrupt(f, req, &d); > - if (path) > - free(path); > - pthread_rwlock_unlock(&f->tree_lock); > + if (path != NULL) > + free_path(f, ino, path); > + > pthread_mutex_lock(&dh->lock); > pthread_mutex_unlock(&dh->lock); > pthread_mutex_destroy(&dh->lock); > @@ -2246,17 +2337,14 @@ static void fuse_lib_fsyncdir(fuse_req_t > > get_dirhandle(llfi, &fi); > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_err(req, err); > } > > @@ -2264,26 +2352,21 @@ static void fuse_lib_statfs(fuse_req_t r > { > struct fuse *f = req_fuse_prepare(req); > struct statvfs buf; > - char *path; > - int err; > + char *path = NULL; > + int err = 0; > > memset(&buf, 0, sizeof(buf)); > - pthread_rwlock_rdlock(&f->tree_lock); > - if (!ino) { > - err = -ENOMEM; > - path = strdup("/"); > - } else { > - err = -ENOENT; > - path = get_path(f, ino); > - } > - if (path) { > + if (ino) > + err = get_path(f, ino, &path); > + > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > - err = fuse_fs_statfs(f->fs, path, &buf); > + err = fuse_fs_statfs(f->fs, path ? path : "/", &buf); > fuse_finish_interrupt(f, req, &d); > - free(path); > + if (path != NULL) > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > > if (!err) > fuse_reply_statfs(req, &buf); > @@ -2298,17 +2381,14 @@ static void fuse_lib_setxattr(fuse_req_t > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_err(req, err); > } > > @@ -2318,17 +2398,14 @@ static int common_getxattr(struct fuse * > int err; > char *path; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_getxattr(f->fs, path, name, value, size); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > return err; > } > > @@ -2365,17 +2442,14 @@ static int common_listxattr(struct fuse > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_listxattr(f->fs, path, list, size); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > return err; > } > > @@ -2412,17 +2486,14 @@ static void fuse_lib_removexattr(fuse_re > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_removexattr(f->fs, path, name); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > reply_err(req, err); > } > > @@ -2578,11 +2649,10 @@ static void fuse_lib_release(fuse_req_t > { > struct fuse *f = req_fuse_prepare(req); > struct fuse_intr_data d; > - char *path; > + char *path = NULL; > int err = 0; > > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > + get_path(f, ino, &path); > if (f->conf.debug) > fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n", > fi->flush ? "+FLUSH" : "", > @@ -2597,8 +2667,8 @@ static void fuse_lib_release(fuse_req_t > fuse_prepare_interrupt(f, req, &d); > fuse_do_release(f, ino, path, fi); > fuse_finish_interrupt(f, req, &d); > - free(path); > - pthread_rwlock_unlock(&f->tree_lock); > + if (path != NULL) > + free_path(f, ino, path); > > reply_err(req, err); > } > @@ -2607,16 +2677,16 @@ static void fuse_lib_flush(fuse_req_t re > struct fuse_file_info *fi) > { > struct fuse *f = req_fuse_prepare(req); > - char *path; > + char *path = NULL; > int err; > > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path && f->conf.debug) > + get_path(f, ino, &path); > + if (f->conf.debug) > fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh); > err = fuse_flush_common(f, req, ino, path, fi); > - free(path); > - pthread_rwlock_unlock(&f->tree_lock); > + if (path != NULL) > + free_path(f, ino, path); > + > reply_err(req, err); > } > > @@ -2628,17 +2698,14 @@ static int fuse_lock_common(fuse_req_t r > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > struct fuse_intr_data d; > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_lock(f->fs, path, fi, cmd, lock); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > return err; > } > > @@ -2693,16 +2760,13 @@ static void fuse_lib_bmap(fuse_req_t req > char *path; > int err; > > - err = -ENOENT; > - pthread_rwlock_rdlock(&f->tree_lock); > - path = get_path(f, ino); > - if (path != NULL) { > + err = get_path(f, ino, &path); > + if (!err) { > fuse_prepare_interrupt(f, req, &d); > err = fuse_fs_bmap(f->fs, path, blocksize, &idx); > fuse_finish_interrupt(f, req, &d); > - free(path); > + free_path(f, ino, path); > } > - pthread_rwlock_unlock(&f->tree_lock); > if (!err) > fuse_reply_bmap(req, idx); > else > @@ -2884,7 +2948,7 @@ static void fuse_lib_help(void) > " -o readdir_ino try to fill in d_ino in readdir\n" > " -o direct_io use direct I/O\n" > " -o kernel_cache cache files in kernel\n" > -" -o [no]auto_cache enable caching based on modification times\n" > +" -o [no]auto_cache enable caching based on modification times (off)\n" > " -o umask=M set file permissions (octal)\n" > " -o uid=N set file owner\n" > " -o gid=N set file group\n" > @@ -3113,7 +3177,7 @@ struct fuse *fuse_new_common(struct fuse > } > > fuse_mutex_init(&f->lock); > - pthread_rwlock_init(&f->tree_lock, NULL); > + pthread_cond_init(&f->treecond, NULL); > > root = (struct node *) calloc(1, sizeof(struct node)); > if (root == NULL) { > @@ -3189,8 +3253,8 @@ void fuse_destroy(struct fuse *f) > > for (node = f->id_table[i]; node != NULL; node = node->id_next) { > if (node->is_hidden) { > - char *path = get_path(f, node->nodeid); > - if (path) { > + char *path; > + if (try_get_path(f, node->nodeid, NULL, 0, &path, NULL) == 0) { > fuse_fs_unlink(f->fs, path); > free(path); > } > @@ -3210,7 +3274,7 @@ void fuse_destroy(struct fuse *f) > free(f->id_table); > free(f->name_table); > pthread_mutex_destroy(&f->lock); > - pthread_rwlock_destroy(&f->tree_lock); > + pthread_cond_destroy(&f->treecond); > fuse_session_destroy(f->se); > free(f->conf.modules); > free(f); > @@ -3252,7 +3316,7 @@ static struct fuse *fuse_new_common_comp > struct fuse_args args = FUSE_ARGS_INIT(0, NULL); > > if (fuse_opt_add_arg(&args, "") == -1) > - return NULL; > + return NULL; > if (opts && > (fuse_opt_add_arg(&args, "-o") == -1 || > fuse_opt_add_arg(&args, opts) == -1)) { > |