summaryrefslogtreecommitdiff
path: root/lib/libfuse/fuse_ops.c
diff options
context:
space:
mode:
authorMartin Natano <natano@cvs.openbsd.org>2016-09-07 17:53:36 +0000
committerMartin Natano <natano@cvs.openbsd.org>2016-09-07 17:53:36 +0000
commit587b8d5f6cb8ddb5c2ef3598d49e8064e025bc93 (patch)
treef9a6811178669d088b0bffc1e2c950abc67961e1 /lib/libfuse/fuse_ops.c
parent6732fa617ab1e37ccf7d3ed7505a90bd35dfe941 (diff)
Fix fuse node lookups. Currently fusefs nodes in the kernel remember the
parent inode number for ".." lookups. This only works until the kernel starts to reuse vnodes and the parent's vnode is reclaimed and the ino to path mapping is removed from the userland process by libfuse. Fix this by using reference counting in libfuse, so that parent mapping are retained as long as a child uses them. Also, don't free the root node. This commit resolves following issue: $ doas fuse-zip ~/Downloads/foo.zip /mnt $ ls /mnt openbsd-www $ grep -IR foo /usr/src > /dev/null # force vfs to reclaim vnodes $ ls /mnt ls: /mnt: No such file or directory $ ok tedu
Diffstat (limited to 'lib/libfuse/fuse_ops.c')
-rw-r--r--lib/libfuse/fuse_ops.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/lib/libfuse/fuse_ops.c b/lib/libfuse/fuse_ops.c
index ebbadfd1417..74853d17444 100644
--- a/lib/libfuse/fuse_ops.c
+++ b/lib/libfuse/fuse_ops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_ops.c,v 1.25 2016/08/30 16:45:54 natano Exp $ */
+/* $OpenBSD: fuse_ops.c,v 1.26 2016/09/07 17:53:35 natano Exp $ */
/*
* Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
*
@@ -432,15 +432,28 @@ ifuse_ops_lookup(struct fuse *f, struct fusebuf *fbuf)
DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
DPRINTF("For file %s\n", fbuf->fb_dat);
- vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
- if (vn == NULL) {
- vn = alloc_vn(f, (const char *)fbuf->fb_dat, -1, fbuf->fb_ino);
- if (vn == NULL) {
- fbuf->fb_err = -errno;
- free(fbuf->fb_dat);
+ if (strcmp((const char *)fbuf->fb_dat, "..") == 0) {
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+ if (vn == NULL || vn->parent == NULL) {
+ fbuf->fb_err = -ENOENT;
return (0);
}
- set_vn(f, vn); /*XXX*/
+ vn = vn->parent;
+ if (vn->ino != FUSE_ROOT_INO)
+ ref_vn(vn);
+ } else {
+ vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+ if (vn == NULL) {
+ vn = alloc_vn(f, (const char *)fbuf->fb_dat, -1,
+ fbuf->fb_ino);
+ if (vn == NULL) {
+ fbuf->fb_err = -errno;
+ free(fbuf->fb_dat);
+ return (0);
+ }
+ set_vn(f, vn); /*XXX*/
+ } else if (vn->ino != FUSE_ROOT_INO)
+ ref_vn(vn);
}
DPRINTF("new ino %llu\n", (unsigned long long)vn->ino);
@@ -991,11 +1004,9 @@ ifuse_ops_reclaim(struct fuse *f, struct fusebuf *fbuf)
{
struct fuse_vnode *vn;
- vn = tree_pop(&f->vnode_tree, fbuf->fb_ino);
- if (vn) {
- remove_vnode_from_name_tree(f, vn);
- free(vn);
- }
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+ if (vn != NULL)
+ unref_vn(f, vn);
return (0);
}