PERFORCE change 168308 for review
Gleb Kurtsou
gk at FreeBSD.org
Mon Sep 7 21:47:01 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=168308
Change 168308 by gk at 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
#include <assert.h>
#include <ctype.h>
#include <inttypes.h>
@@ -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 <sys/param.h>
+#include <sys/dirent.h>
#include <sys/endian.h>
#include <sys/lock.h>
#include <sys/libkern.h>
@@ -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 <sys/queue.h>
#include <sys/proc.h>
#include <sys/uio.h>
+#include <sys/taskqueue.h>
#include <sys/vnode.h>
#include <fs/pefs/pefs.h>
@@ -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) <<<
More information about the p4-projects
mailing list