Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Sep 2009 21:47:00 GMT
From:      Gleb Kurtsou <gk@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 168308 for review
Message-ID:  <200909072147.n87Ll0WV029538@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <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) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200909072147.n87Ll0WV029538>