From owner-p4-projects@FreeBSD.ORG Tue Jun 30 10:52:33 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 50D4210656CE; Tue, 30 Jun 2009 10:52:33 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0D3EC10656B7 for ; Tue, 30 Jun 2009 10:52:31 +0000 (UTC) (envelope-from gk@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 38C5F8FC0A for ; Tue, 30 Jun 2009 10:52:31 +0000 (UTC) (envelope-from gk@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n5UAqVp6092058 for ; Tue, 30 Jun 2009 10:52:31 GMT (envelope-from gk@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n5UAqV7b092056 for perforce@freebsd.org; Tue, 30 Jun 2009 10:52:31 GMT (envelope-from gk@FreeBSD.org) Date: Tue, 30 Jun 2009 10:52:31 GMT Message-Id: <200906301052.n5UAqV7b092056@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to gk@FreeBSD.org using -f From: Gleb Kurtsou To: Perforce Change Reviews Cc: Subject: PERFORCE change 165463 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 30 Jun 2009 10:52:34 -0000 http://perforce.freebsd.org/chv.cgi?CH=165463 Change 165463 by gk@gk_h1 on 2009/06/30 10:52:23 Store tweak and checksum in encrypted file name. Update lookup routines to perform readdir to do real lookup Do not use pefs_bypass as vnode bypass operation Add vop_mknode Use cached lookup Affected files ... .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#4 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#1 add .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#4 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#3 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#4 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_xbase64.c#3 edit .. //depot/projects/soc2009/gk_pefs/sys/modules/pefs/Makefile#4 edit Differences ... ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#4 (text+ko) ==== @@ -37,62 +37,115 @@ * $FreeBSD$ */ +#include #include -struct pefs_mount { - struct mount *pm_vfs; - struct vnode *pm_rootvp; /* Reference to root pefs_node */ +#ifdef _KERNEL + +#define PEFS_BLOCK 16 +#define PEFS_TWEAK_SIZE 16 +#define PEFS_KEY_SIZE 64 +#define PEFS_NAME_CSUM_SIZE 2 + +#define PEFS_NAME_NTOP_SIZE(a) (((a) * 4 + 2)/3) +#define PEFS_NAME_PTON_SIZE(a) (((a) * 3)/4) + +SLIST_HEAD(pefs_key_head, pefs_key); + +struct pefs_key { + SLIST_ENTRY(pefs_key) pk_entry; + volatile u_int pk_refcnt; + char pk_name[PEFS_KEY_SIZE]; + char pk_data[PEFS_KEY_SIZE]; }; -#ifdef _KERNEL +struct pefs_node_key { + struct pefs_key *pnk_key; + char pnk_tweak[PEFS_TWEAK_SIZE]; +}; -#define PEFS_BLOCK 16 +struct pefs_node { + LIST_ENTRY(pefs_node) pn_hash; /* Hash list */ + struct vnode *pn_lowervp; /* VREFed once */ + struct vnode *pn_vnode; /* Back pointer */ + struct pefs_node_key pn_key; +}; -/* - * A cache of vnode references - */ -struct pefs_node { - LIST_ENTRY(pefs_node) pn_hash; /* Hash list */ - struct vnode *pn_lowervp; /* VREFed once */ - struct vnode *pn_vnode; /* Back pointer */ +struct pefs_mount { + struct mount *pm_vfs; + struct vnode *pm_rootvp; /* Reference to root pefs_node */ + struct pefs_key_head pm_keys; }; struct pefs_chunk { int pc_iovcnt; int pc_basescnt; struct iovec *pc_iov; - int pc_size; + size_t pc_size; + size_t pc_capacity; void **pc_bases; struct uio pc_uio; }; -typedef void (*pefs_tr)(void *mem, size_t size, void *arg); +static inline struct pefs_mount* +VFS_TO_PEFS(struct mount *mp) +{ + MPASS(mp != NULL && mp->mnt_data != NULL); + return ((struct pefs_mount *)(mp->mnt_data)); +} + +static inline struct pefs_node* +VP_TO_PN(struct vnode *vp) +{ + MPASS(vp != NULL && vp->v_data != NULL); + return ((struct pefs_node *)vp->v_data); +} + +static inline struct vnode* +PN_TO_VP(struct pefs_node *pn) +{ + MPASS(pn != NULL && pn->pn_vnode != NULL); + return (pn->pn_vnode); +} + +#ifdef DIAGNOSTIC +struct vnode *pefs_checkvp(struct vnode *vp, char *fil, int lno); +#endif + +static inline struct vnode* +PEFS_LOWERVP(struct vnode *vp) +{ + struct vnode *lvp; -#define MOUNTTOPEMOUNT(mp) ((struct pefs_mount *)((mp)->mnt_data)) -#define VTOPE(vp) ((struct pefs_node *)(vp)->v_data) -#define PETOV(xp) ((xp)->pn_vnode) + MPASS(vp != NULL); +#ifdef DIAGNOSTIC + pefs_checkvp((vp), __FILE__, __LINE__); +#endif + lvp = VP_TO_PN(vp)->pn_lowervp; + MPASS(lvp != NULL); + return (lvp); +} struct vfsconf; struct vop_generic_args; int pefs_init(struct vfsconf *vfsp); int pefs_uninit(struct vfsconf *vfsp); -int pefs_nodeget(struct mount *mp, struct vnode *target, struct vnode **vpp); -void pefs_hashrem(struct pefs_node *xp); -int pefs_bypass(struct vop_generic_args *ap); -int pefs_name_encrypt(const char *plain, size_t plain_len, char *enc, size_t enc_size); -int pefs_name_decrypt(const char *enc, size_t enc_len, char *plain, size_t plain_size); +int pefs_node_get(struct mount *mp, struct vnode *target, struct vnode **vpp); +void pefs_node_free(struct pefs_node *xp); -void pefs_xor(void *mem, size_t size); +void pefs_data_encrypt(struct pefs_node *pn, off_t offset, struct pefs_chunk *pc); +void pefs_data_encrypt_buf(struct pefs_node *pn, off_t offset, void *mem, size_t size); +void pefs_data_decrypt(struct pefs_node *pn, off_t offset, struct pefs_chunk *pc); +void pefs_data_decrypt_buf(struct pefs_node *pn, off_t offset, void *mem, size_t size); -#define PEFS_NAME_NTOP_SIZE(a) (((a) * 4 + 2)/3) -#define PEFS_NAME_PTON_SIZE(a) (((a) * 3)/4) +int pefs_name_encrypt(struct pefs_node_key *pnk, const char *plain, size_t plain_len, char *enc, size_t enc_size); +int pefs_name_decrypt(struct pefs_node_key *pnk, const char *enc, size_t enc_len, char *plain, size_t plain_size); int pefs_name_ntop(u_char const *src, size_t srclength, char *target, size_t targsize); int pefs_name_pton(char const *src, size_t srclen, u_char *target, size_t targsize); -void pefs_xor_chunk(struct pefs_chunk *pc); - struct pefs_chunk* pefs_chunk_create(size_t size); +void pefs_chunk_restore(struct pefs_chunk* pc); void pefs_chunk_free(struct pefs_chunk* pc); struct uio* pefs_chunk_uio(struct pefs_chunk *pc, off_t uio_offset, enum uio_rw uio_rw); struct uio* pefs_chunk_uio_range(struct pefs_chunk *pc, size_t skip, size_t size, off_t uio_offset, enum uio_rw uio_rw); @@ -102,17 +155,9 @@ void pefs_chunk_crop(struct pefs_chunk *pc, size_t skip_begin, size_t skip_end); void pefs_chunk_shrink(struct pefs_chunk *pc, size_t size); -#ifdef DIAGNOSTIC -struct vnode *pefs_checkvp(struct vnode *vp, char *fil, int lno); -#define PEVPTOLOWERVP(vp) pefs_checkvp((vp), __FILE__, __LINE__) -#else -#define PEVPTOLOWERVP(vp) (VTOPE(vp)->pn_lowervp) -#endif - extern struct vop_vector pefs_vnodeops; #ifdef MALLOC_DECLARE -MALLOC_DECLARE(M_PEFSNODE); MALLOC_DECLARE(M_PEFSBUF); #endif ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#4 (text+ko) ==== @@ -69,7 +69,7 @@ struct mtx pefs_hashmtx; static MALLOC_DEFINE(M_PEFSHASH, "pefs_hash", "PEFS hash table"); -MALLOC_DEFINE(M_PEFSNODE, "pefs_node", "PEFS vnode private part"); +static MALLOC_DEFINE(M_PEFSNODE, "pefs_node", "PEFS vnode private part"); MALLOC_DEFINE(M_PEFSBUF, "pefs_buf", "PEFS buffers"); /* @@ -117,14 +117,14 @@ hd = PEFS_NHASH(lowervp); mtx_lock(&pefs_hashmtx); LIST_FOREACH(a, hd, pn_hash) { - if (a->pn_lowervp == lowervp && PETOV(a)->v_mount == mp) { + if (a->pn_lowervp == lowervp && PN_TO_VP(a)->v_mount == mp) { /* * Since we have the lower node locked the pefs * node can not be in the process of recycling. If * it had been recycled before we grabed the lower * lock it would not have been found on the hash. */ - vp = PETOV(a); + vp = PN_TO_VP(a); vref(vp); mtx_unlock(&pefs_hashmtx); return (vp); @@ -149,12 +149,12 @@ mtx_lock(&pefs_hashmtx); LIST_FOREACH(oxp, hd, pn_hash) { if (oxp->pn_lowervp == xp->pn_lowervp && - PETOV(oxp)->v_mount == mp) { + PN_TO_VP(oxp)->v_mount == mp) { /* * See pefs_hashget for a description of this * operation. */ - ovp = PETOV(oxp); + ovp = PN_TO_VP(oxp); vref(ovp); mtx_unlock(&pefs_hashmtx); return (ovp); @@ -186,7 +186,7 @@ * the caller's "spare" reference to created pefs vnode. */ int -pefs_nodeget(struct mount *mp, struct vnode *lowervp, struct vnode **vpp) +pefs_node_get(struct mount *mp, struct vnode *lowervp, struct vnode **vpp) { struct pefs_node *xp; struct vnode *vp; @@ -213,7 +213,7 @@ * elsewhere if MALLOC should block. */ xp = malloc(sizeof(struct pefs_node), - M_PEFSNODE, M_WAITOK); + M_PEFSNODE, M_WAITOK | M_ZERO); error = getnewvnode("pefs", mp, &pefs_vnodeops, &vp); if (error) { @@ -227,7 +227,7 @@ vp->v_data = xp; vp->v_vnlock = lowervp->v_vnlock; if (vp->v_vnlock == NULL) - panic("pefs_nodeget: Passed a NULL vnlock.\n"); + panic("pefs_node_get: Passed a NULL vnlock.\n"); error = insmntque1(vp, mp, pefs_insmntque_dtr, xp); if (error != 0) return (error); @@ -249,82 +249,18 @@ } /* - * Remove node from hash. + * Remove node from hash and free it. */ void -pefs_hashrem(struct pefs_node *xp) +pefs_node_free(struct pefs_node *xp) { mtx_lock(&pefs_hashmtx); LIST_REMOVE(xp, pn_hash); mtx_unlock(&pefs_hashmtx); + free(xp, M_PEFSNODE); } -void -pefs_xor(void *mem, size_t size) -{ - char *b = (char *)mem; - char *e = b + size; - - for (; b < e; b++) { - *b ^= 0xAA; - } -} - -void -pefs_xor_chunk(struct pefs_chunk *pc) -{ - long arg = 0; - char *mem; - size_t size; - - while (1) { - mem = pefs_chunk_get(pc, &size, &arg); - if (mem == NULL) - break; - pefs_xor(mem, size); - } -} - -int -pefs_name_encrypt(const char *plain, size_t plain_len, char *enc, size_t enc_size) -{ - char b_static[64]; - char *b; - int r; - - if (plain_len <= sizeof(b_static)) - b = b_static; - else - b = malloc(plain_len, M_PEFSBUF, M_WAITOK); - memcpy(b, plain, plain_len); - // FIXME - for (int i = 0; i < plain_len; i++) - b[i] ^= 0xAA; - r = pefs_name_ntop(b, plain_len, enc, enc_size); - // printf("pefs_name_encrypt: %d; %.*s => %.*s\n", r, plain_len, plain, r, enc); - if (b != b_static) - free(b, M_PEFSBUF); - return r; -} - -int -pefs_name_decrypt(const char *enc, size_t enc_len, char *plain, size_t plain_size) -{ - int r; - - r = pefs_name_pton(enc, enc_len, plain, plain_size); - if (r > 0) { - // FIXME - for (int i = 0; i < r; i++) - plain[i] ^= 0xAA; - } - if (r < plain_size) - plain[r] = '\0'; - // printf("pefs_name_decrypt: %d; %.*s => %.*s\n", r, enc_len, enc, r < 0 ? 0 : r, plain); - return r; -} - struct pefs_chunk* pefs_chunk_create(size_t size) { @@ -357,6 +293,21 @@ } void +pefs_chunk_restore(struct pefs_chunk* pc) +{ + size_t size = pc->pc_capacity; + pc->pc_iov = (struct iovec *)(pc->pc_bases + pc->pc_basescnt); + pc->pc_iovcnt = pc->pc_basescnt; + + for (int i = 0; i < pc->pc_iovcnt && size > 0; i++) { + int len = imin(PAGE_SIZE, size); + pc->pc_iov[i].iov_len = len; + pc->pc_iov[i].iov_base = pc->pc_bases[i]; + size -= len; + } +} + +void pefs_chunk_free(struct pefs_chunk* pc) { for (int i = 0; i < pc->pc_basescnt; i++) { @@ -518,7 +469,7 @@ pefs_checkvp(struct vnode *vp, char *fil, int lno) { int interlock = 0; - struct pefs_node *a = VTOPE(vp); + struct pefs_node *a = VP_TO_PN(vp); #ifdef notyet /* * Can't do this check because vop_reclaim runs @@ -559,7 +510,7 @@ VI_LOCK(vp); #ifdef notyet printf("null %x/%d -> %x/%d [%s, %d]\n", - PETOV(a), vrefcnt(PETOV(a)), + PN_TO_VP(a), vrefcnt(PN_TO_VP(a)), a->pn_lowervp, vrefcnt(a->pn_lowervp), fil, lno); #endif ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#3 (text+ko) ==== @@ -123,7 +123,7 @@ /* * Check multi null mount to avoid `lock against myself' panic. */ - if (lowerrootvp == VTOPE(mp->mnt_vnodecovered)->pn_lowervp) { + if (lowerrootvp == VP_TO_PN(mp->mnt_vnodecovered)->pn_lowervp) { PEFSDEBUG("pefs_mount: multi null mount?\n"); vput(lowerrootvp); return (EDEADLK); @@ -141,7 +141,7 @@ * Save reference. Each mount also holds * a reference on the root vnode. */ - error = pefs_nodeget(mp, lowerrootvp, &vp); + error = pefs_node_get(mp, lowerrootvp, &vp); /* * Make sure the node alias worked */ @@ -165,7 +165,7 @@ */ VOP_UNLOCK(vp, 0); - if (PEVPTOLOWERVP(pm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { + if (PEFS_LOWERVP(pm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; MNT_IUNLOCK(mp); @@ -218,13 +218,13 @@ struct vnode *vp; PEFSDEBUG("pefs_root(mp = %p, vp = %p->%p)\n", (void *)mp, - (void *)MOUNTTOPEMOUNT(mp)->pm_rootvp, - (void *)PEVPTOLOWERVP(MOUNTTOPEMOUNT(mp)->pm_rootvp)); + (void *)VFS_TO_PEFS(mp)->pm_rootvp, + (void *)PEFS_LOWERVP(VFS_TO_PEFS(mp)->pm_rootvp)); /* * Return locked reference to root. */ - vp = MOUNTTOPEMOUNT(mp)->pm_rootvp; + vp = VFS_TO_PEFS(mp)->pm_rootvp; VREF(vp); #ifdef PEFSXXX_DEBUG @@ -239,7 +239,7 @@ static int pefs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg) { - return VFS_QUOTACTL(MOUNTTOPEMOUNT(mp)->pm_vfs, cmd, uid, arg); + return VFS_QUOTACTL(VFS_TO_PEFS(mp)->pm_vfs, cmd, uid, arg); } static int @@ -249,12 +249,12 @@ struct statfs mstat; PEFSDEBUG("pefs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, - (void *)MOUNTTOPEMOUNT(mp)->pm_rootvp, - (void *)PEVPTOLOWERVP(MOUNTTOPEMOUNT(mp)->pm_rootvp)); + (void *)VFS_TO_PEFS(mp)->pm_rootvp, + (void *)PEFS_LOWERVP(VFS_TO_PEFS(mp)->pm_rootvp)); bzero(&mstat, sizeof(mstat)); - error = VFS_STATFS(MOUNTTOPEMOUNT(mp)->pm_vfs, &mstat); + error = VFS_STATFS(VFS_TO_PEFS(mp)->pm_vfs, &mstat); if (error) return (error); @@ -284,11 +284,11 @@ pefs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { int error; - error = VFS_VGET(MOUNTTOPEMOUNT(mp)->pm_vfs, ino, flags, vpp); + error = VFS_VGET(VFS_TO_PEFS(mp)->pm_vfs, ino, flags, vpp); if (error) return (error); - return (pefs_nodeget(mp, *vpp, vpp)); + return (pefs_node_get(mp, *vpp, vpp)); } static int @@ -296,11 +296,11 @@ { int error; - error = VFS_FHTOVP(MOUNTTOPEMOUNT(mp)->pm_vfs, fidp, vpp); + error = VFS_FHTOVP(VFS_TO_PEFS(mp)->pm_vfs, fidp, vpp); if (error) return (error); - error = pefs_nodeget(mp, *vpp, vpp); + error = pefs_node_get(mp, *vpp, vpp); printf("pefs_fhtovp: error=%d; vp=%p; v_object=%p\n", error, !error ? *vpp : NULL, !error ? (*vpp)->v_object : NULL); if (error) @@ -312,7 +312,7 @@ static int pefs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, int namespace, const char *attrname) { - return VFS_EXTATTRCTL(MOUNTTOPEMOUNT(mp)->pm_vfs, cmd, filename_vp, + return VFS_EXTATTRCTL(VFS_TO_PEFS(mp)->pm_vfs, cmd, filename_vp, namespace, attrname); } ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#4 (text+ko) ==== @@ -68,45 +68,77 @@ const static struct { size_t namelen; const char *name; -} _pefs_name_shadow_list[] = { - { 1, "." }, - { 2, ".." }, +} _pefs_name_skip_list[] = { { 4, ".zfs" }, { 5, ".snap" }, { 10, "lost+found" }, { 0, NULL }, }; -static int -pefs_name_shadow(char *name, int namelen, /*OPTIONAL*/ struct componentname *cnp) +struct pefs_enccn { + struct componentname pec_cn; + void *pec_buf; +}; + +static inline int +pefs_name_skip(char *name, int namelen) { - if (cnp != NULL && cnp->cn_flags & ISDOTDOT) - return (0); - for (int i = 0; _pefs_name_shadow_list[i].namelen && _pefs_name_shadow_list[i].namelen <= namelen; i++) { - if (namelen == _pefs_name_shadow_list[i].namelen && - memcmp(_pefs_name_shadow_list[i].name, name, namelen) == 0) - return (0); + if (name[0] == '.' && (namelen == 1 || (namelen == 2 && name[1] == '.'))) + return (1); + for (int i = 0; _pefs_name_skip_list[i].namelen && + _pefs_name_skip_list[i].namelen <= namelen; i++) { + if (namelen == _pefs_name_skip_list[i].namelen && + memcmp(_pefs_name_skip_list[i].name, name, namelen) == 0) + return (1); } - return (1); + return (0); +} + +static void +pefs_enccn_init(struct pefs_enccn *pec, char *encname, int encname_len, struct componentname *cnp) +{ + MPASS(pec != NULL && cnp != NULL); + + if (encname_len >= MAXPATHLEN) + panic("invalid encrypted name length: %d", encname_len); + + pec->pec_cn = *cnp; + pec->pec_buf = uma_zalloc(namei_zone, M_WAITOK); + memcpy(pec->pec_buf, encname, encname_len); + ((char *) pec->pec_buf)[encname_len] = '\0'; + pec->pec_cn.cn_pnbuf = pec->pec_buf; + pec->pec_cn.cn_nameptr = pec->pec_buf; + pec->pec_cn.cn_namelen = encname_len; + pec->pec_cn.cn_consume = 0; // XXX?? + PEFSDEBUG("%s: name=%s len=%d\n", __func__, (char*)pec->pec_buf, encname_len); } static int -pefs_cn_shadow_create(struct componentname *cnp, struct componentname *o_cnp) +pefs_enccn_create(struct pefs_enccn *pec, struct pefs_key *pk, struct componentname *cnp) { - char *pnbuf; + struct pefs_node_key pnk; int r; - pnbuf = uma_zalloc(namei_zone, M_WAITOK); - r = pefs_name_encrypt(cnp->cn_nameptr, cnp->cn_namelen, pnbuf, MAXPATHLEN); + MPASS(pec != NULL && cnp != NULL); + + pec->pec_cn = *cnp; + if (/* pk == NULL || */ (cnp->cn_flags & ISDOTDOT) || pefs_name_skip(cnp->cn_nameptr, cnp->cn_namelen)) { + pefs_enccn_init(pec, cnp->cn_nameptr, cnp->cn_namelen, cnp); + return (0); + } + pec->pec_buf = uma_zalloc(namei_zone, M_WAITOK); + pnk.pnk_key = pk; + arc4rand(pnk.pnk_tweak, PEFS_TWEAK_SIZE, 0); + r = pefs_name_encrypt(&pnk, cnp->cn_nameptr, cnp->cn_namelen, pec->pec_buf, MAXPATHLEN); if (r <= 0) { - uma_zfree(namei_zone, pnbuf); + uma_zfree(namei_zone, pec->pec_buf); return (EIO); } - *o_cnp = *cnp; - cnp->cn_pnbuf = pnbuf; - cnp->cn_nameptr = pnbuf; - cnp->cn_namelen = r; - cnp->cn_consume = 0; // XXX?? + pec->pec_cn.cn_pnbuf = pec->pec_buf; + pec->pec_cn.cn_nameptr = pec->pec_buf; + pec->pec_cn.cn_namelen = r; + pec->pec_cn.cn_consume = 0; // XXX?? + PEFSDEBUG("%s: cn_flags=%lu\n", __func__, cnp->cn_flags); /* printf("%s: ENC cn_nameiop=%lx, cn_pnbuf=%s; cn_nameptr=%.*s; cn_consume=%d, cn_namelen=%d\n", @@ -117,14 +149,136 @@ return (0); } -static void -pefs_cn_shadow_finish(struct componentname *cnp, const struct componentname *o_cnp) +static inline void +pefs_enccn_free(struct pefs_enccn *pec) +{ + uma_zfree(namei_zone, pec->pec_buf); +} + +static struct dirent* +pefs_enccn_lookup_dirent(void *mem, size_t sz, char *name, int namelen, char *buf, size_t buf_sz) +{ + struct pefs_node_key pnk; + struct dirent *de; + int d_namelen; + int de_len; + + PEFSDEBUG("%s: lookup %.*s (%d)\n", __func__, namelen, name, namelen); + for (de = (struct dirent*) mem; sz > 0; + sz -= de_len, + de = (struct dirent *)(((caddr_t)de) + de_len)) { + de_len = GENERIC_DIRSIZ(de); + if (pefs_name_skip(de->d_name, de->d_namlen)) + continue; + d_namelen = pefs_name_decrypt(&pnk, de->d_name, de->d_namlen, buf, buf_sz); + PEFSDEBUG("%s =>; res=%d; %.*s --> %.*s\n", __func__, d_namelen, + de->d_namlen, de->d_name, + d_namelen < 0 ? 0 : d_namelen, buf); + if (d_namelen == namelen && memcmp(name, buf, namelen) == 0) { + PEFSDEBUG("%s: check dirent: %s\n", __func__, name); + return de; + } + } + return NULL; +} + +static int +pefs_enccn_lookup(struct pefs_enccn *pec, struct vnode *dvp, struct componentname *cnp) +{ + struct dirent *de; + struct pefs_chunk *pc; + struct uio *uio; + struct vnode *ldvp = PEFS_LOWERVP(dvp); + char *namebuf; + off_t offset; + int error, eofflag; + + MPASS(pec != NULL && dvp != NULL && cnp != NULL); + + if ((cnp->cn_flags & ISDOTDOT) || pefs_name_skip(cnp->cn_nameptr, cnp->cn_namelen)) { + pefs_enccn_init(pec, cnp->cn_nameptr, cnp->cn_namelen, cnp); + return (0); + } + + const char *op; + switch (cnp->cn_nameiop & OPMASK) { + case LOOKUP: + op = "LOOKUP"; + break; + case CREATE: + op = "CREATE"; + break; + case DELETE: + op = "DELETE"; + break; + case RENAME: + op = "RENAME"; + break; + default: + op = NULL; + } + PEFSDEBUG("XXX pefs_enccn_lookup: name=%.*s op=%s\n", (int) cnp->cn_namelen, cnp->cn_nameptr, op); + + pc = pefs_chunk_create(PAGE_SIZE); + namebuf = malloc(MAXNAMLEN + 1, M_PEFSBUF, M_WAITOK); + offset = 0; + eofflag = 0; + de = NULL; + while (!eofflag && de == NULL) { + long arg = 0; + + uio = pefs_chunk_uio(pc, offset, UIO_READ); + offset = uio->uio_offset; + error = VOP_READDIR(ldvp, uio, cnp->cn_cred, &eofflag, NULL, NULL); + if (error) { + pefs_chunk_free(pc); + free(namebuf, M_PEFSBUF); + return (error); + } + + printf("%s: size = %d\n", __func__, pc->pc_size - uio->uio_resid); + pefs_chunk_shrink(pc, pc->pc_size - uio->uio_resid); + while (1) { + size_t size; + char *mem; + + mem = pefs_chunk_get(pc, &size, &arg); + if (mem == NULL) + break; + de = pefs_enccn_lookup_dirent(mem, size, + cnp->cn_nameptr, cnp->cn_namelen, + namebuf, MAXNAMLEN + 1); + if (de != NULL) + break; + } + pefs_chunk_restore(pc); + } + + if (de != NULL) { + PEFSDEBUG("%s: dirent found: %.*s\n", __func__, de->d_namlen, de->d_name); + pefs_enccn_init(pec, de->d_name, de->d_namlen, cnp); + } + + pefs_chunk_free(pc); + free(namebuf, M_PEFSBUF); + + if (de == NULL) + return (ENOENT); + return (0); +} + +static int +pefs_enccn_lookup_create(struct pefs_enccn *pec, struct vnode *dvp, struct componentname *cnp) { - uma_zfree(namei_zone, cnp->cn_pnbuf); - cnp->cn_pnbuf = o_cnp->cn_pnbuf; - cnp->cn_nameptr = o_cnp->cn_nameptr; - cnp->cn_namelen = o_cnp->cn_namelen; - cnp->cn_consume = o_cnp->cn_consume; + int error; + + error = pefs_enccn_lookup(pec, dvp, cnp); + PEFSDEBUG("%s: lookup error = %d\n", __func__, error); + if (error == ENOENT) + error = pefs_enccn_create(pec, NULL, cnp); + PEFSDEBUG("%s: returning = %d\n", __func__, error); + + return (error); } /* @@ -151,8 +305,8 @@ * - all mapped vnodes are of our vnode-type (NEEDSWORK: * problems on rmdir'ing mount points and renaming?) */ -int -pefs_bypass(struct vop_generic_args *ap) +static int +pefs_bypass(struct vop_generic_args *ap, struct pefs_enccn *enccn) { struct vnode **this_vp_p; int error; @@ -195,7 +349,7 @@ old_vps[i] = NULLVP; } else { old_vps[i] = *this_vp_p; - *(vps_p[i]) = PEVPTOLOWERVP(*this_vp_p); + *(vps_p[i]) = PEFS_LOWERVP(*this_vp_p); /* * XXX - Several operations have the side effect * of vrele'ing their vp's. We must account for @@ -246,6 +400,10 @@ if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && !(descp->vdesc_flags & VDESC_NOMAP_VPP) && !error) { + if (enccn == NULL) { + printf("PANIC: vop_bypass: map of outgoing vnode without encrypted name: %s", descp->vdesc_name); + // panic("vop_bypass: map of outgoing vnode without encrypted name: %s", descp->vdesc_name); + } /* * XXX - even though some ops have vpp returned vp's, * several ops actually vrele this before returning. @@ -257,7 +415,7 @@ vppp = VOPARG_OFFSETTO(struct vnode***, descp->vdesc_vpp_offset,ap); if (*vppp) - error = pefs_nodeget(old_vps[0]->v_mount, **vppp, *vppp); + error = pefs_node_get(old_vps[0]->v_mount, **vppp, *vppp); } out: @@ -270,14 +428,13 @@ * if this layer is mounted read-only. */ static int -pefs_lookup(struct vop_lookup_args *ap) +pefs_lookup(struct vop_cachedlookup_args *ap) { struct componentname *cnp = ap->a_cnp; - struct componentname o_cnp = *ap->a_cnp; struct vnode *dvp = ap->a_dvp; struct vnode *vp, *ldvp, *lvp; + struct pefs_enccn enccn; int flags = cnp->cn_flags; - int shadow; int error; PEFSDEBUG("%s: cn_nameiop=%lx, cn_pnbuf=%s; cn_nameptr=%.*s; cn_consume=%d, cn_namelen=%d\n", @@ -288,38 +445,53 @@ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); - shadow = pefs_name_shadow(cnp->cn_nameptr, cnp->cn_namelen, cnp); - if (shadow) - pefs_cn_shadow_create(cnp, &o_cnp); + error = pefs_enccn_lookup(&enccn, dvp, cnp); + if (error == ENOENT && (cnp->cn_flags & ISLASTCN) && + (cnp->cn_nameiop == CREATE || + cnp->cn_nameiop == RENAME)) + return EJUSTRETURN; + else if (error) + return (error); /* * Although it is possible to call pefs_bypass(), we'll do * a direct call to reduce overhead */ - ldvp = PEVPTOLOWERVP(dvp); + ldvp = PEFS_LOWERVP(dvp); vp = lvp = NULL; - error = VOP_LOOKUP(ldvp, &lvp, cnp); + error = VOP_LOOKUP(ldvp, &lvp, &enccn.pec_cn); if (error == EJUSTRETURN && (flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) error = EROFS; - if (shadow) - pefs_cn_shadow_finish(cnp, &o_cnp); + PEFSDEBUG("XXX %s: result=%d\n", __func__, error); + + pefs_enccn_free(&enccn); - if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) { + if (error == ENOENT && (cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) { + PEFSDEBUG("%s: cache_enter negative %.*s\n", __func__, (int) cnp->cn_namelen, cnp->cn_nameptr); + cache_enter(dvp, NULLVP, cnp); + } else if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) { if (ldvp == lvp) { *ap->a_vpp = dvp; VREF(dvp); vrele(lvp); } else { - error = pefs_nodeget(dvp->v_mount, lvp, &vp); - if (error) + error = pefs_node_get(dvp->v_mount, lvp, &vp); + if (error) { vput(lvp); - else + } else { *ap->a_vpp = vp; + if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) { + PEFSDEBUG("%s: cache_enter %.*s\n", __func__, (int) cnp->cn_namelen, cnp->cn_nameptr); + cache_enter(dvp, vp, cnp); + } + } } } + + return (error); } @@ -330,14 +502,10 @@ struct vnode *vp, *ldvp; vp = ap->a_vp; - ldvp = PEVPTOLOWERVP(vp); - retval = pefs_bypass(&ap->a_gen); + ldvp = PEFS_LOWERVP(vp); + retval = pefs_bypass(&ap->a_gen, NULL); if (retval == 0) { - if (vp->v_type == VSOCK || vp->v_type == VFIFO) { - vp->v_object = ldvp->v_object; - } else { - vnode_create_vobject(vp, 0, ap->a_td); - } + vnode_create_vobject(vp, 0, ap->a_td); } return (retval); } @@ -353,7 +521,7 @@ int resid, size; int error; - lvp = PEVPTOLOWERVP(vp); + lvp = PEFS_LOWERVP(vp); error = VOP_GETATTR(lvp, &o_va, cred); if (error) return (error); @@ -377,7 +545,7 @@ for (off=o_va.va_size; size > 0;) { int inc = min(size, pc_size_max); - if (inc != size && (off + inc) % PEFS_BLOCK) + if (inc != size && (off + inc) % PEFS_BLOCK) inc -= (off + inc) % PEFS_BLOCK; puio = pefs_chunk_uio_range(pc, 0, inc, off, UIO_WRITE); @@ -472,7 +640,7 @@ } } - lvp = PEVPTOLOWERVP(vp); + lvp = PEFS_LOWERVP(vp); return VOP_SETATTR(lvp, vap, cred); } @@ -485,7 +653,7 @@ struct vattr *vap = ap->a_vap; int error; - if ((error = pefs_bypass((struct vop_generic_args *)ap)) != 0) + if ((error = pefs_bypass((struct vop_generic_args *)ap, NULL)) != 0) return (error); vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; @@ -521,7 +689,7 @@ break; } } - return (pefs_bypass((struct vop_generic_args *)ap)); + return (pefs_bypass((struct vop_generic_args *)ap, NULL)); } /* @@ -532,14 +700,15 @@ static int pefs_rename(struct vop_rename_args *ap) { + struct vnode *fdvp = ap->a_fdvp; + struct vnode *fvp = ap->a_fvp; struct vnode *tdvp = ap->a_tdvp; - struct vnode *fvp = ap->a_fvp; - struct vnode *fdvp = ap->a_fdvp; struct vnode *tvp = ap->a_tvp; struct componentname *fcnp = ap->a_fcnp; struct componentname *tcnp = ap->a_tcnp; - struct componentname o_fcnp, o_tcnp; - int fshadow, tshadow, error; + struct pefs_enccn fenccn; + struct pefs_enccn tenccn; + int error; /* Check for cross-device rename. */ if ((fvp->v_mount != tdvp->v_mount) || @@ -556,22 +725,32 @@ } - fshadow = pefs_name_shadow(fcnp->cn_nameptr, fcnp->cn_namelen, fcnp); - if (fshadow) - pefs_cn_shadow_create(fcnp, &o_fcnp); - tshadow = pefs_name_shadow(tcnp->cn_nameptr, tcnp->cn_namelen, tcnp); - if (tshadow) - pefs_cn_shadow_create(tcnp, &o_tcnp); + error = pefs_enccn_lookup(&fenccn, fdvp, fcnp); + if (error) { + return (error); + } + error = pefs_enccn_lookup_create(&tenccn, tdvp, tcnp); + if (error) { + pefs_enccn_free(&fenccn); + return (error); + } PEFSDEBUG("%s: %.*s -> %.*s\n", __func__, (int) fcnp->cn_namelen, fcnp->cn_nameptr, (int) tcnp->cn_namelen, tcnp->cn_nameptr); - error = pefs_bypass((struct vop_generic_args *)ap); + ap->a_fcnp = &fenccn.pec_cn; + ap->a_tcnp = &tenccn.pec_cn; + error = pefs_bypass((struct vop_generic_args *)ap, NULL); + ap->a_fcnp = fcnp; + ap->a_tcnp = tcnp; + + pefs_enccn_free(&fenccn); + pefs_enccn_free(&tenccn); - if (fshadow) - pefs_cn_shadow_finish(fcnp, &o_fcnp); - if (tshadow) - pefs_cn_shadow_finish(tcnp, &o_tcnp); + if (!error) { + cache_purge(fdvp); + cache_purge(fvp); + } return (error); } @@ -595,13 +774,13 @@ VI_LOCK(vp); ap->a_flags = flags |= LK_INTERLOCK; } - nn = VTOPE(vp); + nn = VP_TO_PN(vp); /* * If we're still active we must ask the lower layer to * lock as ffs has special lock considerations in it's * vop lock. */ - if (nn != NULL && (lvp = PEVPTOLOWERVP(vp)) != NULL) { + if (nn != NULL && (lvp = PEFS_LOWERVP(vp)) != NULL) { VI_LOCK_FLAGS(lvp, MTX_DUPOK); VI_UNLOCK(vp); /* >>> TRUNCATED FOR MAIL (1000 lines) <<<