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>