From owner-p4-projects@FreeBSD.ORG Mon Sep 7 21:47:01 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 784601065767; Mon, 7 Sep 2009 21:47:01 +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 34BE1106575D for ; Mon, 7 Sep 2009 21:47:00 +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 C60198FC1B for ; Mon, 7 Sep 2009 21:47:00 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n87Ll0ji029540 for ; Mon, 7 Sep 2009 21:47:00 GMT (envelope-from gk@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n87Ll0WV029538 for perforce@freebsd.org; Mon, 7 Sep 2009 21:47:00 GMT (envelope-from gk@FreeBSD.org) Date: Mon, 7 Sep 2009 21:47:00 GMT Message-Id: <200909072147.n87Ll0WV029538@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 168308 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: Mon, 07 Sep 2009 21:47:01 -0000 http://perforce.freebsd.org/chv.cgi?CH=168308 Change 168308 by gk@gk_h1 on 2009/09/07 21:46:01 merge from local repo: repend '.' to encrypted file names allow mounting on same path. forbid on subdirs preallocate per node pefs_chunk buffers change pefs_chunk_* to use continuous buffer use taskqueue to asynchronously free pefs_node pefs_lookup: fixes + SAVENAME bug fix pefs_rename: fixes remove pefs_enccn_lookup_create, lookup is not needed pefs_lock, pefs_unlock: do not use VP_TO_PN and PEFS_LOWERVP split pefs_node_get into pefs_node_get_{nokey,haskey,lookupkey} check max file name size in pefs_name_encrypt open .pefs file on filesystem root Affected files ... .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.c#5 edit .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.h#6 edit .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_keychain.c#4 edit .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_mount.c#3 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#11 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#9 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_hmac.c#1 add .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_hmac.h#1 add .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#11 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#10 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#13 edit .. //depot/projects/soc2009/gk_pefs/sys/modules/pefs/Makefile#7 edit Differences ... ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.c#5 (text+ko) ==== @@ -28,7 +28,9 @@ #include __FBSDID("$FreeBSD$"); -#include +#include +#include + #include #include #include @@ -99,6 +101,46 @@ return (1); } +int +pefs_getfsroot(const char *path, char *fsroot, size_t size) +{ + struct statfs fs; + int error; + + if (statfs(path, &fs) == -1) { + error = errno; + warn("statfs failed: %s", path); + return (error); + } + + if (strcmp(PEFS_FSTYPE, fs.f_fstypename) != 0) { + warnx("invalid filesystem type: %s", path); + return (EINVAL); + } + + if (fsroot != NULL) + strlcpy(fsroot, fs.f_mntfromname, size); + + return (0); +} + +static int +pefs_openfs(char *path) +{ + char fsroot[PATH_MAX]; + int fd; + + if (pefs_getfsroot(path, fsroot, sizeof(fsroot)) != 0) + return (-1); + + fd = open(fsroot, O_RDONLY); + if (fd == -1) + warn("cannot open %s", path); + + return (fd); + +} + uintmax_t pefs_keyid_as_int(char *keyid) { @@ -174,11 +216,10 @@ bzero(&k, sizeof(k)); if (error) return (EX_DATAERR); - fd = open(argv[0], O_RDONLY); - if (fd == -1) { - err(EX_IOERR, "cannot open %s", argv[0]); - } - + fd = pefs_openfs(argv[0]); + if (fd == -1) + return (EX_IOERR); + error = func(&kch, fd); pefs_keychain_free(&kch); @@ -278,7 +319,7 @@ argv += optind; if (chain == PEFS_KEYCHAIN_USE && addkey) - errx(EX_USAGE, "invalid arguments: -x -c"); + errx(EX_USAGE, "invalid argument combination: -x -c"); if (argc != 1) { if (argc == 0) @@ -289,6 +330,9 @@ pefs_usage(); } + /* only check filesystem type */ + pefs_getfsroot(argv[0], NULL, 0); + error = pefs_key_get(&k, NULL, 0, &kp); if (error != 0) return (error); @@ -301,7 +345,8 @@ fd = open(argv[0], O_RDONLY); if (fd == -1) { - err(EX_IOERR, "cannot open %s", argv[0]); + warn("cannot open %s", argv[0]); + return (EX_IOERR); } if (ioctl(fd, PEFS_SETKEY, &k) == -1) { @@ -325,10 +370,9 @@ pefs_usage(); } - fd = open(argv[0], O_RDONLY); - if (fd == -1) { - err(EX_IOERR, "cannot open %s", argv[0]); - } + fd = pefs_openfs(argv[0]); + if (fd == -1) + return (EX_IOERR); if (ioctl(fd, PEFS_FLUSHKEYS) == -1) { err(EX_IOERR, "cannot flush keys"); } @@ -357,10 +401,9 @@ pefs_usage(); } - fd = open(argv[0], O_RDONLY); - if (fd == -1) { - err(EX_IOERR, "cannot open %s", argv[0]); - } + fd = pefs_openfs(argv[0]); + if (fd == -1) + return (EX_IOERR); bzero(&k, sizeof(k)); if (ioctl(fd, PEFS_GETKEY, &k) == -1) { ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.h#6 (text+ko) ==== @@ -26,6 +26,8 @@ * $FreeBSD$ */ +#define PEFS_FSTYPE "pefs" + #define PEFS_ALG_DEFAULT PEFS_ALG_AES_CTR #define PEFS_ALG_DEFAULT_KEYBITS 256 @@ -55,6 +57,7 @@ void pefs_usage(void); int pefs_mount(int argc, char *argv[]); int pefs_mount_prog(int argc, char *argv[]); +int pefs_getfsroot(const char *path, char *fsroot, size_t size); int pefs_key_get(struct pefs_xkey *xk, const char *prompt, int verify, struct pefs_keyparam *kp); int pefs_key_encrypt(struct pefs_xkey *xk, const struct pefs_xkey *xk_parent); int pefs_key_decrypt(struct pefs_xkey *xk, const struct pefs_xkey *xk_parent); ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_keychain.c#4 (text+ko) ==== @@ -56,7 +56,10 @@ char buf[MAXPATHLEN]; DB *db; - snprintf(buf, sizeof(buf), "%s/%s", filesystem, KEYCHAIN_DBFILE); + if (pefs_getfsroot(filesystem, buf, sizeof(buf)) != 0) + return (NULL); + strlcat(buf, "/", sizeof(buf)); + strlcat(buf, KEYCHAIN_DBFILE, sizeof(buf)); db = dbopen(buf, flags | O_EXLOCK, S_IRUSR | S_IWUSR, DB_BTREE, NULL); if (db == NULL && (kc_flags & PEFS_KEYCHAIN_USE || errno != ENOENT)) warn("keychain %s", buf); ==== //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_mount.c#3 (text+ko) ==== @@ -89,13 +89,15 @@ (void)checkpath(argv[0], target); (void)checkpath(argv[1], source); - if (subdir(target, source) || subdir(source, target)) - errx(EX_USAGE, "%s (%s) and %s are not distinct paths", + if ((subdir(target, source) || subdir(source, target)) && + strcmp(target, source) != 0) { + errx(EX_USAGE, "%s (%s) and %s are nested paths", argv[0], target, argv[1]); + } iov[0].iov_base = strdup("fstype"); iov[0].iov_len = sizeof("fstype"); - iov[1].iov_base = strdup("pefs"); + iov[1].iov_base = strdup(PEFS_FSTYPE); iov[1].iov_len = strlen(iov[1].iov_base) + 1; iov[2].iov_base = strdup("fspath"); iov[2].iov_len = sizeof("fspath"); ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#11 (text+ko) ==== @@ -96,12 +96,18 @@ char ptk_tweak[PEFS_TWEAK_SIZE]; }; -#define PN_HASKEY 0x0001 +#define PN_HASKEY 0x000001 +#define PN_WANTRECYCLE 0x000100 +#define PN_LOCKBUF_SMALL 0x001000 +#define PN_LOCKBUF_LARGE 0x002000 struct pefs_node { - LIST_ENTRY(pefs_node) pn_hash; /* Hash list */ + LIST_ENTRY(pefs_node) pn_listentry; struct vnode *pn_lowervp; /* VREFed once */ + struct vnode *pn_lowervp_dead; /* VREFed once */ struct vnode *pn_vnode; /* Back pointer */ + void *pn_buf_small; + void *pn_buf_large; int pn_flags; struct pefs_tkey pn_tkey; }; @@ -114,12 +120,11 @@ }; struct pefs_chunk { - int pc_iovcnt; - int pc_basescnt; - struct iovec *pc_iov; size_t pc_size; size_t pc_capacity; - void **pc_bases; + void *pc_base; + int pc_nodebuf; + struct iovec pc_iov; struct uio pc_uio; }; @@ -162,6 +167,16 @@ return (lvp); } +static inline void ** +pefs_node_buf(struct pefs_node *pn, int flag) +{ + MPASS(flag == PN_LOCKBUF_SMALL || flag == PN_LOCKBUF_LARGE); + if (flag == PN_LOCKBUF_SMALL) + return (&pn->pn_buf_small); + else + return (&pn->pn_buf_large); +} + struct vfsconf; struct vop_generic_args; struct pefs_ctx; @@ -171,14 +186,21 @@ void pefs_crypto_init(void); void pefs_crypto_uninit(void); -int pefs_node_get(struct mount *mp, struct vnode *lvp, struct vnode *ldvp, struct vnode **vpp, struct ucred *cred, struct pefs_tkey *ptk); -void pefs_node_free(struct pefs_node *xp); +int pefs_node_get_nokey(struct mount *mp, struct vnode *lvp, + struct vnode **vpp); +int pefs_node_get_haskey(struct mount *mp, struct vnode *lvp, + struct vnode **vpp, struct pefs_tkey *ptk); +int pefs_node_get_lookupkey(struct mount *mp, struct vnode *lvp, + struct vnode **vpp, struct ucred *cred); +void pefs_node_asyncfree(struct pefs_node *xp); struct pefs_key * pefs_node_key(struct pefs_node *pn); +void pefs_node_buf_free(struct pefs_node *pn); struct pefs_ctx * pefs_ctx_get(void); void pefs_ctx_free(struct pefs_ctx *ctx); -struct pefs_key * pefs_key_get(int alg, int keybits, const char *key, const char *keyid); +struct pefs_key * pefs_key_get(int alg, int keybits, const char *key, + const char *keyid); struct pefs_key * pefs_key_ref(struct pefs_key *pk); void pefs_key_release(struct pefs_key *pk); @@ -187,25 +209,39 @@ void pefs_key_remove(struct pefs_mount *pm, struct pefs_key *pk); int pefs_key_remove_all(struct pefs_mount *pm); -void pefs_data_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc); -void pefs_data_decrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc); +void pefs_data_encrypt_start(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + off_t offset); +void pefs_data_encrypt_update(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + struct pefs_chunk *pc); +void pefs_data_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + off_t offset, struct pefs_chunk *pc); +void pefs_data_decrypt_start(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + off_t offset); +void pefs_data_decrypt_update(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + struct pefs_chunk *pc); +void pefs_data_decrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + off_t offset, struct pefs_chunk *pc); -int pefs_name_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, const char *plain, size_t plain_len, char *enc, size_t enc_size); -int pefs_name_decrypt(struct pefs_ctx *ctx, struct pefs_key *pk, struct pefs_tkey *ptk, const char *enc, size_t enc_len, char *plain, size_t plain_size); +int pefs_name_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + const char *plain, size_t plain_len, char *enc, size_t enc_size); +int pefs_name_decrypt(struct pefs_ctx *ctx, struct pefs_key *pk, + struct pefs_tkey *ptk, 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); +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); -struct pefs_chunk * pefs_chunk_create(size_t size); +void pefs_chunk_create(struct pefs_chunk *pc, struct pefs_node *pn, + size_t size); void pefs_chunk_restore(struct pefs_chunk* pc); -void pefs_chunk_free(struct pefs_chunk* pc); -void* pefs_chunk_pullup(struct pefs_chunk *pc, size_t size); -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); +void pefs_chunk_free(struct pefs_chunk* pc, struct pefs_node *pn); +struct uio * pefs_chunk_uio(struct pefs_chunk *pc, off_t uio_offset, + enum uio_rw uio_rw); void pefs_chunk_zero(struct pefs_chunk *pc); -int pefs_chunk_copy(struct pefs_chunk *pc, size_t skip, struct uio *uio); -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); +int pefs_chunk_copy(struct pefs_chunk *pc, struct uio *uio); +void pefs_chunk_setsize(struct pefs_chunk *pc, size_t size); extern struct vop_vector pefs_vnodeops; @@ -225,7 +261,7 @@ pefs_no_keys(struct vnode *vp) { return (!(VP_TO_PN(vp)->pn_flags & PN_HASKEY) && - pefs_rootkey(VFS_TO_PEFS(vp->v_mount)) == NULL); + pefs_rootkey(VFS_TO_PEFS(vp->v_mount)) == NULL); } #ifdef MALLOC_DECLARE ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#9 (text+ko) ==== @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -371,33 +372,62 @@ } void -pefs_data_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc) +pefs_data_encrypt_start(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + off_t offset) +{ + MPASS(ctx != NULL); + MPASS(ptk->ptk_key != NULL); + + pefs_ctx_cpy(ctx, ptk->ptk_key->pk_data_ctx); + ptk->ptk_key->pk_alg->pa_ivsetup(ctx, ptk->ptk_tweak, offset); +} + +void +pefs_data_encrypt_update(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + struct pefs_chunk *pc) +{ + MPASS(ctx != NULL); + MPASS(ptk->ptk_key != NULL); + + ptk->ptk_key->pk_alg->pa_crypt(ctx, pc->pc_base, pc->pc_base, + pc->pc_size); +} + +void +pefs_data_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, + struct pefs_chunk *pc) { - const struct pefs_alg *alg; - struct iovec *iov; int free_ctx = 0; - KASSERT(ptk->ptk_key != NULL, ("pefs_data_encrypt: key is null")); - if (ctx == NULL) { ctx = pefs_ctx_get(); free_ctx = 1; } - alg = ptk->ptk_key->pk_alg; - pefs_ctx_cpy(ctx, ptk->ptk_key->pk_data_ctx); - alg->pa_ivsetup(ctx, ptk->ptk_tweak, offset); - for (iov = pc->pc_iov; iov < pc->pc_iov + pc->pc_iovcnt; iov++) { - alg->pa_crypt(ctx, iov->iov_base, iov->iov_base, - iov->iov_len); - } + pefs_data_encrypt_start(ctx, ptk, offset); + pefs_data_encrypt_update(ctx, ptk, pc); if (free_ctx) pefs_ctx_free(ctx); } void -pefs_data_decrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, struct pefs_chunk *pc) +pefs_data_decrypt_start(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + off_t offset) +{ + pefs_data_encrypt_start(ctx, ptk, offset); +} + +void +pefs_data_decrypt_update(struct pefs_ctx *ctx, struct pefs_tkey *ptk, + struct pefs_chunk *pc) +{ + pefs_data_encrypt_update(ctx, ptk, pc); +} + +void +pefs_data_decrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, off_t offset, + struct pefs_chunk *pc) { pefs_data_encrypt(ctx, ptk, offset, pc); } @@ -443,21 +473,27 @@ int pefs_name_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, const char *plain, size_t plain_len, char *enc, size_t enc_size) { + CTASSERT(MAXNAMLEN >= PEFS_NAME_PTON_SIZE(MAXNAMLEN) + PEFS_CSUM_BLOCK_SIZE); const struct pefs_alg *alg; - char *buf, *buf_name, *buf_tweak; - size_t size, psize; + char buf[MAXNAMLEN + 1]; + char *buf_name, *buf_tweak; + size_t size; int free_ctx = 0; int r; - KASSERT(ptk->ptk_key != NULL, ("pefs_name_encrypt: key is null")); + KASSERT(ptk != NULL && ptk->ptk_key != NULL, + ("pefs_name_encrypt: key is null")); alg = ptk->ptk_key->pk_alg; size = PEFS_TWEAK_SIZE + plain_len + PEFS_NAME_CSUM_SIZE; - if (enc_size < PEFS_NAME_NTOP_SIZE(size)) { + if (PEFS_NAME_NTOP_SIZE(size) + 1 > MAXNAMLEN) { + return (-ENAMETOOLONG); + } + if (enc_size < PEFS_NAME_NTOP_SIZE(size) + 1) { printf("pefs: name encryption buffer is too small: length %ld, required %ld\n", enc_size, PEFS_NAME_NTOP_SIZE(size)); - return (-1); + return (-EOVERFLOW); } if (ctx == NULL) { @@ -465,9 +501,6 @@ free_ctx = 1; } - psize = pefs_name_checksum_psize(size); - buf = malloc(psize, M_PEFSBUF, M_WAITOK); - buf_tweak = buf + PEFS_NAME_CSUM_SIZE; buf_name = buf + PEFS_NAME_CSUM_SIZE + PEFS_TWEAK_SIZE; memcpy(buf_tweak, ptk->ptk_tweak, PEFS_TWEAK_SIZE); @@ -477,14 +510,13 @@ alg->pa_ivsetup(ctx, magic_tweak_name, 0); alg->pa_crypt(ctx, buf_tweak, buf_tweak, size - PEFS_NAME_CSUM_SIZE); - pefs_name_checksum(ctx, ptk->ptk_key, buf, buf, size, psize); + pefs_name_checksum(ctx, ptk->ptk_key, buf, buf, size, sizeof(buf)); if (free_ctx) pefs_ctx_free(ctx); - r = pefs_name_ntop(buf, size, enc, enc_size); - - free(buf, M_PEFSBUF); + enc[0] = '.'; + r = pefs_name_ntop(buf, size, enc + 1, enc_size - 1); return (r); } @@ -499,20 +531,25 @@ int free_ctx = 0; int r, ki_rev; - KASSERT(ptk->ptk_key != NULL, ("pefs_name_decrypt: key is null")); KASSERT(enc != plain, ("pefs_name_decrypt: ciphertext and plaintext buffers should differ")); alg = pk->pk_alg; + if (enc[0] != '.') + return (-EINVAL); + enc++; + enc_len--; + if (PEFS_NAME_PTON_SIZE(enc_len) <= PEFS_TWEAK_SIZE + PEFS_NAME_CSUM_SIZE) + return (-EINVAL); r = pefs_name_pton(enc, enc_len, plain, plain_size); - if (r < 0 || r <= PEFS_TWEAK_SIZE + PEFS_NAME_CSUM_SIZE) { + if (r < 0) { PEFSDEBUG("pefs_name_decrypt: error: r=%d\n", r); - return (-1); + return (-EINVAL); } if (plain_size < pefs_name_checksum_psize(r)) { printf("pefs: name decryption buffer is too small: length %ld, required %ld\n", plain_size, pefs_name_checksum_psize(r)); - return (-1); + return (-EOVERFLOW); } plain_tweak = plain + PEFS_NAME_CSUM_SIZE; ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#11 (text+ko) ==== @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -68,9 +69,20 @@ #define PEFS_NHASH(vp) \ (&pefs_node_hashtbl[(((uintptr_t)vp)>>LOG2_SIZEVNODE) & pefs_node_hash]) -static LIST_HEAD(pefs_node_hashhead, pefs_node) *pefs_node_hashtbl; +typedef int (pefs_node_init_fn)(struct mount *mp, struct pefs_node *pn, + void *context); +LIST_HEAD(pefs_node_listhead, pefs_node); + +static void pefs_node_free_proc(void *, int); + +static struct taskqueue *pefs_taskq; +static struct task pefs_task_freenode; + +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_hash; -static struct mtx pefs_hashmtx; static MALLOC_DEFINE(M_PEFSHASH, "pefs_hash", "PEFS hash table"); MALLOC_DEFINE(M_PEFSBUF, "pefs_buf", "PEFS buffers"); @@ -85,12 +97,19 @@ { 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_node_hashtbl = hashinit(NPENODECACHE, M_PEFSHASH, &pefs_node_hash); - mtx_init(&pefs_hashmtx, "pefs_hash", NULL, MTX_DEF); + mtx_init(&pefs_node_listmtx, "pefs_node_list", NULL, MTX_DEF); pefs_crypto_init(); return (0); } @@ -98,8 +117,11 @@ int pefs_uninit(struct vfsconf *vfsp) { + taskqueue_enqueue(pefs_taskq, &pefs_task_freenode); + taskqueue_drain(pefs_taskq, &pefs_task_freenode); + taskqueue_free(pefs_taskq); pefs_crypto_uninit(); - mtx_destroy(&pefs_hashmtx); + mtx_destroy(&pefs_node_listmtx); free(pefs_node_hashtbl, M_PEFSHASH); uma_zdestroy(pefs_node_zone); return (0); @@ -112,7 +134,7 @@ static struct vnode * pefs_hashget(struct mount *mp, struct vnode *lowervp) { - struct pefs_node_hashhead *hd; + struct pefs_node_listhead *hd; struct pefs_node *a; struct vnode *vp; @@ -125,8 +147,8 @@ * reference count (but NOT the lower vnode's VREF counter). */ hd = PEFS_NHASH(lowervp); - mtx_lock(&pefs_hashmtx); - LIST_FOREACH(a, hd, pn_hash) { + mtx_lock(&pefs_node_listmtx); + LIST_FOREACH(a, hd, pn_listentry) { if (a->pn_lowervp == lowervp && PN_TO_VP(a)->v_mount == mp) { /* * Since we have the lower node locked the pefs @@ -136,11 +158,11 @@ */ vp = PN_TO_VP(a); vref(vp); - mtx_unlock(&pefs_hashmtx); + mtx_unlock(&pefs_node_listmtx); return (vp); } } - mtx_unlock(&pefs_hashmtx); + mtx_unlock(&pefs_node_listmtx); return (NULLVP); } @@ -151,13 +173,13 @@ static struct vnode * pefs_hashins(struct mount *mp, struct pefs_node *pn) { - struct pefs_node_hashhead *hd; + struct pefs_node_listhead *hd; struct pefs_node *oxp; struct vnode *ovp; hd = PEFS_NHASH(pn->pn_lowervp); - mtx_lock(&pefs_hashmtx); - LIST_FOREACH(oxp, hd, pn_hash) { + 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) { /* @@ -166,12 +188,12 @@ */ ovp = PN_TO_VP(oxp); vref(ovp); - mtx_unlock(&pefs_hashmtx); + mtx_unlock(&pefs_node_listmtx); return (ovp); } } - LIST_INSERT_HEAD(hd, pn, pn_hash); - mtx_unlock(&pefs_hashmtx); + LIST_INSERT_HEAD(hd, pn, pn_listentry); + mtx_unlock(&pefs_node_listmtx); return (NULLVP); } @@ -192,7 +214,8 @@ } static int -pefs_node_lookup_name(struct vnode *lvp, struct vnode *ldvp, struct ucred *cred, char *encname, int *encname_len) +pefs_node_lookup_name(struct vnode *lvp, struct vnode *ldvp, struct ucred *cred, + char *encname, int *encname_len) { struct vnode *nldvp; int error, locked, dlocked; @@ -231,7 +254,8 @@ } static int -pefs_node_lookup_key(struct pefs_mount *pm, struct vnode *lvp, struct vnode *ldvp, struct ucred *cred, struct pefs_tkey *ptk) +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; @@ -242,7 +266,7 @@ encname_len = MAXNAMLEN + 1; error = pefs_node_lookup_name(lvp, ldvp, cred, encname, &encname_len); - if (!error) { + if (error) { free(namebuf, M_PEFSBUF); return (error); } @@ -253,11 +277,10 @@ encname, encname_len, namebuf, MAXNAMLEN + 1); - if (name_len < 0) { + if (name_len > 0) { + pefs_key_ref(ptk->ptk_key); + } else { PEFSDEBUG("pefs_node_lookup_key: not found: %.*s\n", encname_len, encname); - error = 0; - } else { - pefs_key_ref(ptk->ptk_key); } free(namebuf, M_PEFSBUF); @@ -265,6 +288,48 @@ return (error); } +static int +pefs_node_init_knownkey(struct mount *mp, struct pefs_node *pn, + void *context) +{ + struct pefs_tkey *ptk = context; + + MPASS((pn->pn_flags & PN_HASKEY) == 0); + + if (ptk != NULL && ptk->ptk_key != NULL) { + pn->pn_tkey = *ptk; + pefs_key_ref(pn->pn_tkey.ptk_key); + pn->pn_flags |= PN_HASKEY; + } + + return (0); +} + +static int +pefs_node_init_lookupkey(struct mount *mp, struct pefs_node *pn, + void *context) +{ + struct ucred *cred = context; + int error; + + KASSERT(mp->mnt_data != NULL, + ("pefs_node_get_lookupkey called for uninitialized mount point?")); + + if (pefs_rootkey(VFS_TO_PEFS(mp)) == NULL) + return (0); + + error = pefs_node_lookup_key(VFS_TO_PEFS(mp), pn->pn_lowervp, NULL, + cred, &pn->pn_tkey); + + if (pn->pn_tkey.ptk_key != NULL) { + MPASS(error == 0); + pn->pn_flags = PN_HASKEY; + } + + return (error); + +} + /* * Make a new or get existing pefs node. * vp is the alias vnode @@ -275,8 +340,9 @@ * vrele lvp if pefs node was taken from hash. Otherwise it "transfers" * the caller's "spare" reference to created pefs vnode. */ -int -pefs_node_get(struct mount *mp, struct vnode *lvp, struct vnode *ldvp, struct vnode **vpp, struct ucred *cred, struct pefs_tkey *ptk) +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; @@ -303,21 +369,15 @@ * elsewhere if MALLOC should block. */ pn = uma_zalloc(pefs_node_zone, M_WAITOK | M_ZERO); + pn->pn_lowervp = lvp; - if (ptk != NULL && ptk->ptk_key != NULL) { - pn->pn_tkey = *ptk; - pn->pn_flags = PN_HASKEY; - pefs_key_ref(pn->pn_tkey.ptk_key); - } else if (mp->mnt_data != NULL && pefs_rootkey(VFS_TO_PEFS(mp)) != NULL) { - if (cred == NULL) - cred = curthread->td_ucred; - error = pefs_node_lookup_key(VFS_TO_PEFS(mp), lvp, ldvp, cred, &pn->pn_tkey); - if (error) { - uma_zfree(pefs_node_zone, pn); - return (error); - } - if (pn->pn_tkey.ptk_key != NULL) - pn->pn_flags = PN_HASKEY; + /* 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) { + uma_zfree(pefs_node_zone, pn); + return (error); } error = getnewvnode("pefs", mp, &pefs_vnodeops, &vp); @@ -332,7 +392,6 @@ } pn->pn_vnode = vp; - pn->pn_lowervp = lvp; vp->v_type = lvp->v_type; vp->v_data = pn; vp->v_vnlock = lvp->v_vnlock; @@ -358,18 +417,83 @@ return (0); } +int +pefs_node_get_nokey(struct mount *mp, struct vnode *lvp, struct vnode **vpp) +{ + return (pefs_node_get(mp, lvp, vpp, pefs_node_init_knownkey, NULL)); +} + +int +pefs_node_get_haskey(struct mount *mp, struct vnode *lvp, struct vnode **vpp, + struct pefs_tkey *ptk) +{ + MPASS(ptk != NULL && ptk->ptk_key != NULL); + return (pefs_node_get(mp, lvp, vpp, pefs_node_init_knownkey, ptk)); +} + /* + * Lookup vnode key using VOP_VPTOCNP. + * Directory vnode (ldvp) of lvp should not be locked. + * XXX will fail if ldvp is not active ??? + */ +int +pefs_node_get_lookupkey(struct mount *mp, struct vnode *lvp, struct vnode **vpp, + struct ucred *cred) +{ + MPASS(cred != NULL); + return (pefs_node_get(mp, lvp, vpp, pefs_node_init_lookupkey, cred)); +} + +static void +pefs_node_free_proc(void *context __unused, int pending __unused) +{ + struct pefs_node *pn; + struct vnode *lowervp; + + while (1) { + mtx_lock(&pefs_node_listmtx); + pn = LIST_FIRST(&pefs_node_freelist); + if (pn == NULL) { + mtx_unlock(&pefs_node_listmtx); + break; + } + LIST_REMOVE(pn, pn_listentry); + mtx_unlock(&pefs_node_listmtx); + lowervp = pn->pn_lowervp_dead; + uma_zfree(pefs_node_zone, pn); + if (lowervp != NULL) + vrele(lowervp); + } +} + +/* * Remove node from hash and free it. */ void -pefs_node_free(struct pefs_node *pn) +pefs_node_asyncfree(struct pefs_node *pn) { - PEFSDEBUG("pefs_node_free: free node %p\n", pn); - mtx_lock(&pefs_hashmtx); - LIST_REMOVE(pn, pn_hash); - mtx_unlock(&pefs_hashmtx); + PEFSDEBUG("pefs_node_asyncfree: free node %p\n", pn); pefs_key_release(pn->pn_tkey.ptk_key); - uma_zfree(pefs_node_zone, pn); + mtx_lock(&pefs_node_listmtx); + LIST_REMOVE(pn, pn_listentry); + LIST_INSERT_HEAD(&pefs_node_freelist, pn, pn_listentry); + mtx_unlock(&pefs_node_listmtx); + taskqueue_enqueue(pefs_taskq, &pefs_task_freenode); +} + +void +pefs_node_buf_free(struct pefs_node *pn) +{ + if (pn->pn_buf_small != NULL && + (pn->pn_flags & PN_LOCKBUF_SMALL) == 0) { + free(pn->pn_buf_small, M_PEFSBUF); + pn->pn_buf_small = 0; + } + if (pn->pn_buf_large != NULL && + (pn->pn_flags & PN_LOCKBUF_LARGE) == 0) { + free(pn->pn_buf_large, M_PEFSBUF); + pn->pn_buf_large = 0; + } } struct pefs_key* @@ -388,190 +512,112 @@ return (pefs_key_ref(pk)); } -struct pefs_chunk* -pefs_chunk_create(size_t size) +void +pefs_chunk_create(struct pefs_chunk *pc, struct pefs_node *pn, size_t size) { - struct pefs_chunk *pc; - int iovcnt; + size_t wantbufsize; + int nodebuf; + void **nodebuf_ptr; - iovcnt = (size + PAGE_SIZE - 1) / PAGE_SIZE; - pc = malloc(sizeof(struct pefs_chunk) + (sizeof(void*) + sizeof(struct iovec) * 2) * iovcnt, - M_PEFSBUF, M_WAITOK | M_ZERO); + if (size > DFLTPHYS) + panic("pefs_chunk_create: requested buffer is too large %jd", size); + nodebuf = 0; + wantbufsize = (size <= PAGE_SIZE ? PAGE_SIZE : DFLTPHYS); + if (pn != NULL) { + nodebuf = (size <= PAGE_SIZE ? PN_LOCKBUF_SMALL : + PN_LOCKBUF_LARGE); + VI_LOCK(pn->pn_vnode); + if ((pn->pn_flags & nodebuf) == 0) { + pn->pn_flags |= nodebuf; + nodebuf_ptr = pefs_node_buf(pn, nodebuf); + } else if (nodebuf == PN_LOCKBUF_SMALL && + (pn->pn_flags & PN_LOCKBUF_LARGE) == 0) { + nodebuf = PN_LOCKBUF_LARGE; + wantbufsize = DFLTPHYS; + pn->pn_flags |= nodebuf; + nodebuf_ptr = &pn->pn_buf_large; + } else { + nodebuf = 0; + } + VI_UNLOCK(pn->pn_vnode); + } + if (nodebuf != 0) { + if (*nodebuf_ptr == NULL) { + *nodebuf_ptr = malloc(wantbufsize, M_PEFSBUF, M_WAITOK); + } + pc->pc_nodebuf = nodebuf; + pc->pc_base = *nodebuf_ptr; + } else { + pc->pc_nodebuf = 0; + pc->pc_base = malloc(wantbufsize, M_PEFSBUF, M_WAITOK); + } pc->pc_size = size; - pc->pc_iovcnt = iovcnt; - pc->pc_basescnt = iovcnt; - pc->pc_bases = (void **)(pc + 1); - pc->pc_iov = (struct iovec *)(pc->pc_bases + iovcnt); - pc->pc_uio.uio_iov = (struct iovec *)(pc->pc_iov + iovcnt); - - for (int i = 0; i < iovcnt && size > 0; i++) { - int len = imin(PAGE_SIZE, size); - pc->pc_iov[i].iov_len = len; - pc->pc_bases[i] = malloc(len, M_PEFSBUF, M_WAITOK | M_ZERO); - pc->pc_iov[i].iov_base = pc->pc_bases[i]; - size -= len; - } - - MPASS(size == 0); - - return (pc); + pc->pc_capacity = pc->pc_size; + pc->pc_uio.uio_iovcnt = 1; + pc->pc_uio.uio_iov = &pc->pc_iov; } 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]; >>> TRUNCATED FOR MAIL (1000 lines) <<<