From owner-p4-projects@FreeBSD.ORG Wed Jul 22 13:01:33 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id E25571065670; Wed, 22 Jul 2009 13:01:32 +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 A1E00106566B for ; Wed, 22 Jul 2009 13:01:32 +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 8E79F8FC18 for ; Wed, 22 Jul 2009 13:01:32 +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 n6MD1W6Q029997 for ; Wed, 22 Jul 2009 13:01:32 GMT (envelope-from gk@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n6MD1Wba029995 for perforce@freebsd.org; Wed, 22 Jul 2009 13:01:32 GMT (envelope-from gk@FreeBSD.org) Date: Wed, 22 Jul 2009 13:01:32 GMT Message-Id: <200907221301.n6MD1Wba029995@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 166406 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: Wed, 22 Jul 2009 13:01:33 -0000 http://perforce.freebsd.org/chv.cgi?CH=166406 Change 166406 by gk@gk_h1 on 2009/07/22 13:00:50 Add support for multiply keys per filesystem Replace sbin/mount_pefs with sbin/pefs (it also installs link to /sbin/mount_pefs) Configuration utility is capable of mounting/unmounting filesystems, adding/deleting keys Affected files ... .. //depot/projects/soc2009/gk_pefs/sbin/mount_pefs/Makefile#2 delete .. //depot/projects/soc2009/gk_pefs/sbin/mount_pefs/mount_pefs.c#2 delete .. //depot/projects/soc2009/gk_pefs/sbin/pefs/Makefile#1 add .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.c#1 add .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_ctl.h#1 add .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_key.c#1 add .. //depot/projects/soc2009/gk_pefs/sbin/pefs/pefs_mount.c#1 add .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#7 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#4 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#7 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#6 edit .. //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#7 edit Differences ... ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs.h#7 (text+ko) ==== @@ -38,29 +38,48 @@ */ #include +#include #include #include #include #include -#ifdef _KERNEL +#define PEFS_ALG_SALSA20 1 #define PEFS_TWEAK_SIZE 8 #define PEFS_KEY_BITS 256 #define PEFS_KEY_SIZE (PEFS_KEY_BITS / 8) +#define PEFS_KEYID_SIZE 8 #define PEFS_NAME_CSUM_SIZE 2 +struct pefs_xkey { + int pxk_index; + int pxk_alg; + char pxk_keyid[PEFS_KEYID_SIZE]; + char pxk_key[PEFS_KEY_SIZE]; +}; + +#define PEFS_GETKEY _IOWR('p', 0, struct pefs_xkey) +#define PEFS_ADDKEY _IOWR('p', 1, struct pefs_xkey) +#define PEFS_SETKEY _IOWR('p', 2, struct pefs_xkey) +#define PEFS_DELKEY _IOWR('p', 3, struct pefs_xkey) +#define PEFS_FLUSHKEYS _IO('p', 4) + +#ifdef _KERNEL + #define PEFS_NAME_NTOP_SIZE(a) (((a) * 4 + 2)/3) #define PEFS_NAME_PTON_SIZE(a) (((a) * 3)/4) -LIST_HEAD(pefs_key_head, pefs_key); +TAILQ_HEAD(pefs_key_head, pefs_key); struct pefs_key { volatile u_int pk_refcnt; - LIST_ENTRY(pefs_key) pk_entry; + int pk_alg; + TAILQ_ENTRY(pefs_key) pk_entry; struct mtx *pk_entry_lock; char pk_name[PEFS_KEY_SIZE]; char pk_data[PEFS_KEY_SIZE]; + char pk_keyid[PEFS_KEYID_SIZE]; }; struct pefs_tkey { @@ -79,7 +98,7 @@ }; struct pefs_mount { - struct mount *pm_vfs; + struct mount *pm_lowervfs; struct vnode *pm_rootvp; /* Reference to root pefs_node */ struct mtx pm_keys_lock; struct pefs_key_head pm_keys; @@ -95,21 +114,21 @@ struct uio pc_uio; }; -static inline struct pefs_mount* +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* +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* +static inline struct vnode * PN_TO_VP(struct pefs_node *pn) { MPASS(pn != NULL && pn->pn_vnode != NULL); @@ -120,7 +139,7 @@ struct vnode *pefs_checkvp(struct vnode *vp, char *fil, int lno); #endif -static inline struct vnode* +static inline struct vnode * PEFS_LOWERVP(struct vnode *vp) { struct vnode *lvp; @@ -146,15 +165,20 @@ 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_lookup_name(struct vnode *lvp, struct vnode *ldvp, struct ucred *cred, char *encname, int *encname_len); -struct pefs_key* pefs_node_key(struct pefs_node *pn); +struct pefs_key * pefs_node_key(struct pefs_node *pn); -struct pefs_ctx *pefs_ctx_get(void); +struct pefs_ctx * pefs_ctx_get(void); void pefs_ctx_free(struct pefs_ctx *ctx); -struct pefs_key* pefs_key_get(char *passwd, int passwd_len); -struct pefs_key* pefs_key_ref(struct pefs_key *pk); +struct pefs_key * pefs_key_get(int alg, const char *key, const char *keyid); +struct pefs_key * pefs_key_ref(struct pefs_key *pk); void pefs_key_release(struct pefs_key *pk); +struct pefs_key * pefs_key_lookup(struct pefs_mount *pm, char *keyid); +int pefs_key_add(struct pefs_mount *pm, int index, struct pefs_key *pk); +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); @@ -164,12 +188,12 @@ 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); +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); 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); +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_get(struct pefs_chunk *pc, size_t *size, long *_state); void pefs_chunk_zero(struct pefs_chunk *pc); int pefs_chunk_copy(struct pefs_chunk *pc, size_t skip, struct uio *uio); @@ -178,13 +202,13 @@ extern struct vop_vector pefs_vnodeops; -static inline struct pefs_key* +static inline struct pefs_key * pefs_rootkey(struct pefs_mount *pm) { struct pefs_key *pk; mtx_lock(&pm->pm_keys_lock); - pk = LIST_FIRST(&pm->pm_keys); + pk = TAILQ_FIRST(&pm->pm_keys); mtx_unlock(&pm->pm_keys_lock); return (pk); ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_crypto.c#4 (text+ko) ==== @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2009 Gleb Kurtsou. All rights reserved. + * Copyright (c) 2009 Gleb Kurtsou + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,16 +45,9 @@ 0x5c, 0x83, 0xcb, 0x96, 0x2f, 0xaf, 0x3b, 0xb5, }; -#define MAGIC_KEYGEN_ITERATIONS 32 +#define MAGIC_KEYGEN_ITERATIONS 16 -static const uint8_t magic_key_keygen[PEFS_KEY_SIZE] = { - 0xd2, 0x68, 0x7d, 0x52, 0xb7, 0xc1, 0xe0, 0xc7, - 0x26, 0xf1, 0x53, 0xaf, 0xa1, 0x46, 0x7a, 0xc9, - 0x3a, 0x37, 0xc6, 0xf6, 0x7d, 0xd3, 0xbe, 0xed, - 0xf4, 0x52, 0x24, 0x9e, 0x6c, 0x85, 0xd9, 0x5c, -}; - -static const uint8_t magic_tweak_keygen[PEFS_TWEAK_SIZE] = { +static const char magic_tweak_keygen[PEFS_TWEAK_SIZE] = { 0xc8, 0x27, 0xa3, 0x7e, 0xcf, 0x86, 0x3d, 0x0d, }; @@ -68,10 +62,10 @@ pefs_crypto_init(void) { pefs_ctx_zone = uma_zcreate("pefs_ctx", sizeof(struct pefs_ctx), - NULL, NULL, NULL, (uma_fini) bzero, + NULL, NULL, NULL, (uma_fini)bzero, UMA_ALIGN_PTR, 0); pefs_key_zone = uma_zcreate("pefs_key", sizeof(struct pefs_key), - NULL, NULL, NULL, (uma_fini) bzero, + NULL, NULL, NULL, (uma_fini)bzero, UMA_ALIGN_PTR, 0); } @@ -94,47 +88,50 @@ uma_zfree(pefs_ctx_zone, ctx); } +/* + * This is not a key derivation function in common sense! + * Key should be cryptographically strong. + */ static void -pefs_key_generate(struct pefs_ctx *ctx, uint8_t *key) +pefs_key_generate(struct pefs_ctx *ctx, char *key) { - uint8_t tweak[PEFS_TWEAK_SIZE]; + char tweak[PEFS_TWEAK_SIZE]; int i, j; memcpy(tweak, magic_tweak_keygen, PEFS_TWEAK_SIZE); - salsa20_keysetup(&ctx->pctx_salsa, magic_key_keygen, PEFS_KEY_BITS); - salsa20_ivsetup(&ctx->pctx_salsa, tweak, 0); - salsa20_crypt(&ctx->pctx_salsa, key, key, PEFS_KEY_SIZE); - for (i = 1; i < MAGIC_KEYGEN_ITERATIONS; i++) { - for (j = 0; j < PEFS_TWEAK_SIZE; j++) - tweak[j]++; salsa20_keysetup(&ctx->pctx_salsa, key, PEFS_KEY_BITS); salsa20_ivsetup(&ctx->pctx_salsa, tweak, i * 64); salsa20_crypt(&ctx->pctx_salsa, key, key, PEFS_KEY_SIZE); + for (j = 0; j < PEFS_TWEAK_SIZE; j++) + tweak[j]++; } } struct pefs_key * -pefs_key_get(char *passwd, int passwd_len) +pefs_key_get(int alg, const char *key, const char *keyid) { struct pefs_ctx *ctx; struct pefs_key *pk; - int i; + + switch (alg) { + case PEFS_ALG_SALSA20: + break; + default: + return (NULL); + } pk = uma_zalloc(pefs_key_zone, M_WAITOK | M_ZERO); + pk->pk_alg = alg; refcount_init(&pk->pk_refcnt, 1); - - if (passwd_len > PEFS_KEY_SIZE) - passwd_len = PEFS_KEY_SIZE; - memcpy(pk->pk_name, passwd, passwd_len); - for (i = passwd_len; i < PEFS_KEY_SIZE; i++) - pk->pk_name[i] = passwd[i % passwd_len]; + memcpy(pk->pk_keyid, keyid, PEFS_KEYID_SIZE); ctx = pefs_ctx_get(); + memcpy(pk->pk_data, key, PEFS_KEY_SIZE); + pefs_key_generate(ctx, pk->pk_data); + memcpy(pk->pk_name, pk->pk_data, PEFS_KEY_SIZE); pefs_key_generate(ctx, pk->pk_name); - memcpy(pk->pk_data, pk->pk_name, PEFS_KEY_SIZE); - pefs_key_generate(ctx, pk->pk_data); pefs_ctx_free(ctx); return (pk); @@ -152,8 +149,95 @@ { if (pk == NULL) return; - if (refcount_release(&pk->pk_refcnt)) + if (pk->pk_refcnt == 0) { + PEFSDEBUG("!!!! pefs_key_release: zero reference count\n"); + return; + } + if (refcount_release(&pk->pk_refcnt)) { + PEFSDEBUG("pefs_key_release: free pk=%p\n", pk); uma_zfree(pefs_key_zone, pk); + } +} + +struct pefs_key * +pefs_key_lookup(struct pefs_mount *pm, char *keyid) +{ + struct pefs_key *pk; + + mtx_assert(&pm->pm_keys_lock, MA_OWNED); + TAILQ_FOREACH(pk, &pm->pm_keys, pk_entry) { + if (memcmp(pk->pk_keyid, keyid, PEFS_KEYID_SIZE) == 0) { + return (pk); + } + } + + return (NULL); +} + +int +pefs_key_add(struct pefs_mount *pm, int index, struct pefs_key *pk) +{ + struct pefs_key *i, *pk_pos; + int pos; + + mtx_lock(&pm->pm_keys_lock); + if (index == 0 && !TAILQ_EMPTY(&pm->pm_keys)) { + mtx_unlock(&pm->pm_keys_lock); + return (EEXIST); + } + pk_pos = NULL; + pos = 0; + TAILQ_FOREACH(i, &pm->pm_keys, pk_entry) { + if (memcmp(pk->pk_keyid, i->pk_keyid, PEFS_KEYID_SIZE) == 0 || + memcmp(pk->pk_name, i->pk_name, PEFS_KEY_SIZE) == 0 || + memcmp(pk->pk_data, i->pk_data, PEFS_KEY_SIZE) == 0) { + mtx_unlock(&pm->pm_keys_lock); + return (EEXIST); + } + if (index == pos + 1) { + pk_pos = i; + } + } + pk->pk_entry_lock = &pm->pm_keys_lock; + if (TAILQ_EMPTY(&pm->pm_keys)) { + TAILQ_INSERT_HEAD(&pm->pm_keys, pk, pk_entry); + PEFSDEBUG("pefs_key_add: root key added: %p\n", pk); + } else if (pk_pos == NULL) { + TAILQ_INSERT_TAIL(&pm->pm_keys, pk, pk_entry); + PEFSDEBUG("pefs_key_add: tail key added: %p\n", pk); + } else { + TAILQ_INSERT_AFTER(&pm->pm_keys, pk_pos, pk, pk_entry); + PEFSDEBUG("pefs_key_add: key added at pos=%d: %p\n", pos, pk); + } + mtx_unlock(&pm->pm_keys_lock); + + return (0); +} + +void +pefs_key_remove(struct pefs_mount *pm, struct pefs_key *pk) +{ + mtx_assert(&pm->pm_keys_lock, MA_OWNED); + MPASS(pk->pk_entry_lock != NULL); + TAILQ_REMOVE(&pm->pm_keys, pk, pk_entry); + pk->pk_entry_lock = NULL; + PEFSDEBUG("pefs_key_remove: pk=%p\n", pk); + pefs_key_release(pk); +} + +int +pefs_key_remove_all(struct pefs_mount *pm) +{ + int n = 0; + + mtx_lock(&pm->pm_keys_lock); + while (!TAILQ_EMPTY(&pm->pm_keys)) { + pefs_key_remove(pm, TAILQ_FIRST(&pm->pm_keys)); + n++; + } + mtx_unlock(&pm->pm_keys_lock); + + return (n); } void @@ -277,14 +361,20 @@ 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) { - u_short csum; + struct pefs_key *ki; + char *dec; int free_ctx = 0; - int r; + int r, ki_rev; if (pk == NULL) { PEFSDEBUG("!!!! %s: NULL pk\n", __func__); return (-1); } + + if (enc == plain) { + PEFSDEBUG("pefs_name_decrypt: enc == plain\n"); + return (-1); + } r = pefs_name_pton(enc, enc_len, plain, plain_size); if (r < 0 || r <= PEFS_TWEAK_SIZE + PEFS_NAME_CSUM_SIZE) { @@ -297,29 +387,55 @@ free_ctx = 1; } - salsa20_keysetup(&ctx->pctx_salsa, pk->pk_name, PEFS_KEY_BITS); - salsa20_ivsetup(&ctx->pctx_salsa, magic_tweak_name, 0); - salsa20_crypt(&ctx->pctx_salsa, plain, plain, r); + ki = pk; + ki_rev = 0; + if (plain_size >= r * 2) + dec = plain + r; + else + dec = plain; + do { + PEFSDEBUG("pefs_name_decrypt: check key %p\n", ki); + salsa20_keysetup(&ctx->pctx_salsa, ki->pk_name, PEFS_KEY_BITS); + salsa20_ivsetup(&ctx->pctx_salsa, magic_tweak_name, 0); + salsa20_crypt(&ctx->pctx_salsa, plain, dec, r); + + if (pefs_name_checksum(dec, r) == 0) + break; + + if (plain == dec) { + /* Restore previous value. */ + salsa20_ivsetup(&ctx->pctx_salsa, magic_tweak_name, 0); + salsa20_crypt(&ctx->pctx_salsa, dec, plain, r); + } + + if (!ki_rev) { + ki = TAILQ_NEXT(ki, pk_entry); + PEFSDEBUG("pefs_name_decrypt: next key %p\n", ki); + if (ki == NULL) { + ki_rev = 1; + ki = pk; + } + } + if (ki_rev) { + ki = TAILQ_PREV(ki, pefs_key_head, pk_entry); + PEFSDEBUG("pefs_name_decrypt: prev key %p\n", ki); + } + } while (ki != NULL); if (free_ctx) pefs_ctx_free(ctx); - csum = pefs_name_checksum(plain, r); - if (csum != 0) { - PEFSDEBUG("%s: invalid csum = %d\n", __func__, csum); + if (ki == NULL) return (-1); - } if (ptk) { - ptk->ptk_key = pk; - memcpy(plain, ptk->ptk_tweak, PEFS_TWEAK_SIZE); + ptk->ptk_key = ki; + memcpy(ptk->ptk_tweak, dec, PEFS_TWEAK_SIZE); } r -= PEFS_TWEAK_SIZE + PEFS_NAME_CSUM_SIZE; - memcpy(plain, plain + PEFS_TWEAK_SIZE, r); - - if (r < plain_size) - plain[r] = '\0'; + memcpy(plain, dec + PEFS_TWEAK_SIZE, r); + plain[r] = '\0'; PEFSDEBUG("pefs_name_decrypt: %d; %.*s => %.*s\n", r, enc_len, enc, r < 0 ? 0 : r, plain); ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_subr.c#7 (text+ko) ==== @@ -182,6 +182,7 @@ PEFSDEBUG("pefs_insmntque_dtr: free node %p\n", pn); vp->v_data = NULL; vp->v_vnlock = &vp->v_lock; + PEFSDEBUG("pefs_insmntque_dtr: pk=%p\n", pn->pn_tkey.ptk_key); pefs_key_release(pn->pn_tkey.ptk_key); uma_zfree(pefs_node_zone, pn); vp->v_op = &dead_vnodeops; @@ -321,6 +322,9 @@ if (xp->pn_tkey.ptk_key != NULL) xp->pn_flags = PN_HASKEY; } + if (xp->pn_tkey.ptk_key != NULL) { + PEFSDEBUG("pefs_node_get: node has key: pk_refcnt=%d\n", xp->pn_tkey.ptk_key->pk_refcnt); + } error = getnewvnode("pefs", mp, &pefs_vnodeops, &vp); if (error) { ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vfsops.c#6 (text+ko) ==== @@ -133,20 +133,12 @@ M_PEFSMNT, M_WAITOK | M_ZERO); /* XXX */ mtx_init(&xmp->pm_keys_lock, "pefs_mount lock", NULL, MTX_DEF); - LIST_INIT(&xmp->pm_keys); - -#if 0 - // FIXME - struct pefs_key *pk; - pk = pefs_key_get("a", 1); - pk->pk_entry_lock = &xmp->pm_keys_lock; - LIST_INSERT_HEAD(&xmp->pm_keys, pk, pk_entry); -#endif + TAILQ_INIT(&xmp->pm_keys); /* * Save reference to underlying FS */ - xmp->pm_vfs = lowerrootvp->v_mount; + xmp->pm_lowervfs = lowerrootvp->v_mount; /* * Save reference. Each mount also holds @@ -219,15 +211,7 @@ */ pm = VFS_TO_PEFS(mp); mp->mnt_data = 0; - mtx_lock(&pm->pm_keys_lock); - while (!LIST_EMPTY(&pm->pm_keys)) { - struct pefs_key *pk = LIST_FIRST(&pm->pm_keys); - - LIST_REMOVE(pk, pk_entry); - pk->pk_entry_lock = NULL; - pefs_key_release(pk); - } - mtx_unlock(&pm->pm_keys_lock); + pefs_key_remove_all(pm); mtx_destroy(&pm->pm_keys_lock); free(pm, M_PEFSMNT); return 0; @@ -248,10 +232,6 @@ vp = VFS_TO_PEFS(mp)->pm_rootvp; VREF(vp); -#ifdef PEFSXXX_DEBUG - if (VOP_ISLOCKED(vp)) - panic("root vnode is locked.\n"); -#endif vn_lock(vp, flags | LK_RETRY); *vpp = vp; return 0; @@ -260,7 +240,7 @@ static int pefs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg) { - return VFS_QUOTACTL(VFS_TO_PEFS(mp)->pm_vfs, cmd, uid, arg); + return VFS_QUOTACTL(VFS_TO_PEFS(mp)->pm_lowervfs, cmd, uid, arg); } static int @@ -275,7 +255,7 @@ bzero(&mstat, sizeof(mstat)); - error = VFS_STATFS(VFS_TO_PEFS(mp)->pm_vfs, &mstat); + error = VFS_STATFS(VFS_TO_PEFS(mp)->pm_lowervfs, &mstat); if (error) return (error); @@ -305,7 +285,7 @@ pefs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { int error; - error = VFS_VGET(VFS_TO_PEFS(mp)->pm_vfs, ino, flags, vpp); + error = VFS_VGET(VFS_TO_PEFS(mp)->pm_lowervfs, ino, flags, vpp); if (error) return (error); @@ -317,7 +297,7 @@ { int error; - error = VFS_FHTOVP(VFS_TO_PEFS(mp)->pm_vfs, fidp, vpp); + error = VFS_FHTOVP(VFS_TO_PEFS(mp)->pm_lowervfs, fidp, vpp); if (error) return (error); @@ -333,7 +313,7 @@ static int pefs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, int namespace, const char *attrname) { - return VFS_EXTATTRCTL(VFS_TO_PEFS(mp)->pm_vfs, cmd, filename_vp, + return VFS_EXTATTRCTL(VFS_TO_PEFS(mp)->pm_lowervfs, cmd, filename_vp, namespace, attrname); } ==== //depot/projects/soc2009/gk_pefs/sys/fs/pefs/pefs_vnops.c#7 (text+ko) ==== @@ -131,12 +131,6 @@ 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", - __func__, cnp->cn_nameiop, cnp->cn_pnbuf, (int) cnp->cn_namelen, cnp->cn_nameptr, - (int) cnp->cn_consume, (int) cnp->cn_namelen); - */ - return (0); } @@ -300,6 +294,49 @@ } /* + * Recycle vnodes using key pk. + * If pk is NULL recycle all vnodes with PN_HASKEY flag set. + */ +static int +pefs_flushkey(struct mount *mp, struct pefs_key *pk) +{ + struct vnode *vp, *mvp; + struct pefs_node *pn; + int error; + + PEFSDEBUG("pefs_flushkey: pk=%p\n", pk); + MNT_ILOCK(mp); +loop: + MNT_VNODE_FOREACH(vp, mp, mvp) { + if (vp->v_type != VREG && vp->v_type != VDIR) + continue; + VI_LOCK(vp); + pn = VP_TO_PN(vp); + if ((pn->pn_flags & PN_HASKEY) && + (pk == NULL || pn->pn_tkey.ptk_key == pk)) { + vholdl(vp); + MNT_IUNLOCK(mp); + error = vn_lock(vp, LK_INTERLOCK | LK_EXCLUSIVE); + if (error) { + vdrop(vp); + MNT_ILOCK(mp); + MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); + goto loop; + } + PEFSDEBUG("pefs_flushkey: pk=%p, vp=%p\n", pk, vp); + vgone(vp); + VOP_UNLOCK(vp, 0); + vdrop(vp); + MNT_ILOCK(mp); + } else { + VI_UNLOCK(vp); + } + } + MNT_IUNLOCK(mp); + return (0); +} + +/* * This is the 10-Apr-92 bypass routine. * This version has been optimized for speed, throwing away some * safety checks. It should still always work, but it's not as @@ -887,18 +924,14 @@ static int pefs_inactive(struct vop_inactive_args *ap) { - /* Do not vrecycle vnode */ -#if 0 struct vnode *vp = ap->a_vp; struct thread *td = ap->a_td; + struct pefs_node *pn = VP_TO_PN(vp); - PEFSDEBUG("pefs_inactive: recycle vnode: vp=%p\n", vp); - /* - * If this is the last reference, then free up the vnode - * so as not to tie up the lower vnodes. - */ - vrecycle(vp, td); -#endif + if ((pn->pn_flags & PN_HASKEY) && pn->pn_tkey.ptk_key->pk_entry_lock == NULL) { + PEFSDEBUG("pefs_inactive: recycle vnode: vp=%p\n", vp); + vrecycle(vp, td); + } return (0); } @@ -910,8 +943,8 @@ pefs_reclaim(struct vop_reclaim_args *ap) { struct vnode *vp = ap->a_vp; - struct pefs_node *xp = VP_TO_PN(vp); - struct vnode *lowervp = xp->pn_lowervp; + struct pefs_node *pn = VP_TO_PN(vp); + struct vnode *lowervp = pn->pn_lowervp; PEFSDEBUG("pefs_reclaim: vp=%p\n", vp); @@ -919,7 +952,7 @@ cache_purge(vp); if (lowervp) - pefs_node_free(xp); + pefs_node_free(pn); /* * Use the interlock to protect the clearing of v_data to * prevent faults in pefs_lock(). @@ -941,8 +974,9 @@ pefs_print(struct vop_print_args *ap) { struct vnode *vp = ap->a_vp; + struct pefs_node *pn = VP_TO_PN(vp); - printf("\tvp=%p, lowervp=%p\n", vp, PEFS_LOWERVP(vp)); + printf("\tvp=%p, lowervp=%p, flags=%04d\n", vp, pn->pn_lowervp, pn->pn_flags); return (0); } @@ -950,14 +984,14 @@ static int pefs_getwritemount(struct vop_getwritemount_args *ap) { - struct pefs_node *xp; + struct pefs_node *pn; struct vnode *lowervp; struct vnode *vp; vp = ap->a_vp; VI_LOCK(vp); - xp = VP_TO_PN(vp); - if (xp && (lowervp = xp->pn_lowervp)) { + pn = VP_TO_PN(vp); + if (pn && (lowervp = pn->pn_lowervp)) { VI_LOCK_FLAGS(lowervp, MTX_DUPOK); VI_UNLOCK(vp); vholdl(lowervp); @@ -1043,13 +1077,13 @@ pn_key = pefs_node_key(pn); buf = malloc(MAXNAMLEN + 1, M_PEFSBUF, M_WAITOK); - printf("%s: size = %d\n", __func__, o_resid - puio->uio_resid); + PEFSDEBUG("%s: size = %d\n", __func__, o_resid - puio->uio_resid); pefs_chunk_shrink(pc, o_resid - puio->uio_resid); while (1) { mem = pefs_chunk_get(pc, &size, &arg); if (mem == NULL) break; - printf("%s: convert mem=%p; size=%d\n", __func__, mem, size); + PEFSDEBUG("%s: convert mem=%p; size=%d\n", __func__, mem, size); pefs_readdir_decrypt(pn_key, pn->pn_flags, mem, size, buf, MAXNAMLEN + 1); } pefs_chunk_copy(pc, 0, uio); @@ -1276,13 +1310,6 @@ if (!(pn->pn_flags & PN_HASKEY)) return (VOP_READLINK(lvp, uio, ap->a_cred)); - /* - printf("%s: uio_offset=%ju, uio_resid=%u, uio_segflg:sysspace=%d, uio_rw=%x, ioveccnt=%d; iov_len[0]=%u\n", - __func__, - (intmax_t) uio->uio_offset, uio->uio_resid, - uio->uio_segflg == UIO_SYSSPACE, uio->uio_rw, uio->uio_iovcnt, - uio->uio_iov[0].iov_len); - */ o_offset = uio->uio_offset; o_resid = uio->uio_resid; pc = pefs_chunk_create(o_resid); @@ -1434,6 +1461,95 @@ return (error); } +static int +pefs_ioctl(struct vop_ioctl_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct pefs_mount *pm = VFS_TO_PEFS(vp->v_mount); + struct pefs_xkey *xk = ap->a_data; + struct pefs_key *pk; + int error, i; + + vn_lock(pm->pm_rootvp, LK_SHARED | LK_RETRY); + error = VOP_ACCESS(pm->pm_rootvp, VWRITE, ap->a_cred, ap->a_td); + VOP_UNLOCK(pm->pm_rootvp, 0); + if (error != 0) + return (error); + + /* + * Recycle all unused vnodes after adding/deleting keys to cleanup + * caches. + */ + switch (ap->a_command) { + case PEFS_GETKEY: + PEFSDEBUG("pefs_ioctl: get key: pm=%p, pxk_index=%d\n", pm, xk->pxk_index); + mtx_lock(&pm->pm_keys_lock); + i = 0; + TAILQ_FOREACH(pk, &pm->pm_keys, pk_entry) { + if (i++ == xk->pxk_index) { + memcpy(xk->pxk_keyid, pk->pk_keyid, PEFS_KEYID_SIZE); + xk->pxk_alg = pk->pk_alg; + break; + } + } + mtx_unlock(&pm->pm_keys_lock); + if (pk == NULL) + error = ENOENT; + break; + case PEFS_SETKEY: + mtx_lock(&pm->pm_keys_lock); + pk = pefs_key_lookup(pm, xk->pxk_keyid); + mtx_unlock(&pm->pm_keys_lock); + if (pk != NULL) + error = ENOTSUP; // FIXME + else + error = ENOENT; + PEFSDEBUG("pefs_ioctl: set key\n"); + break; + case PEFS_ADDKEY: + PEFSDEBUG("pefs_ioctl: add key\n"); + pk = pefs_key_get(xk->pxk_alg, xk->pxk_key, xk->pxk_keyid); + if (pk == NULL) { + error = ENOENT; + break; + } + error = pefs_key_add(pm, xk->pxk_index, pk); + if (error == 0) + vflush(vp->v_mount, 0, 0, ap->a_td); + else + pefs_key_release(pk); + break; + case PEFS_DELKEY: + PEFSDEBUG("pefs_ioctl: del key\n"); + mtx_lock(&pm->pm_keys_lock); + pk = pefs_key_lookup(pm, xk->pxk_keyid); + if (pk != NULL) { + pefs_key_ref(pk); + pefs_key_remove(pm, pk); + mtx_unlock(&pm->pm_keys_lock); + vflush(vp->v_mount, 0, 0, ap->a_td); + pefs_flushkey(vp->v_mount, pk); + pefs_key_release(pk); + } else { + mtx_unlock(&pm->pm_keys_lock); + error = ENOENT; + } + break; + case PEFS_FLUSHKEYS: + PEFSDEBUG("pefs_ioctl: flush keys\n"); + if (pefs_key_remove_all(pm)) { + vflush(vp->v_mount, 0, 0, ap->a_td); + pefs_flushkey(vp->v_mount, NULL); + } + break; + default: + error = ENOTTY; + break; + }; + + return (error); +} + /* * Global vfs data structures */ @@ -1473,4 +1589,6 @@ .vop_getpages = vop_stdgetpages, .vop_putpages = vop_stdputpages, .vop_fsync = vop_stdfsync, + /* */ + .vop_ioctl = pefs_ioctl, };