DF-0925 / fix.diff
diff --git a/sys/vfs/fuse/fuse.h b/sys/vfs/fuse/fuse.h --- a/sys/vfs/fuse/fuse.h +++ b/sys/vfs/fuse/fuse.h @@ -116,6 +116,7 @@ uint64_t ino; enum vtype type; size_t size; + uint32_t fn_refcnt; /* prevents free during concurrent lookup */ uint64_t nlookup; uint64_t fh; bool closed; /* XXX associated with closed fh */ diff --git a/sys/vfs/fuse/fuse_node.c b/sys/vfs/fuse/fuse_node.c --- a/sys/vfs/fuse/fuse_node.c +++ b/sys/vfs/fuse/fuse_node.c @@ -62,6 +62,7 @@ mtx_init(&fnp->node_lock, "fuse_node_lock"); fnp->ino = ino; + fnp->fn_refcnt = 1; /* tree's reference */ fnp->type = vtyp; fnp->size = 0; fnp->nlookup = 0; @@ -80,11 +81,13 @@ { fuse_dbg("free ino=%ju\n", fnp->ino); + KKASSERT(fnp->fn_refcnt > 0); mtx_lock(&fmp->ino_lock); RB_REMOVE(fuse_node_tree, &fmp->node_head, fnp); mtx_unlock(&fmp->ino_lock); - objcache_put(fuse_node_objcache, fnp); + if (atomic_fetchadd_int(&fnp->fn_refcnt, -1) == 1) + objcache_put(fuse_node_objcache, fnp); } /* @@ -108,10 +111,18 @@ if (fnp == NULL) { fuse_node_new(fmp, ino, vtyp, &fnp); allocated = 1; + } else { + atomic_add_int(&fnp->fn_refcnt, 1); /* pin while we use it */ } mtx_unlock(&fmp->ino_lock); error = fuse_node_vn(fnp, vpp); + + if (!allocated) { + if (atomic_fetchadd_int(&fnp->fn_refcnt, -1) == 1) + objcache_put(fuse_node_objcache, fnp); + } + if (error) { if (allocated) fuse_node_free(fmp, fnp); diff --git a/sys/vfs/fuse/fuse_vnops.c b/sys/vfs/fuse/fuse_vnops.c --- a/sys/vfs/fuse/fuse_vnops.c +++ b/sys/vfs/fuse/fuse_vnops.c @@ -1791,7 +1791,9 @@ if (fnp) { vp->v_data = NULL; + mtx_lock(&fnp->node_lock); fnp->vp = NULL; + mtx_unlock(&fnp->node_lock); fuse_dbg("ino=%ju\n", fnp->ino); if (fnp != fmp->rfnp) |