From 5830ee0d3ff65246d6a80a17030fb0131023a3ce Mon Sep 17 00:00:00 2001 From: kib Date: Thu, 2 May 2013 18:44:31 +0000 Subject: For the new regular tmpfs vnode, v_object is initialized before insmntque() is called. The standard insmntque destructor resets the vop vector to deadfs one, and calls vgone() on the vnode. As result, v_object is kept unchanged, which triggers an assertion in the reclaim code, on instmntque() failure. Also, in this case, OBJ_TMPFS flag on the backed vm object is not cleared. Provide the tmpfs insmntque() destructor which properly clears OBJ_TMPFS flag and resets v_object. Reported and tested by: pho Sponsored by: The FreeBSD Foundation --- sys/fs/tmpfs/tmpfs.h | 1 + sys/fs/tmpfs/tmpfs_subr.c | 32 +++++++++++++++++++++++++++++++- sys/fs/tmpfs/tmpfs_vnops.c | 15 ++------------- 3 files changed, 34 insertions(+), 14 deletions(-) (limited to 'sys/fs/tmpfs') diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h index 8f03f10..5a27ccf 100644 --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -402,6 +402,7 @@ int tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *, const char *, u_int, struct tmpfs_dirent **); void tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *); void tmpfs_dirent_init(struct tmpfs_dirent *, const char *, u_int); +void tmpfs_destroy_vobject(struct vnode *vp, vm_object_t obj); int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, int, struct vnode **); void tmpfs_free_vp(struct vnode *); diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index f639b09..e751331 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -429,6 +429,36 @@ tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de) /* --------------------------------------------------------------------- */ +void +tmpfs_destroy_vobject(struct vnode *vp, vm_object_t obj) +{ + + if (vp->v_type != VREG || obj == NULL) + return; + + VM_OBJECT_WLOCK(obj); + VI_LOCK(vp); + vm_object_clear_flag(obj, OBJ_TMPFS); + obj->un_pager.swp.swp_tmpfs = NULL; + VI_UNLOCK(vp); + VM_OBJECT_WUNLOCK(obj); +} + +/* + * Need to clear v_object for insmntque failure. + */ +static void +tmpfs_insmntque_dtr(struct vnode *vp, void *dtr_arg) +{ + + tmpfs_destroy_vobject(vp, vp->v_object); + vp->v_object = NULL; + vp->v_data = NULL; + vp->v_op = &dead_vnodeops; + vgone(vp); + vput(vp); +} + /* * Allocates a new vnode for the node node or returns a new reference to * an existing one if the node had already a vnode referencing it. The @@ -540,7 +570,7 @@ loop: panic("tmpfs_alloc_vp: type %p %d", node, (int)node->tn_type); } - error = insmntque(vp, mp); + error = insmntque1(vp, mp, tmpfs_insmntque_dtr, NULL); if (error) vp = NULL; diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 029aefb..4808181 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -1468,23 +1468,12 @@ tmpfs_reclaim(struct vop_reclaim_args *v) struct tmpfs_mount *tmp; struct tmpfs_node *node; - vm_object_t obj; node = VP_TO_TMPFS_NODE(vp); tmp = VFS_TO_TMPFS(vp->v_mount); - if (node->tn_type == VREG) { - obj = node->tn_reg.tn_aobj; - if (obj != NULL) { - /* Instead of vnode_destroy_vobject() */ - VM_OBJECT_WLOCK(obj); - VI_LOCK(vp); - vm_object_clear_flag(obj, OBJ_TMPFS); - obj->un_pager.swp.swp_tmpfs = NULL; - VI_UNLOCK(vp); - VM_OBJECT_WUNLOCK(obj); - } - } + if (vp->v_type == VREG) + tmpfs_destroy_vobject(vp, node->tn_reg.tn_aobj); vp->v_object = NULL; cache_purge(vp); -- cgit v1.1