diff --git a/sys/vfs/dirfs/dirfs.h b/sys/vfs/dirfs/dirfs.h index e0d900d..4af2986 100644 --- a/sys/vfs/dirfs/dirfs.h +++ b/sys/vfs/dirfs/dirfs.h @@ -54,12 +54,12 @@ MALLOC_DECLARE(M_DIRFS_MISC); #define DIRFS_NOFD -1 /* No fd present */ #define DIRFS_ROOT 0x00000001 -#define DIRFS_PASVFD 0x00000002 +#define DIRFS_DOOMED 0x00000002 #define DIRFS_NODE_RD 0x00000004 #define DIRFS_NODE_WR 0x00000008 #define DIRFS_NODE_EXE 0x00000010 -#define DIRFS_TXTFLG "pasvfd" +#define DIRFS_TXTFLG "doomed" /* Used for buffer cache operations */ #define BSIZE 16384 @@ -117,6 +117,7 @@ extern int statfs(const char *, struct statfs *); * Misc macros */ #define dirfs_node_isroot(n) (n->dn_state & DIRFS_ROOT) +#define dirfs_node_hasfd(n) (n->dn_fd != DIRFS_NOFD) /* * Main in-memory node structure which will represent a host file when active. @@ -129,7 +130,6 @@ struct dirfs_node { int dn_state; /* Node state flags */ - TAILQ_ENTRY(dirfs_node) dn_fdentry; /* Passive fd cache */ RB_ENTRY(dirfs_node) dn_rbentry; /* Inode no. lookup */ int dn_refcnt; /* Refs from children */ @@ -172,7 +172,6 @@ typedef struct dirfs_node *dirfs_node_t; */ struct dirfs_mount { RB_HEAD(, dn_rbentry) dm_inotree; - TAILQ_HEAD(, dirfs_node) dm_fdlist; struct lock dm_lock; struct lwkt_token dm_token; @@ -201,8 +200,6 @@ typedef struct dirfs_mount *dirfs_mount_t; extern int debuglvl; extern int dirfs_fd_limit; extern int dirfs_fd_used; -extern long passive_fd_list_miss; -extern long passive_fd_list_hits; extern struct vop_ops dirfs_vnode_vops; @@ -212,17 +209,26 @@ extern struct vop_ops dirfs_vnode_vops; static __inline void dirfs_node_ref(dirfs_node_t dnp) { + lockmgr(&dnp->dn_lock, LK_EXCLUSIVE); atomic_add_int(&dnp->dn_refcnt, 1); + lockmgr(&dnp->dn_lock, LK_RELEASE); } static __inline int dirfs_node_unref(dirfs_node_t dnp) { + int ret = 0; + /* * Returns non-zero on last unref. */ KKASSERT(dnp->dn_refcnt > 0); - return (atomic_fetchadd_int(&dnp->dn_refcnt, -1) == 1); + + lockmgr(&dnp->dn_lock, LK_EXCLUSIVE); + ret = (atomic_fetchadd_int(&dnp->dn_refcnt, -1) == 1); + lockmgr(&dnp->dn_lock, LK_RELEASE); + + return ret; } static __inline void @@ -248,9 +254,8 @@ void dirfs_node_setname(dirfs_node_t, const char *, int); char *dirfs_node_fullpath(dirfs_mount_t, const char *); int dirfs_node_free(dirfs_mount_t, dirfs_node_t); void dirfs_node_drop(dirfs_mount_t dmp, dirfs_node_t dnp); -void dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state); void dirfs_alloc_vp(struct mount *, struct vnode **, int, dirfs_node_t); -void dirfs_free_vp(dirfs_mount_t, dirfs_node_t); +void dirfs_free_vp(dirfs_node_t); int dirfs_alloc_file(dirfs_mount_t, dirfs_node_t *, dirfs_node_t, struct namecache *, struct vnode **, struct vattr *, int); dirfs_node_t dirfs_findfd(dirfs_mount_t dmp, dirfs_node_t cur, diff --git a/sys/vfs/dirfs/dirfs_subr.c b/sys/vfs/dirfs/dirfs_subr.c index 020ae78..7a92af3 100644 --- a/sys/vfs/dirfs/dirfs_subr.c +++ b/sys/vfs/dirfs/dirfs_subr.c @@ -85,9 +85,6 @@ dirfs_node_alloc(struct mount *mp) return dnp; } -/* - * Drops a reference to the node and. Node is freed when in the last reference. - */ void dirfs_node_drop(dirfs_mount_t dmp, dirfs_node_t dnp) { @@ -110,8 +107,6 @@ dirfs_node_free(dirfs_mount_t dmp, dirfs_node_t dnp) KKASSERT(dnp != NULL); debug_node2(dnp); - KKASSERT(dirfs_node_refcnt(dnp) == 0); - vp = NODE_TO_VP(dnp); /* * Remove the inode from the passive fds list @@ -120,16 +115,17 @@ dirfs_node_free(dirfs_mount_t dmp, dirfs_node_t dnp) */ dirfs_mount_gettoken(dmp); - if (dnp->dn_parent) { /* NULL when children reaped parents */ + if (dnp->dn_parent) { dirfs_node_drop(dmp, dnp->dn_parent); dnp->dn_parent = NULL; } - dirfs_node_setpassive(dmp, dnp, 0); if (dnp->dn_name) { kfree(dnp->dn_name, M_DIRFS_MISC); dnp->dn_name = NULL; } + close(dnp->dn_fd); + /* * The file descriptor should have been closed already by the * previous call to dirfs_set-passive. If not, force a sync and @@ -141,8 +137,8 @@ dirfs_node_free(dirfs_mount_t dmp, dirfs_node_t dnp) close(dnp->dn_fd); dnp->dn_fd = DIRFS_NOFD; } - lockuninit(&dnp->dn_lock); + kfree(dnp, M_DIRFS_NODE); dnp = NULL; @@ -205,7 +201,7 @@ dirfs_alloc_file(dirfs_mount_t dmp, dirfs_node_t *dnpp, dirfs_node_t pdnp, if (error) { /* XXX Handle errors */ error = errno; if (vp) - dirfs_free_vp(dmp, dnp); + dirfs_free_vp(dnp); dirfs_node_free(dmp, dnp); dirfs_dropfd(dmp, pathnp, pathfree); return error; @@ -251,7 +247,7 @@ dirfs_alloc_vp(struct mount *mp, struct vnode **vpp, int lkflags, vp->v_type = dnp->dn_type; if (dmp->dm_root == dnp) vsetflags(vp, VROOT); - dirfs_node_ref(dnp); /* ref for dnp<->vp */ +// dirfs_node_ref(dnp); /* ref for dnp<->vp */ /* Type-specific initialization. */ switch (dnp->dn_type) { @@ -292,13 +288,12 @@ dirfs_alloc_vp(struct mount *mp, struct vnode **vpp, int lkflags, * Do not call locked! */ void -dirfs_free_vp(dirfs_mount_t dmp, dirfs_node_t dnp) +dirfs_free_vp(dirfs_node_t dnp) { - struct vnode *vp = NODE_TO_VP(dnp); +// struct vnode *vp = NODE_TO_VP(dnp); - dnp->dn_vnode = NULL; - vp->v_data = NULL; - dirfs_node_drop(dmp, dnp); +// vp->v_data = NULL; +// dnp->dn_vnode = NULL; } int @@ -801,72 +796,6 @@ dirfs_node_chsize(dirfs_node_t dnp, off_t nsize) return error; } -void -dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state) -{ - struct vnode *vp; - - if (state && (dnp->dn_state & DIRFS_PASVFD) == 0 && - dnp->dn_fd != DIRFS_NOFD) { - dirfs_node_ref(dnp); - dirfs_node_setflags(dnp, DIRFS_PASVFD); - TAILQ_INSERT_TAIL(&dmp->dm_fdlist, dnp, dn_fdentry); - ++dirfs_fd_used; - ++dmp->dm_fd_used; - - /* - * If we are over our limit remove nodes from the - * passive fd cache. - */ - while (dmp->dm_fd_used > dirfs_fd_limit) { - dnp = TAILQ_FIRST(&dmp->dm_fdlist); - dirfs_node_setpassive(dmp, dnp, 0); - } - } - if (state == 0 && (dnp->dn_state & DIRFS_PASVFD)) { - dirfs_node_clrflags(dnp, DIRFS_PASVFD); - TAILQ_REMOVE(&dmp->dm_fdlist, dnp, dn_fdentry); - --dirfs_fd_used; - --dmp->dm_fd_used; - dbg(5, "dnp=%p removed from fdlist. %d used\n", - dnp, dirfs_fd_used); - - /* - * Attempt to close the descriptor. We can only do this - * if the related vnode is inactive and has exactly two - * refs (representing the vp<->dnp and PASVFD). Otherwise - * someone might have ref'd the node in order to use the - * dn_fd. - * - * Also, if the vnode is in any way dirty we leave the fd - * open for the buffer cache code. The syncer will eventually - * come along and fsync the vnode, and the next inactive - * transition will deal with the descriptor. - * - * The descriptor for the root node is NEVER closed by - * this function. - */ - vp = dnp->dn_vnode; - if (dirfs_node_refcnt(dnp) == 2 && vp && - dnp->dn_fd != DIRFS_NOFD && - !dirfs_node_isroot(dnp) && - (vp->v_flag & (VINACTIVE|VOBJDIRTY)) == VINACTIVE && - RB_EMPTY(&vp->v_rbdirty_tree)) { - dbg(5, "passive cache: closing %d\n", dnp->dn_fd); - close(dnp->dn_fd); - dnp->dn_fd = DIRFS_NOFD; - } else { - if (dirfs_node_refcnt(dnp) == 1 && dnp->dn_vnode == NULL && - dnp->dn_fd != DIRFS_NOFD && - dnp != dmp->dm_root) { - dbg(5, "passive cache: closing %d\n", dnp->dn_fd); - close(dnp->dn_fd); - dnp->dn_fd = DIRFS_NOFD; - } - } - dirfs_node_drop(dmp, dnp); - } -} char * dirfs_flag2str(dirfs_node_t dnp) @@ -874,7 +803,7 @@ dirfs_flag2str(dirfs_node_t dnp) const char *txtflg[] = { DIRFS_TXTFLG }; static char str[512] = {0}; - if (dnp->dn_state & DIRFS_PASVFD) + if (dnp->dn_state & DIRFS_DOOMED) ksprintf(str, "%s ", txtflg[0]); return str; @@ -891,4 +820,3 @@ debug(int level, const char *fmt, ...) __va_end(ap); } } - diff --git a/sys/vfs/dirfs/dirfs_vfsops.c b/sys/vfs/dirfs/dirfs_vfsops.c index afdf19a..2e849ab 100644 --- a/sys/vfs/dirfs/dirfs_vfsops.c +++ b/sys/vfs/dirfs/dirfs_vfsops.c @@ -77,8 +77,6 @@ KTR_INFO(KTR_DIRFS, dirfs, unmount, 22, int debuglvl = 0; int dirfs_fd_limit = 100; int dirfs_fd_used = 0; -long passive_fd_list_miss = 0; -long passive_fd_list_hits = 0; SYSCTL_NODE(_vfs, OID_AUTO, dirfs, CTLFLAG_RW, 0, "dirfs filesystem for vkernels"); @@ -88,10 +86,6 @@ SYSCTL_INT(_vfs_dirfs, OID_AUTO, fd_limit, CTLFLAG_RW, &dirfs_fd_limit, 0, "Maximum number of passive nodes to cache"); SYSCTL_INT(_vfs_dirfs, OID_AUTO, fd_used, CTLFLAG_RD, &dirfs_fd_used, 0, "Current number of passive nodes cached"); -SYSCTL_LONG(_vfs_dirfs, OID_AUTO, passive_fd_list_miss, CTLFLAG_RD, - &passive_fd_list_miss, 0, "Passive fd list cache misses"); -SYSCTL_LONG(_vfs_dirfs, OID_AUTO, passive_fd_list_hits, CTLFLAG_RD, - &passive_fd_list_hits, 0, "Passive fd list cache misses"); static int dirfs_statfs(struct mount *, struct statfs *, struct ucred *); @@ -160,7 +154,6 @@ dirfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) dmp->dm_uid = getuid(); dmp->dm_gid = getgid(); - TAILQ_INIT(&dmp->dm_fdlist); RB_INIT(&dmp->dm_inotree); kmalloc_raise_limit(M_DIRFS_NODE, 0); @@ -191,14 +184,6 @@ dirfs_unmount(struct mount *mp, int mntflags) goto failure; /* - * Clean up dm_fdlist. There should be no vnodes left so the - * only ref should be from the fdlist. - */ - while ((dnp = TAILQ_FIRST(&dmp->dm_fdlist)) != NULL) { - dirfs_node_setpassive(dmp, dnp, 0); - } - - /* * Cleanup root node. In the case the filesystem is mounted * but no operation is done on it, there will be no call to * VFS_ROOT() so better check dnp is not NULL before attempting @@ -259,7 +244,7 @@ dirfs_root(struct mount *mp, struct vnode **vpp) fd = open(dmp->dm_path, O_DIRECTORY); if (fd == -1) { dbg(5, "failed to open ROOT node\n"); - dirfs_free_vp(dmp, dnp); + dirfs_free_vp(dnp); dirfs_node_free(dmp, dnp); return errno; } diff --git a/sys/vfs/dirfs/dirfs_vnops.c b/sys/vfs/dirfs/dirfs_vnops.c index df08540..b6a869b 100644 --- a/sys/vfs/dirfs/dirfs_vnops.c +++ b/sys/vfs/dirfs/dirfs_vnops.c @@ -196,25 +196,7 @@ dirfs_nresolve(struct vop_nresolve_args *ap) pdnp = VP_TO_NODE(dvp); dmp = VFS_TO_DIRFS(mp); - dirfs_node_lock(pdnp); - TAILQ_FOREACH_MUTABLE(d1, &dmp->dm_fdlist, dn_fdentry, d2) { - if (d1->dn_parent == pdnp && - (strcmp(d1->dn_name, ncp->nc_name) == 0)) { - dnp = d1; - dirfs_node_ref(dnp); - passive_fd_list_hits++; - break; - } - } - dirfs_node_unlock(pdnp); - - if (dnp) { - dirfs_alloc_vp(mp, &vp, LK_CANRECURSE, dnp); - dirfs_node_drop(dmp, dnp); - } else { - passive_fd_list_miss++; - error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, &vp, NULL, 0); - } + error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, &vp, NULL, 0); if (vp) { if (error && error == ENOENT) { @@ -310,11 +292,11 @@ dirfs_open(struct vop_open_args *ap) error = 0; /* - * Root inode has been allocated and opened in VFS_ROOT() so - * no reason to attempt to open it again. */ - if (dmp->dm_root != dnp && dnp->dn_fd == DIRFS_NOFD) { - error = dirfs_open_helper(dmp, dnp, DIRFS_NOFD, NULL); + if (!dirfs_node_isroot(dnp)) { + if (!dirfs_node_hasfd(dnp)) + error = dirfs_open_helper(dmp, dnp, DIRFS_NOFD, NULL); + if (error) return error; } @@ -327,6 +309,7 @@ dirfs_open(struct vop_open_args *ap) static int dirfs_close(struct vop_close_args *ap) { + dirfs_mount_t dmp; struct vnode *vp; dirfs_node_t dnp; int error; @@ -335,6 +318,7 @@ dirfs_close(struct vop_close_args *ap) error = 0; vp = ap->a_vp; + dmp = VFS_TO_DIRFS(vp->v_mount); dnp = VP_TO_NODE(vp); if (vp->v_type == VREG) { @@ -342,19 +326,16 @@ dirfs_close(struct vop_close_args *ap) if (error) dbg(5, "vfsync error=%d\n", error); } - vop_stdclose(ap); - /* - * XXX - Currently VOP_INACTIVE() is not being called unless there is - * vnode pressure so, by now, call inactive directly on last close. - */ - vn_lock(vp, LK_UPGRADE | LK_RETRY); - if (vp->v_opencount == 0 && vp->v_writecount == 0) - VOP_INACTIVE(vp); + if (!dirfs_node_isroot(dnp) && vp->v_opencount == 1) { + dirfs_node_setflags(dnp, DIRFS_DOOMED); + } KTR_LOG(dirfs_close, dnp, dnp->dn_fd, vp->v_opencount, vp->v_writecount, error); + vop_stdclose(ap); + return 0; } @@ -932,7 +913,6 @@ dirfs_nremove(struct vop_nremove_args *ap) error = unlinkat(pathnp->dn_fd, tmp, 0); if (error == 0) { cache_unlink(nch); - dirfs_node_setpassive(dmp, dnp, 0); if (dnp->dn_parent) { dirfs_node_drop(dmp, dnp->dn_parent); dnp->dn_parent = NULL; @@ -1016,7 +996,6 @@ dirfs_nrename(struct vop_nrename_args *ap) dbg(5, "RENAME2\n"); dnp = VP_TO_NODE(vp); cache_unlink(ap->a_tnch); - dirfs_node_setpassive(dmp, dnp, 0); if (dnp->dn_parent) { dirfs_node_drop(dmp, dnp->dn_parent); dnp->dn_parent = NULL; @@ -1139,7 +1118,6 @@ dirfs_nrmdir(struct vop_nrmdir_args *ap) error = rmdir(tmp); if (error == 0) { cache_unlink(nch); - dirfs_node_setpassive(dmp, dnp, 0); if (dnp->dn_parent) { dirfs_node_drop(dmp, dnp->dn_parent); dnp->dn_parent = NULL; @@ -1389,7 +1367,8 @@ dirfs_inactive(struct vop_inactive_args *ap) return 0; } - dirfs_mount_gettoken(dmp); + if (dirfs_node_refcnt(dnp) == 0) + dirfs_node_free(dmp,dnp); /* * Deal with the case the inode has 0 links which means it was unlinked. @@ -1401,12 +1380,7 @@ dirfs_inactive(struct vop_inactive_args *ap) goto out; } - /* - * Try to retain the fd in our fd cache. - */ - dirfs_node_setpassive(dmp, dnp, 1); out: - dirfs_mount_reltoken(dmp); return 0; @@ -1425,9 +1399,10 @@ dirfs_reclaim(struct vop_reclaim_args *ap) dnp = VP_TO_NODE(vp); dmp = VFS_TO_DIRFS(vp->v_mount); - dirfs_free_vp(dmp, dnp); +// dirfs_free_vp(dnp); + vp->v_data = NULL; /* dnp is now invalid, may have been destroyed */ - + dbg(5, "ending reclaim\n"); return 0; }