Index: sys/fs/fuse/fuse_node.c =================================================================== --- sys/fs/fuse/fuse_node.c (revisione 238487) +++ sys/fs/fuse/fuse_node.c (copia locale) @@ -213,18 +213,13 @@ fuse_vnode_alloc(struct mount *mp, } err = vfs_hash_insert(*vpp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE, td, &vp2, fuse_vnode_cmp, &nodeid); - - if (err) { - fuse_vnode_destroy(*vpp); - *vpp = NULL; + if (err) return (err); + if (vp2 != NULL) { + *vpp = vp2; + return (0); } - /* - * XXXIP: Prevent silent vnode reuse. It may happen because several fuse - * filesystems ignore inode numbers - */ - KASSERT(vp2 == NULL, - ("vfs hash collision for node #%ju\n", (uintmax_t)nodeid)); + ASSERT_VOP_ELOCKED(*vpp, "fuse_vnode_alloc"); return (0); Index: sys/fs/fuse/fuse_vnops.c =================================================================== --- sys/fs/fuse/fuse_vnops.c (revisione 238487) +++ sys/fs/fuse/fuse_vnops.c (copia locale) @@ -933,9 +933,30 @@ calldaemon: goto out; } if (flags & ISDOTDOT) { + struct mount *mp; int ltype; + /* + * Expanded copy of vn_vget_ino() so that + * fuse_vnode_get() can be used. + */ + mp = dvp->v_mount; ltype = VOP_ISLOCKED(dvp); + err = vfs_busy(mp, MBF_NOWAIT); + if (err != 0) { + vfs_ref(mp); + VOP_UNLOCK(dvp, 0); + err = vfs_busy(mp, 0); + vn_lock(dvp, ltype | LK_RETRY); + vfs_rel(mp); + if (err) + goto out; + if ((dvp->v_iflag & VI_DOOMED) != 0) { + err = ENOENT; + vfs_unbusy(mp); + goto out; + } + } VOP_UNLOCK(dvp, 0); err = fuse_vnode_get(vnode_mount(dvp), nid, @@ -943,8 +964,15 @@ calldaemon: &vp, cnp, IFTOVT(fattr->mode)); + vfs_unbusy(mp); vn_lock(dvp, ltype | LK_RETRY); - vref(vp); + if ((dvp->v_iflag & VI_DOOMED) != 0) { + if (err == 0) + vput(vp); + err = ENOENT; + } + if (err) + goto out; *vpp = vp; } else if (nid == VTOI(dvp)) { vref(dvp); Index: sys/fs/fuse/fuse_ipc.h =================================================================== --- sys/fs/fuse/fuse_ipc.h (revisione 238487) +++ sys/fs/fuse/fuse_ipc.h (copia locale) @@ -320,6 +320,7 @@ fuse_aw_remove(struct fuse_ticket *ftick) { DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n", ftick, ftick->tk_refcount); + mtx_assert(&ftick->tk_data->aw_mtx, MA_OWNED); TAILQ_REMOVE(&ftick->tk_data->aw_head, ftick, tk_aw_link); #ifdef INVARIANTS ftick->tk_aw_link.tqe_next = NULL; Index: sys/fs/fuse/fuse_device.c =================================================================== --- sys/fs/fuse/fuse_device.c (revisione 238487) +++ sys/fs/fuse/fuse_device.c (copia locale) @@ -428,7 +428,12 @@ fuse_device_write(struct cdev *dev, struct uio *ui /* pretender doesn't wanna do anything with answer */ DEBUG("stuff devalidated, so we drop it\n"); } - FUSE_ASSERT_AW_DONE(tick); + + /* + * As aw_mtx was not held during the callback execution the + * ticket may have been inserted again. However, this is safe + * because fuse_ticket_drop() will deal with refcount anyway. + */ fuse_ticket_drop(tick); } else { /* no callback at all! */