Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Oct 2009 22:14:54 GMT
From:      Gleb Kurtsou <gk@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 169442 for review
Message-ID:  <200910122214.n9CMEsTS097255@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=169442

Change 169442 by gk@gk_h1 on 2009/10/12 22:14:48

	implement dircache (enabled by default)
	rename node hash routines

Affected files ...

.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#15 edit
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#15 edit
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_dircache.c#1 add
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_dircache.h#1 add
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#16 edit
.. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#22 edit
.. //depot/projects/soc2009/gk_pefs/sys/modules/pefs/Makefile#8 edit

Differences ...

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#15 (text+ko) ====

@@ -36,6 +36,7 @@
 #define PEFS_KEY_SIZE			(PEFS_KEY_BITS / 8)
 #define PEFS_KEYID_SIZE			8
 #define PEFS_NAME_CSUM_SIZE		8
+#define PEFS_NAME_BLOCK_SIZE		16
 
 struct pefs_xkey {
 	uint32_t pxk_index;
@@ -60,6 +61,8 @@
 
 struct pefs_alg;
 struct pefs_ctx;
+struct pefs_dircache;
+struct vfsconf;
 
 TAILQ_HEAD(pefs_key_head, pefs_key);
 
@@ -91,6 +94,7 @@
 	struct vnode *pn_lowervp;	/* VREFed once */
 	struct vnode *pn_lowervp_dead;	/* VREFed once */
 	struct vnode *pn_vnode;		/* Back pointer */
+	struct pefs_dircache *pn_dircache;
 	void *pn_buf_small;
 	void *pn_buf_large;
 	int pn_flags;
@@ -165,10 +169,6 @@
 		return (&pn->pn_buf_large);
 }
 
-struct vfsconf;
-struct vop_generic_args;
-struct pefs_ctx;
-
 int pefs_init(struct vfsconf *vfsp);
 int pefs_uninit(struct vfsconf *vfsp);
 void pefs_crypto_init(void);
@@ -252,8 +252,27 @@
 	    pefs_rootkey(VFS_TO_PEFS(vp->v_mount)) == NULL);
 }
 
+static inline uint32_t
+pefs_hash_mixptr(void *ptr)
+{
+	uintptr_t h = (uintptr_t)ptr;
+
+	h = (~h) + (h << 18);
+	h = h ^ (h >> 31);
+	h = h * 21;
+	h = h ^ (h >> 11);
+	h = h + (h << 6);
+	h = h ^ (h >> 22);
+	return (h);
+}
+
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_vfs_pefs);
+#endif
+
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_PEFSBUF);
+MALLOC_DECLARE(M_PEFSHASH);
 #endif
 
 #ifdef PEFS_DEBUG

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#15 (text+ko) ====

@@ -49,7 +49,6 @@
 #include <fs/pefs/vmac.h>
 
 #define PEFS_CTR_BLOCK_SIZE		16
-#define PEFS_NAME_BLOCK_SIZE		16
 
 CTASSERT(PEFS_KEY_SIZE <= SHA512_DIGEST_LENGTH);
 CTASSERT(PEFS_TWEAK_SIZE == 64/8);

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#16 (text+ko) ====

@@ -71,13 +71,15 @@
 #include <sys/queue.h>
 #include <sys/proc.h>
 #include <sys/sysctl.h>
+#include <sys/sx.h>
 #include <sys/uio.h>
 #include <sys/taskqueue.h>
 #include <sys/vnode.h>
 
 #include <fs/pefs/pefs.h>
+#include <fs/pefs/pefs_dircache.h>
 
-static SYSCTL_NODE(_vfs, OID_AUTO, pefs, CTLFLAG_RW, 0, "PEFS filesystem");
+SYSCTL_NODE(_vfs, OID_AUTO, pefs, CTLFLAG_RW, 0, "PEFS filesystem");
 
 typedef int (pefs_node_init_fn)(struct mount *mp, struct pefs_node *pn,
     void *context);
@@ -91,10 +93,10 @@
 static struct mtx pefs_node_listmtx;
 
 static struct pefs_node_listhead pefs_node_freelist;
-static struct pefs_node_listhead *pefs_node_hashtbl;
-static u_long pefs_node_hashmask;
+static struct pefs_node_listhead *pefs_nodehash_tbl;
+static u_long pefs_nodehash_mask;
 
-static MALLOC_DEFINE(M_PEFSHASH, "pefs_hash", "PEFS hash table");
+MALLOC_DEFINE(M_PEFSHASH, "pefs_hash", "PEFS hash table");
 MALLOC_DEFINE(M_PEFSBUF, "pefs_buf", "PEFS buffers");
 
 static uma_zone_t pefs_node_zone;
@@ -121,11 +123,12 @@
 	pefs_node_zone = uma_zcreate("pefs_node", sizeof(struct pefs_node),
 	    NULL, NULL, NULL, (uma_fini) bzero, UMA_ALIGN_PTR, 0);
 
-	pefs_node_hashtbl = hashinit(desiredvnodes / 8, M_PEFSHASH,
-	    &pefs_node_hashmask);
+	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);
@@ -137,26 +140,21 @@
 	taskqueue_enqueue(pefs_taskq, &pefs_task_freenode);
 	taskqueue_drain(pefs_taskq, &pefs_task_freenode);
 	taskqueue_free(pefs_taskq);
+	pefs_dircache_uninit();
 	pefs_crypto_uninit();
 	mtx_destroy(&pefs_node_listmtx);
-	free(pefs_node_hashtbl, M_PEFSHASH);
+	free(pefs_nodehash_tbl, M_PEFSHASH);
 	uma_zdestroy(pefs_node_zone);
 	return (0);
 }
 
 static inline struct pefs_node_listhead *
-pefs_node_hashlookup(struct vnode *vp)
+pefs_nodehash_gethead(struct vnode *vp)
 {
-	uintptr_t v = (uintptr_t)vp;
+	uint32_t v;
 
-	v = (~v) + (v << 18);
-	v = v ^ (v >> 31);
-	v = v * 21;
-	v = v ^ (v >> 11);
-	v = v + (v << 6);
-	v = v ^ (v >> 22);
-
-	return (&pefs_node_hashtbl[v & pefs_node_hashmask]);
+	v = pefs_hash_mixptr(vp);
+	return (&pefs_nodehash_tbl[v & pefs_nodehash_mask]);
 }
 
 /*
@@ -164,13 +162,13 @@
  * Lower vnode should be locked on entry and will be left locked on exit.
  */
 static struct vnode *
-pefs_hashget(struct mount *mp, struct vnode *lowervp)
+pefs_nodehash_get(struct mount *mp, struct vnode *lowervp)
 {
 	struct pefs_node_listhead *hd;
 	struct pefs_node *a;
 	struct vnode *vp;
 
-	ASSERT_VOP_LOCKED(lowervp, "pefs_hashget");
+	ASSERT_VOP_LOCKED(lowervp, "pefs_nodehash_get");
 
 	/*
 	 * Find hash base, and then search the (two-way) linked
@@ -178,7 +176,7 @@
 	 * the lower vnode.  If found, the increment the pefs_node
 	 * reference count (but NOT the lower vnode's VREF counter).
 	 */
-	hd = pefs_node_hashlookup(lowervp);
+	hd = pefs_nodehash_gethead(lowervp);
 	mtx_lock(&pefs_node_listmtx);
 	LIST_FOREACH(a, hd, pn_listentry) {
 		if (a->pn_lowervp == lowervp && PN_TO_VP(a)->v_mount == mp) {
@@ -199,23 +197,23 @@
 }
 
 /*
- * Act like pefs_hashget, but add passed pefs_node to hash if no existing
+ * Act like pefs_nodehash_get, but add passed pefs_node to hash if no existing
  * node found.
  */
 static struct vnode *
-pefs_hashins(struct mount *mp, struct pefs_node *pn)
+pefs_nodehash_insert(struct mount *mp, struct pefs_node *pn)
 {
 	struct pefs_node_listhead *hd;
 	struct pefs_node *oxp;
 	struct vnode *ovp;
 
-	hd = pefs_node_hashlookup(pn->pn_lowervp);
+	hd = pefs_nodehash_gethead(pn->pn_lowervp);
 	mtx_lock(&pefs_node_listmtx);
 	LIST_FOREACH(oxp, hd, pn_listentry) {
 		if (oxp->pn_lowervp == pn->pn_lowervp &&
 		    PN_TO_VP(oxp)->v_mount == mp) {
 			/*
-			 * See pefs_hashget for a description of this
+			 * See pefs_nodehash_get for a description of this
 			 * operation.
 			 */
 			ovp = PN_TO_VP(oxp);
@@ -370,8 +368,8 @@
  * 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.
+ * 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,
@@ -382,7 +380,7 @@
 	int error;
 
 	/* Lookup the hash firstly */
-	*vpp = pefs_hashget(mp, lvp);
+	*vpp = pefs_nodehash_get(mp, lvp);
 	if (*vpp != NULL) {
 		vrele(lvp);
 		return (0);
@@ -437,7 +435,7 @@
 	 * Atomically insert our new node into the hash or vget existing
 	 * if someone else has beaten us to it.
 	 */
-	*vpp = pefs_hashins(mp, pn);
+	*vpp = pefs_nodehash_insert(mp, pn);
 	if (*vpp != NULL) {
 		vrele(lvp);
 		vp->v_vnlock = &vp->v_lock;
@@ -445,6 +443,8 @@
 		vrele(vp);
 		return (0);
 	}
+	if (vp->v_type == VDIR)
+		pn->pn_dircache = pefs_dircache_get();
 	*vpp = vp;
 
 	return (0);
@@ -512,6 +512,7 @@
 {
 	PEFSDEBUG("pefs_node_asyncfree: free node %p\n", pn);
 	pefs_key_release(pn->pn_tkey.ptk_key);
+	pefs_dircache_free(pn->pn_dircache);
 	mtx_lock(&pefs_node_listmtx);
 	pefs_nodes--;
 	LIST_REMOVE(pn, pn_listentry);

==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#22 (text+ko) ====

@@ -72,6 +72,7 @@
 #include <sys/namei.h>
 #include <sys/sf_buf.h>
 #include <sys/sysctl.h>
+#include <sys/sx.h>
 #include <sys/vnode.h>
 #include <sys/dirent.h>
 #include <sys/limits.h>
@@ -86,6 +87,7 @@
 #include <vm/vnode_pager.h>
 
 #include <fs/pefs/pefs.h>
+#include <fs/pefs/pefs_dircache.h>
 
 #define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN + 1))
 #define DIRENT_MAXSIZE (sizeof(struct dirent))
@@ -96,6 +98,43 @@
 	struct pefs_tkey pec_tkey;
 };
 
+static inline u_long
+pefs_getgen(struct vnode *vp, struct ucred *cred)
+{
+	struct vattr va;
+	int error;
+
+	error = VOP_GETATTR(PEFS_LOWERVP(vp), &va, cred);
+	if (error != 0)
+		return (0);
+
+	return (va.va_gen);
+}
+
+static struct pefs_dircache_entry *
+pefs_cache_dirent(struct pefs_dircache *pd, struct dirent *de,
+    struct pefs_ctx *ctx, struct pefs_key *pk)
+{
+	struct pefs_dircache_entry *cache;
+	struct pefs_tkey ptk;
+	char buf[MAXNAMLEN + 1];
+	int name_len;
+
+	cache = pefs_dircache_enclookup(pd, de->d_name, de->d_namlen);
+	if (cache != NULL) {
+		pefs_dircache_update(cache);
+	} else {
+		name_len = pefs_name_decrypt(ctx, pk, &ptk,
+		    de->d_name, de->d_namlen, buf, sizeof(buf));
+		if (name_len <= 0)
+			return (NULL);
+		cache = pefs_dircache_insert(pd, &ptk,
+		    buf, name_len, de->d_name, de->d_namlen);
+	}
+
+	return (cache);
+}
+
 static inline int
 pefs_name_skip(char *name, int namelen)
 {
@@ -205,17 +244,16 @@
 	return (error);
 }
 
-static struct dirent*
-pefs_enccn_lookup_dirent(struct pefs_key *pk, struct pefs_tkey *ptk,
-    void *mem, size_t sz, char *name, size_t namelen)
+static void
+pefs_enccn_parsedir(struct pefs_dircache *pd, struct pefs_ctx *ctx,
+    struct pefs_key *pk, void *mem, size_t sz, char *name, size_t name_len,
+    struct pefs_dircache_entry **retval)
 {
-	struct pefs_ctx *ctx;
+	struct pefs_dircache_entry *cache;
 	struct dirent *de;
-	char buf[MAXNAMLEN + 1];
-	int d_namelen;
 
-	PEFSDEBUG("pefs_enccn_lookup_dirent: lookup %.*s\n", (int)namelen, name);
-	ctx = pefs_ctx_get();
+	PEFSDEBUG("pefs_enccn_parsedir: lookup %.*s\n", (int)name_len, name);
+	cache = NULL;
 	for (de = (struct dirent*) mem; sz > DIRENT_MINSIZE;
 			sz -= de->d_reclen,
 			de = (struct dirent *)(((caddr_t)de) + de->d_reclen)) {
@@ -224,29 +262,29 @@
 			continue;
 		if (pefs_name_skip(de->d_name, de->d_namlen))
 			continue;
-		d_namelen = pefs_name_decrypt(ctx, pk, ptk, de->d_name,
-		    de->d_namlen, buf, sizeof(buf));
-		if (d_namelen == namelen && memcmp(name, buf, namelen) == 0) {
-			pefs_ctx_free(ctx);
-			return (de);
+
+		cache = pefs_cache_dirent(pd, de, ctx, pk);
+		if (cache != NULL && *retval == NULL &&
+		    cache->pde_namelen == name_len &&
+		    memcmp(name, cache->pde_name, name_len) == 0) {
+			*retval = cache;
 		}
 	}
-	pefs_ctx_free(ctx);
-	return (NULL);
 }
 
 static int
 pefs_enccn_lookup(struct pefs_enccn *pec, struct vnode *dvp,
     struct componentname *cnp)
 {
-	struct dirent *de;
 	struct uio *uio;
 	struct vnode *ldvp = PEFS_LOWERVP(dvp);
 	struct pefs_node *dpn = VP_TO_PN(dvp);
 	struct pefs_chunk pc;
+	struct pefs_ctx *ctx;
+	struct pefs_dircache_entry *cache;
 	struct pefs_key *dpn_key;
-	struct pefs_tkey ptk;
 	off_t offset;
+	u_long dgen;
 	int eofflag, error;
 
 	MPASS(pec != NULL && dvp != NULL && cnp != NULL);
@@ -261,13 +299,23 @@
 	PEFSDEBUG("pefs_enccn_lookup: name=%.*s op=%d\n",
 	    (int)cnp->cn_namelen, cnp->cn_nameptr, (int) cnp->cn_nameiop);
 
-	pefs_chunk_create(&pc, dpn, PAGE_SIZE);
+	error = 0;
+	dgen = pefs_getgen(dvp, cnp->cn_cred);
+	pefs_dircache_lock(dpn->pn_dircache);
+	if (pefs_dircache_enable &&
+	    pefs_dircache_valid(dpn->pn_dircache, dgen)) {
+		cache = pefs_dircache_lookup(dpn->pn_dircache,
+		    cnp->cn_nameptr, cnp->cn_namelen);
+		goto out;
+	}
+
 	offset = 0;
 	eofflag = 0;
-	error = 0;
-	de = NULL;
-	ptk.ptk_key = NULL;
+	cache = NULL;
+	ctx = pefs_ctx_get();
+	pefs_chunk_create(&pc, dpn, PAGE_SIZE);
 	dpn_key = pefs_node_key(dpn);
+	pefs_dircache_beginupdate(dpn->pn_dircache, dgen);
 	while (!eofflag) {
 		uio = pefs_chunk_uio(&pc, offset, UIO_READ);
 		error = VOP_READDIR(ldvp, uio, cnp->cn_cred, &eofflag,
@@ -277,23 +325,25 @@
 		offset = uio->uio_offset;
 
 		pefs_chunk_setsize(&pc, pc.pc_size - uio->uio_resid);
-		de = pefs_enccn_lookup_dirent(dpn_key, &ptk,
-		    pc.pc_base, pc.pc_size,
-		    cnp->cn_nameptr, cnp->cn_namelen);
-		if (de != NULL)
-			break;
+		pefs_enccn_parsedir(dpn->pn_dircache, ctx, dpn_key,
+		    pc.pc_base, pc.pc_size, cnp->cn_nameptr, cnp->cn_namelen,
+		    &cache);
 		pefs_chunk_restore(&pc);
 	}
+	pefs_dircache_endupdate(dpn->pn_dircache);
 
-	if (de != NULL && error == 0) {
-		pefs_enccn_set(pec, &ptk, de->d_name, de->d_namlen, cnp);
-	}
-
+	pefs_ctx_free(ctx);
 	pefs_key_release(dpn_key);
 	pefs_chunk_free(&pc, dpn);
+out:
+	if (cache != NULL && error == 0)
+		pefs_enccn_set(pec, &cache->pde_tkey,
+		    cache->pde_encname, cache->pde_encnamelen, cnp);
+	else if (cache == NULL && error == 0)
+		error = ENOENT;
+
+	pefs_dircache_unlock(dpn->pn_dircache);
 
-	if (de == NULL && error == 0)
-		return (ENOENT);
 	return (error);
 }
 
@@ -1132,15 +1182,13 @@
 }
 
 static void
-pefs_readdir_decrypt(struct pefs_key *pk, int dflags, void *mem, size_t *psize)
+pefs_readdir_decrypt(struct pefs_dircache *pd, struct pefs_ctx *ctx,
+    struct pefs_key *pk, int dflags, void *mem, size_t *psize)
 {
-	struct pefs_ctx *ctx;
+	struct pefs_dircache_entry *cache;
 	struct dirent *de, *de_next;
-	char buf[MAXNAMLEN + 1];
 	size_t sz;
-	int d_namelen;
 
-	ctx = pefs_ctx_get();
 	for (de = (struct dirent*) mem, sz = *psize; sz > DIRENT_MINSIZE;
 	    de = de_next) {
 		MPASS(de->d_reclen <= sz);
@@ -1148,22 +1196,20 @@
 		de_next = (struct dirent *)(((caddr_t)de) + de->d_reclen);
 		if (de->d_type == DT_WHT)
 			continue;
-
 		if (pefs_name_skip(de->d_name, de->d_namlen))
 			continue;
-		d_namelen = pefs_name_decrypt(ctx, pk, NULL,
-		    de->d_name, de->d_namlen, buf, sizeof(buf));
-		if (d_namelen > 0) {
+		cache = pefs_cache_dirent(pd, de, ctx, pk);
+		if (cache != NULL) {
 			/* Do not change d_reclen */
-			strlcpy(de->d_name, buf, de->d_namlen + 1);
-			de->d_namlen = d_namelen;
+			MPASS(cache->pde_namelen <= de->d_namlen);
+			memcpy(de->d_name, cache->pde_name, cache->pde_namelen + 1);
+			de->d_namlen = cache->pde_encnamelen;
 		} else if (dflags & PN_HASKEY) {
 			*psize -= de->d_reclen;
 			memcpy(de, de_next, sz);
 			de_next = de;
 		}
 	}
-	pefs_ctx_free(ctx);
 }
 
 static int
@@ -1178,8 +1224,10 @@
 	struct pefs_node *pn = VP_TO_PN(vp);
 	struct pefs_key *pn_key;
 	struct pefs_chunk pc;
+	struct pefs_ctx *ctx;
+	size_t mem_size;
+	u_long gen;
 	int error;
-	size_t mem_size;
 	int r_ncookies = 0, r_ncookies_max = 0, ncookies = 0;
 	u_long *r_cookies = NULL, *cookies = NULL;
 	int *a_ncookies;
@@ -1199,8 +1247,14 @@
 		a_cookies = &cookies;
 	}
 
+	gen = pefs_getgen(vp, cred);
+	ctx = pefs_ctx_get();
 	pefs_chunk_create(&pc, pn, qmin(uio->uio_resid, DFLTPHYS));
 	pn_key = pefs_node_key(pn);
+	pefs_dircache_lock(pn->pn_dircache);
+	if (!pefs_dircache_valid(pn->pn_dircache, gen) && uio->uio_offset != 0)
+		gen = 0;
+	pefs_dircache_beginupdate(pn->pn_dircache, gen);
 	while (1) {
 		if (uio->uio_resid < pc.pc_size)
 			pefs_chunk_setsize(&pc, uio->uio_resid);
@@ -1214,7 +1268,9 @@
 			break;
 		pefs_chunk_setsize(&pc, pc.pc_size - puio->uio_resid);
 		mem_size = pc.pc_size;
-		pefs_readdir_decrypt(pn_key, pn->pn_flags,
+		if (!*eofflag)
+			pefs_dircache_abortupdate(pn->pn_dircache);
+		pefs_readdir_decrypt(pn->pn_dircache, ctx, pn_key, pn->pn_flags,
 		    pc.pc_base, &mem_size);
 		pefs_chunk_setsize(&pc, mem_size);
 		pefs_chunk_copy(&pc, uio);
@@ -1253,6 +1309,10 @@
 
 		pefs_chunk_restore(&pc);
 	}
+	if (*eofflag && error == 0)
+		pefs_dircache_endupdate(pn->pn_dircache);
+	else
+		pefs_dircache_abortupdate(pn->pn_dircache);
 
 	if (error == 0 && a_cookies != NULL) {
 		if (r_cookies != NULL) {
@@ -1264,6 +1324,8 @@
 		}
 	}
 
+	pefs_dircache_unlock(pn->pn_dircache);
+	pefs_ctx_free(ctx);
 	pefs_key_release(pn_key);
 	pefs_chunk_free(&pc, pn);
 

==== //depot/projects/soc2009/gk_pefs/sys/modules/pefs/Makefile#8 (text+ko) ====

@@ -5,6 +5,7 @@
 KMOD=	pefs
 SRCS=	vnode_if.h \
 	pefs_subr.c pefs_vfsops.c pefs_vnops.c pefs_xbase64.c pefs_crypto.c \
+	pefs_dircache.c \
 	pefs_hmac.c vmac.c
 DEBUG_FLAGS+= -g
 #DEBUG_FLAGS+= -DPEFS_DEBUG



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910122214.n9CMEsTS097255>