PERFORCE change 169442 for review
Gleb Kurtsou
gk at FreeBSD.org
Mon Oct 12 22:14:55 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=169442
Change 169442 by gk at 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
More information about the p4-projects
mailing list