2007-11-02 18:53:27

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 0/3] eCryptfs: extent offset fix, crypto performance, and larger header regions

This patch set includes some minor fixes for eCryptfs, including:

- An enhancement to allow larger header regions

- A bugfix for hosts with page size >4K

- An enhancement to reduce crypto overhead

I recommend merging at least the bugfix into 2.6.24.


2007-11-02 18:54:24

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 1/3] eCryptfs: Track header bytes rather than extents

Remove internal references to header extents; just keep track of
header bytes instead. Headers can easily span multiple pages with the
recent persistent file changes.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 98 +++++++++++++++--------------------------
fs/ecryptfs/ecryptfs_kernel.h | 3 +-
fs/ecryptfs/inode.c | 8 +--
fs/ecryptfs/main.c | 5 --
fs/ecryptfs/mmap.c | 21 +++++----
5 files changed, 51 insertions(+), 84 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 9d70289..ca0dfea 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -361,8 +361,7 @@ out:
void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
struct ecryptfs_crypt_stat *crypt_stat)
{
- (*offset) = ((crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front)
+ (*offset) = (crypt_stat->num_header_bytes_at_front
+ (crypt_stat->extent_size * extent_num));
}

@@ -826,15 +825,13 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
set_extent_mask_and_shift(crypt_stat);
crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
- crypt_stat->num_header_extents_at_front = 0;
+ crypt_stat->num_header_bytes_at_front = 0;
else {
if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)
- crypt_stat->num_header_extents_at_front =
- (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE
- / crypt_stat->extent_size);
+ crypt_stat->num_header_bytes_at_front =
+ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
else
- crypt_stat->num_header_extents_at_front =
- (PAGE_CACHE_SIZE / crypt_stat->extent_size);
+ crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE;
}
}

@@ -1220,7 +1217,8 @@ ecryptfs_write_header_metadata(char *virt,

header_extent_size = (u32)crypt_stat->extent_size;
num_header_extents_at_front =
- (u16)crypt_stat->num_header_extents_at_front;
+ (u16)(crypt_stat->num_header_bytes_at_front
+ / crypt_stat->extent_size);
header_extent_size = cpu_to_be32(header_extent_size);
memcpy(virt, &header_extent_size, 4);
virt += 4;
@@ -1295,40 +1293,16 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size,
static int
ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
struct dentry *ecryptfs_dentry,
- char *page_virt)
+ char *virt)
{
- int current_header_page;
- int header_pages;
int rc;

- rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt,
- 0, PAGE_CACHE_SIZE);
- if (rc) {
+ rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,
+ 0, crypt_stat->num_header_bytes_at_front);
+ if (rc)
printk(KERN_ERR "%s: Error attempting to write header "
"information to lower file; rc = [%d]\n", __FUNCTION__,
rc);
- goto out;
- }
- header_pages = ((crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front)
- / PAGE_CACHE_SIZE);
- memset(page_virt, 0, PAGE_CACHE_SIZE);
- current_header_page = 1;
- while (current_header_page < header_pages) {
- loff_t offset;
-
- offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT);
- if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
- page_virt, offset,
- PAGE_CACHE_SIZE))) {
- printk(KERN_ERR "%s: Error attempting to write header "
- "information to lower file; rc = [%d]\n",
- __FUNCTION__, rc);
- goto out;
- }
- current_header_page++;
- }
-out:
return rc;
}

@@ -1354,15 +1328,13 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
* retrieved via a prompt. Exactly what happens at this point should
* be policy-dependent.
*
- * TODO: Support header information spanning multiple pages
- *
* Returns zero on success; non-zero on error
*/
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
{
struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
- char *page_virt;
+ char *virt;
size_t size = 0;
int rc = 0;

@@ -1373,40 +1345,39 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
goto out;
}
} else {
+ printk(KERN_WARNING "%s: Encrypted flag not set\n",
+ __FUNCTION__);
rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING,
- "Called with crypt_stat->encrypted == 0\n");
goto out;
}
/* Released in this function */
- page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER);
- if (!page_virt) {
- ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL);
+ if (!virt) {
+ printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__);
rc = -ENOMEM;
goto out;
}
- rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat,
- ecryptfs_dentry);
+ rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat,
+ ecryptfs_dentry);
if (unlikely(rc)) {
- ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n");
- memset(page_virt, 0, PAGE_CACHE_SIZE);
+ printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
+ __FUNCTION__, rc);
goto out_free;
}
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry,
- crypt_stat, page_virt,
- size);
+ crypt_stat, virt, size);
else
rc = ecryptfs_write_metadata_to_contents(crypt_stat,
- ecryptfs_dentry,
- page_virt);
+ ecryptfs_dentry, virt);
if (rc) {
- printk(KERN_ERR "Error writing metadata out to lower file; "
- "rc = [%d]\n", rc);
+ printk(KERN_ERR "%s: Error writing metadata out to lower file; "
+ "rc = [%d]\n", __FUNCTION__, rc);
goto out_free;
}
out_free:
- kmem_cache_free(ecryptfs_header_cache_0, page_virt);
+ memset(virt, 0, crypt_stat->num_header_bytes_at_front);
+ kfree(virt);
out:
return rc;
}
@@ -1426,16 +1397,16 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
virt += sizeof(u32);
memcpy(&num_header_extents_at_front, virt, sizeof(u16));
num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
- crypt_stat->num_header_extents_at_front =
- (int)num_header_extents_at_front;
+ crypt_stat->num_header_bytes_at_front =
+ (((size_t)num_header_extents_at_front
+ * (size_t)header_extent_size));
(*bytes_read) = (sizeof(u32) + sizeof(u16));
if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
- && ((crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front)
+ && (crypt_stat->num_header_bytes_at_front
< ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
rc = -EINVAL;
- printk(KERN_WARNING "Invalid number of header extents: [%zd]\n",
- crypt_stat->num_header_extents_at_front);
+ printk(KERN_WARNING "Invalid header size: [%zd]\n",
+ crypt_stat->num_header_bytes_at_front);
}
return rc;
}
@@ -1450,7 +1421,8 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
*/
static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
{
- crypt_stat->num_header_extents_at_front = 2;
+ crypt_stat->num_header_bytes_at_front =
+ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
}

/**
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index ce7a5d4..78b7916 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -237,7 +237,7 @@ struct ecryptfs_crypt_stat {
u32 flags;
unsigned int file_version;
size_t iv_bytes;
- size_t num_header_extents_at_front;
+ size_t num_header_bytes_at_front;
size_t extent_size; /* Data extent size; default is 4096 */
size_t key_size;
size_t extent_shift;
@@ -521,7 +521,6 @@ extern struct kmem_cache *ecryptfs_file_info_cache;
extern struct kmem_cache *ecryptfs_dentry_info_cache;
extern struct kmem_cache *ecryptfs_inode_info_cache;
extern struct kmem_cache *ecryptfs_sb_info_cache;
-extern struct kmem_cache *ecryptfs_header_cache_0;
extern struct kmem_cache *ecryptfs_header_cache_1;
extern struct kmem_cache *ecryptfs_header_cache_2;
extern struct kmem_cache *ecryptfs_xattr_cache;
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 0b1ab01..8fb40ff 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -378,8 +378,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_sb)->mount_crypt_stat;
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
- file_size = ((crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front)
+ file_size = (crypt_stat->num_header_bytes_at_front
+ i_size_read(lower_dentry->d_inode));
else
file_size = i_size_read(lower_dentry->d_inode);
@@ -697,7 +696,7 @@ ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
* @crypt_stat: Crypt_stat associated with file
* @upper_size: Size of the upper file
*
- * Calculate the requried size of the lower file based on the
+ * Calculate the required size of the lower file based on the
* specified size of the upper file. This calculation is based on the
* number of headers in the underlying file and the extent size.
*
@@ -709,8 +708,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
{
loff_t lower_size;

- lower_size = (crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front);
+ lower_size = crypt_stat->num_header_bytes_at_front;
if (upper_size != 0) {
loff_t num_extents;

diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index b83a512..333db23 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -650,11 +650,6 @@ static struct ecryptfs_cache_info {
.size = sizeof(struct ecryptfs_sb_info),
},
{
- .cache = &ecryptfs_header_cache_0,
- .name = "ecryptfs_headers_0",
- .size = PAGE_CACHE_SIZE,
- },
- {
.cache = &ecryptfs_header_cache_1,
.name = "ecryptfs_headers_1",
.size = PAGE_CACHE_SIZE,
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 16a7a55..a6242a7 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -102,13 +102,14 @@ static void set_header_info(char *page_virt,
struct ecryptfs_crypt_stat *crypt_stat)
{
size_t written;
- int save_num_header_extents_at_front =
- crypt_stat->num_header_extents_at_front;
+ size_t save_num_header_bytes_at_front =
+ crypt_stat->num_header_bytes_at_front;

- crypt_stat->num_header_extents_at_front = 1;
+ crypt_stat->num_header_bytes_at_front =
+ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written);
- crypt_stat->num_header_extents_at_front =
- save_num_header_extents_at_front;
+ crypt_stat->num_header_bytes_at_front =
+ save_num_header_bytes_at_front;
}

/**
@@ -134,8 +135,11 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
loff_t view_extent_num = ((((loff_t)page->index)
* num_extents_per_page)
+ extent_num_in_page);
+ size_t num_header_extents_at_front =
+ (crypt_stat->num_header_bytes_at_front
+ / crypt_stat->extent_size);

- if (view_extent_num < crypt_stat->num_header_extents_at_front) {
+ if (view_extent_num < num_header_extents_at_front) {
/* This is a header extent */
char *page_virt;

@@ -157,9 +161,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
} else {
/* This is an encrypted data extent */
loff_t lower_offset =
- ((view_extent_num -
- crypt_stat->num_header_extents_at_front)
- * crypt_stat->extent_size);
+ ((view_extent_num * crypt_stat->extent_size)
+ - crypt_stat->num_header_bytes_at_front);

rc = ecryptfs_read_lower_page_segment(
page, (lower_offset >> PAGE_CACHE_SHIFT),
--
1.5.0.6

2007-11-02 18:54:54

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 2/3] eCryptfs: Increment extent_offset once per loop interation

The extent_offset is getting incremented twice per loop iteration
through any given page. It should only be getting incremented
once. This bug should only impact hosts with >4K page sizes.

Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index ca0dfea..4f14d4c 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -503,7 +503,6 @@ int ecryptfs_encrypt_page(struct page *page)
"\n", rc);
goto out;
}
- extent_offset++;
}
out:
kfree(enc_extent_virt);
@@ -639,7 +638,6 @@ int ecryptfs_decrypt_page(struct page *page)
"rc = [%d]\n", __FUNCTION__, rc);
goto out;
}
- extent_offset++;
}
out:
kfree(enc_extent_virt);
--
1.5.0.6

2007-11-02 18:55:52

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH 3/3] eCryptfs: Set inode key only once per crypto operation

There is no need to keep re-setting the same key for any given
eCryptfs inode. This patch optimizes the use of the crypto API and
helps performance a bit.

Signed-off-by: Trevor Highland <[email protected]>
Signed-off-by: Michael Halcrow <[email protected]>
---
fs/ecryptfs/crypto.c | 7 +++++--
fs/ecryptfs/ecryptfs_kernel.h | 1 +
2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 4f14d4c..a0f53aa 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -337,8 +337,11 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
}
/* Consider doing this once, when the file is opened */
mutex_lock(&crypt_stat->cs_tfm_mutex);
- rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
- crypt_stat->key_size);
+ if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
+ rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
+ crypt_stat->key_size);
+ crypt_stat->flags |= ECRYPTFS_KEY_SET;
+ }
if (rc) {
ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
rc);
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 78b7916..114cb86 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -234,6 +234,7 @@ struct ecryptfs_crypt_stat {
#define ECRYPTFS_KEY_VALID 0x00000080
#define ECRYPTFS_METADATA_IN_XATTR 0x00000100
#define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200
+#define ECRYPTFS_KEY_SET 0x00000400
u32 flags;
unsigned int file_version;
size_t iv_bytes;
--
1.5.0.6

2007-11-02 20:10:56

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 3/3] eCryptfs: Set inode key only once per crypto operation

On Fri, 2 Nov 2007 13:53:08 -0500
Michael Halcrow <[email protected]> wrote:

> There is no need to keep re-setting the same key for any given
> eCryptfs inode. This patch optimizes the use of the crypto API and
> helps performance a bit.
>
> Signed-off-by: Trevor Highland <[email protected]>
> Signed-off-by: Michael Halcrow <[email protected]>

I've inferred from this that Michael authored this patch. Please
let me know if that was incorrect.

The way in which we indicate authorship is to put a From: line right
at the top of the changelog. If no such line appears then the From:
line from the mail headers is used.

2007-11-02 20:21:19

by Michael Halcrow

[permalink] [raw]
Subject: Re: [PATCH 3/3] eCryptfs: Set inode key only once per crypto operation

On Fri, Nov 02, 2007 at 01:10:31PM -0700, Andrew Morton wrote:
> On Fri, 2 Nov 2007 13:53:08 -0500
> Michael Halcrow <[email protected]> wrote:
>
> > There is no need to keep re-setting the same key for any given
> > eCryptfs inode. This patch optimizes the use of the crypto API and
> > helps performance a bit.
> >
> > Signed-off-by: Trevor Highland <[email protected]>
> > Signed-off-by: Michael Halcrow <[email protected]>
>
> I've inferred from this that Michael authored this patch. Please
> let me know if that was incorrect.

Trevor Highland actually authored this one.

> The way in which we indicate authorship is to put a From: line right
> at the top of the changelog. If no such line appears then the From:
> line from the mail headers is used.

Noted.

Mike


Attachments:
(No filename) (789.00 B)
(No filename) (481.00 B)
Download all attachments