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); }
/* * 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); }