Beispiel #1
0
static void
pefs_insmntque_dtr(struct vnode *vp, void *_pn)
{
	struct pefs_node *pn = _pn;

	PEFSDEBUG("pefs_insmntque_dtr: free node %p\n", pn);
	vp->v_data = NULL;
	vp->v_vnlock = &vp->v_lock;
	pefs_key_release(pn->pn_tkey.ptk_key);
	uma_zfree(pefs_node_zone, pn);
	vp->v_op = &dead_vnodeops;
	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
	vgone(vp);
	vput(vp);
}
static void
dircache_entry_free(struct pefs_dircache_entry *pde)
{
	MPASS(pde != NULL);

	PEFSDEBUG("dircache_entry_free: %s -> %s\n",
	    pde->pde_name, pde->pde_encname);
	pefs_key_release(pde->pde_tkey.ptk_key);
	LIST_REMOVE(pde, pde_dir_entry);
	mtx_lock(&dircache_mtx);
	LIST_REMOVE(pde, pde_hash_entry);
	LIST_REMOVE(pde, pde_enchash_entry);
	dircache_entries--;
	mtx_unlock(&dircache_mtx);
	uma_zfree(dircache_entry_zone, pde);
}
Beispiel #3
0
/*
 * Make a new or get existing pefs node.
 * vp is the alias vnode
 * lvp is the lower vnode
 * ldvp is the lower directory vnode, used if no key specified
 *
 * The lvp assumed to be locked and having "spare" reference. This routine
 * vrele lvp if pefs node was taken from hash. Otherwise it "transfers" the
 * caller's "spare" reference to created pefs vnode.
 */
static int
pefs_node_get(struct mount *mp, struct vnode *lvp, struct vnode **vpp,
    pefs_node_init_fn *init_fn, void *context)
{
	struct pefs_node *pn;
	struct vnode *vp;
	int error;

	ASSERT_VOP_LOCKED(lvp, "pefs_node_get");
	/* Lookup the hash firstly */
	*vpp = pefs_nodehash_get(mp, lvp);
	if (*vpp != NULL) {
		vrele(lvp);
		return (0);
	}

	/*
	 * We do not serialize vnode creation, instead we will check for
	 * duplicates later, when adding new vnode to hash.
	 *
	 * Note that duplicate can only appear in hash if the lvp is
	 * locked LK_SHARED.
	 */

	/*
	 * Do the MALLOC before the getnewvnode since doing so afterward
	 * might cause a bogus v_data pointer to get dereferenced
	 * elsewhere if MALLOC should block.
	 */
	pn = uma_zalloc(pefs_node_zone, M_WAITOK | M_ZERO);
	pn->pn_lowervp = lvp;

	/* pn->pn_lowervp should be initialized before calling init_fn. */
	error = init_fn(mp, pn, context);
	MPASS(!(((pn->pn_flags & PN_HASKEY) == 0) ^
	    (pn->pn_tkey.ptk_key == NULL)));
	if (error != 0) {
		uma_zfree(pefs_node_zone, pn);
		return (error);
	}

	error = getnewvnode("pefs", mp, &pefs_vnodeops, &vp);
	if (error != 0) {
		pefs_key_release(pn->pn_tkey.ptk_key);
		uma_zfree(pefs_node_zone, pn);
		return (error);
	}

	if (pn->pn_tkey.ptk_key == NULL)
		PEFSDEBUG("pefs_node_get: creating node without key: %p\n", pn);

	pn->pn_vnode = vp;
	vp->v_type = lvp->v_type;
	vp->v_data = pn;
	vp->v_vnlock = lvp->v_vnlock;
	if (vp->v_vnlock == NULL)
		panic("pefs_node_get: Passed a NULL vnlock.\n");
	error = insmntque1(vp, mp, pefs_insmntque_dtr, pn);
	if (error != 0)
		return (error);
	/*
	 * Atomically insert our new node into the hash or vget existing
	 * if someone else has beaten us to it.
	 */
	*vpp = pefs_nodehash_insert(mp, pn);
	if (*vpp != NULL) {
		vrele(lvp);
		vp->v_vnlock = &vp->v_lock;
		pn->pn_lowervp = NULL;
		vrele(vp);
		MPASS(PEFS_LOWERVP(*vpp) == lvp);
		ASSERT_VOP_LOCKED(*vpp, "pefs_node_get: duplicate");
		return (0);
	}
	if (vp->v_type == VDIR)
		pn->pn_dircache = pefs_dircache_get();
	*vpp = vp;
	MPASS(PEFS_LOWERVP(*vpp) == lvp);
	ASSERT_VOP_LOCKED(*vpp, "pefs_node_get");

	return (0);
}