Пример #1
0
struct pefs_dircache_entry *
pefs_dircache_enclookup(struct pefs_dircache *pd, char const *encname,
    size_t encname_len)
{
	struct pefs_dircache_entry *pde;
	struct pefs_dircache_listhead *head;
	uint32_t h;

	h = dircache_hashname(pd, encname, encname_len);
	head = &dircache_enctbl[h & pefs_dircache_hashmask];
	mtx_lock(&dircache_mtx);
	LIST_FOREACH(pde, head, pde_enchash_entry) {
		if (pde->pde_encnamehash == h &&
		    pde->pde_dircache == pd &&
		    pde->pde_encnamelen == encname_len &&
		    memcmp(pde->pde_encname, encname, encname_len) == 0) {
			mtx_unlock(&dircache_mtx);
			PEFSDEBUG("pefs_dircache_enclookup: found %s -> %s\n",
			    pde->pde_name, pde->pde_encname);
			return (pde);
		}
	}
	mtx_unlock(&dircache_mtx);
	PEFSDEBUG("pefs_dircache_enclookup: not found %s\n", encname);
	return (NULL);
}
Пример #2
0
static int
pefs_node_lookup_key(struct pefs_mount *pm, struct vnode *lvp,
    struct vnode *ldvp, struct ucred *cred, struct pefs_tkey *ptk)
{
	char *namebuf;
	char *encname;
	int error, encname_len, name_len;

	namebuf = malloc((MAXNAMLEN + 1)*2, M_PEFSBUF, M_WAITOK | M_ZERO);
	encname = namebuf + MAXNAMLEN + 1;
	encname_len = MAXNAMLEN + 1;

	error = pefs_node_lookup_name(lvp, ldvp, cred, encname, &encname_len);
	if (error != 0) {
		free(namebuf, M_PEFSBUF);
		return (error);
	}

	PEFSDEBUG("pefs_node_lookup_key: encname=%.*s\n", encname_len, encname);

	name_len = pefs_name_decrypt(NULL, pefs_rootkey(pm), ptk,
	    encname, encname_len, namebuf, MAXNAMLEN + 1);

	if (name_len > 0)
		pefs_key_ref(ptk->ptk_key);
	else
		PEFSDEBUG("pefs_node_lookup_key: not found: %.*s\n",
		    encname_len, encname);

	free(namebuf, M_PEFSBUF);

	return (error);
}
Пример #3
0
struct pefs_dircache_entry *
pefs_dircache_lookup(struct pefs_dircache *pd, char const *name,
    size_t name_len)
{
	struct pefs_dircache_entry *pde;
	struct pefs_dircache_listhead *head;
	uint32_t h;

	MPASS(pd != NULL);
	MPASS((pd->pd_flags & PD_UPDATING) == 0);
	MPASS(LIST_EMPTY(DIRCACHE_STALEHEAD(pd)));

	h = dircache_hashname(pd, name, name_len);
	head = &dircache_tbl[h & pefs_dircache_hashmask];
	mtx_lock(&dircache_mtx);
	LIST_FOREACH(pde, head, pde_hash_entry) {
		if (pde->pde_namehash == h &&
		    pde->pde_dircache == pd &&
		    pde->pde_gen == pd->pd_gen &&
		    pde->pde_namelen == name_len &&
		    memcmp(pde->pde_name, name, name_len) == 0) {
			mtx_unlock(&dircache_mtx);
			PEFSDEBUG("pefs_dircache_lookup: found %s -> %s\n",
			    pde->pde_name, pde->pde_encname);
			return (pde);
		}
	}
	mtx_unlock(&dircache_mtx);
	PEFSDEBUG("pefs_dircache_lookup: not found %s\n", name);
	return (NULL);
}
Пример #4
0
static void
dircache_update(struct pefs_dircache_entry *pde, int onlist)
{
	struct pefs_dircache *pd = pde->pde_dircache;

	sx_assert(&pd->pd_lock, SA_XLOCKED);

	if ((pd->pd_flags & PD_UPDATING) != 0) {
		PEFSDEBUG("pefs_dircache_update: %s -> %s\n",
		    pde->pde_name, pde->pde_encname);
		pde->pde_gen = pd->pd_gen;
		if (onlist != 0)
			LIST_REMOVE(pde, pde_dir_entry);
		LIST_INSERT_HEAD(DIRCACHE_ACTIVEHEAD(pd), pde, pde_dir_entry);
	} else if (pd->pd_gen == 0 || pd->pd_gen != pde->pde_gen) {
		PEFSDEBUG("pefs_dircache: inconsistent cache: "
		    "gen=%ld old_gen=%ld name=%s\n",
		    pd->pd_gen, pde->pde_gen, pde->pde_name);
		dircache_expire(pd);
		pde->pde_gen = 0;
		if (onlist == 0)
			LIST_INSERT_HEAD(DIRCACHE_STALEHEAD(pd), pde,
					pde_dir_entry);
	}
}
Пример #5
0
/*
 * Initialise cache headers
 */
int
pefs_init(struct vfsconf *vfsp)
{
	PEFSDEBUG("pefs_init\n");

	LIST_INIT(&pefs_node_freelist);

	TASK_INIT(&pefs_task_freenode, 0, pefs_node_free_proc, NULL);
	pefs_taskq = taskqueue_create("pefs_taskq", M_WAITOK,
	    taskqueue_thread_enqueue, &pefs_taskq);
	taskqueue_start_threads(&pefs_taskq, 1, PVFS, "pefs taskq");

	pefs_node_zone = uma_zcreate("pefs_node", sizeof(struct pefs_node),
	    NULL, NULL, NULL, (uma_fini) bzero, UMA_ALIGN_PTR, 0);

	pefs_nodehash_tbl = hashinit(desiredvnodes / 8, M_PEFSHASH,
	    &pefs_nodehash_mask);
	pefs_nodes = 0;
	mtx_init(&pefs_node_listmtx, "pefs_node_list", NULL, MTX_DEF);

	pefs_dircache_init();
	pefs_crypto_init();

	return (0);
}
Пример #6
0
void
pefs_dircache_abortupdate(struct pefs_dircache *pd)
{
	sx_assert(&pd->pd_lock, SA_XLOCKED);

	if ((pd->pd_flags & PD_UPDATING) != 0) {
		PEFSDEBUG("pefs_dircache_abortupdate: gen=%lu %p\n",
		    pd->pd_gen, pd);
		dircache_expire(pd);
		pd->pd_flags &= ~PD_UPDATING;
	}
	DIRCACHE_ASSERT(pd);
}
Пример #7
0
struct pefs_dircache_entry *
pefs_dircache_insert(struct pefs_dircache *pd, struct pefs_tkey *ptk,
    char const *name, size_t name_len,
    char const *encname, size_t encname_len)
{
	struct pefs_dircache_listhead *head;
	struct pefs_dircache_entry *pde;

	MPASS(ptk->ptk_key != NULL);
	sx_assert(&pd->pd_lock, SA_XLOCKED);

	if (name_len == 0 || name_len >= sizeof(pde->pde_name) ||
	    encname_len == 0 || encname_len >= sizeof(pde->pde_encname))
		panic("pefs: invalid file name length: %zd/%zd",
		    name_len, encname_len);

	pde = uma_zalloc(dircache_entry_zone, M_WAITOK | M_ZERO);
	pde->pde_dircache = pd;

	pde->pde_tkey = *ptk;
	pefs_key_ref(pde->pde_tkey.ptk_key);

	pde->pde_namelen = name_len;
	memcpy(pde->pde_name, name, name_len);
	pde->pde_name[name_len] = '\0';
	pde->pde_namehash = dircache_hashname(pd, pde->pde_name,
	    pde->pde_namelen);

	pde->pde_encnamelen = encname_len;
	memcpy(pde->pde_encname, encname, encname_len);
	pde->pde_encname[encname_len] = '\0';
	pde->pde_encnamehash = dircache_hashname(pd, pde->pde_encname,
	    pde->pde_encnamelen);

	/* Insert into list and set pge_gen */
	dircache_update(pde, 0);

	mtx_lock(&dircache_mtx);
	head = &dircache_tbl[pde->pde_namehash & pefs_dircache_hashmask];
	LIST_INSERT_HEAD(head, pde, pde_hash_entry);
	head = &dircache_enctbl[pde->pde_encnamehash & pefs_dircache_hashmask];
	LIST_INSERT_HEAD(head, pde, pde_enchash_entry);
	dircache_entries++;
	mtx_unlock(&dircache_mtx);

	PEFSDEBUG("pefs_dircache_insert: hash=%x enchash=%x: %s -> %s\n",
	    pde->pde_namehash, pde->pde_encnamehash,
	    pde->pde_name, pde->pde_encname);

	return (pde);
}
Пример #8
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);
}
Пример #9
0
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);
}
Пример #10
0
static void
dircache_expire(struct pefs_dircache *pd)
{
	struct pefs_dircache_entry *pde;

	pd->pd_gen = 0;
	if (LIST_EMPTY(DIRCACHE_STALEHEAD(pd))) {
		pd->pd_flags ^= PD_SWAPEDHEADS;
	} else while (!LIST_EMPTY(DIRCACHE_ACTIVEHEAD(pd))) {
		pde = LIST_FIRST(DIRCACHE_ACTIVEHEAD(pd));
		pde->pde_gen = 0;
		LIST_REMOVE(pde, pde_dir_entry);
		LIST_INSERT_HEAD(DIRCACHE_STALEHEAD(pd), pde, pde_dir_entry);
		PEFSDEBUG("dircache_expire: active entry: %p\n", pde);
	}
	MPASS(LIST_EMPTY(DIRCACHE_ACTIVEHEAD(pd)));
}
Пример #11
0
void
pefs_dircache_beginupdate(struct pefs_dircache *pd, u_long gen)
{
	if (sx_try_upgrade(&pd->pd_lock) == 0) {
		/* vnode should be locked to avoid races */
		sx_unlock(&pd->pd_lock);
		sx_xlock(&pd->pd_lock);
	}
	if (gen != 0 && pd->pd_gen != gen) {
		PEFSDEBUG("pefs_dircache_beginupdate: update: gen=%lu %p\n",
		    gen, pd);
		if (!LIST_EMPTY(DIRCACHE_ACTIVEHEAD(pd))) {
			/* Assert consistent state */
			MPASS(LIST_EMPTY(DIRCACHE_STALEHEAD(pd)));
			dircache_expire(pd);
		}
		pd->pd_gen = gen;
		pd->pd_flags |= PD_UPDATING;
		MPASS(LIST_EMPTY(DIRCACHE_ACTIVEHEAD(pd)));
	}
}
Пример #12
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);
}