eCryptfs: track header bytes rather than extents
authorMichael Halcrow <mhalcrow@us.ibm.com>
Wed, 6 Feb 2008 09:38:32 +0000 (01:38 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 6 Feb 2008 18:41:12 +0000 (10:41 -0800)
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 <mhalcrow@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/inode.c
fs/ecryptfs/main.c
fs/ecryptfs/mmap.c

index 5e7d018..4d1b2b4 100644 (file)
@@ -379,8 +379,7 @@ out:
 static 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));
 }
 
@@ -842,15 +841,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;
        }
 }
 
@@ -1236,7 +1233,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;
@@ -1311,40 +1309,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;
 }
 
@@ -1370,15 +1344,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;
 
@@ -1389,40 +1361,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;
 }
@@ -1442,16 +1413,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;
 }
@@ -1466,7 +1437,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;
 }
 
 /**
index 466661c..3d637e9 100644 (file)
@@ -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;
@@ -518,7 +518,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;
index ed0ed84..a2bc9df 100644 (file)
@@ -365,8 +365,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);
@@ -685,7 +684,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.
  *
@@ -697,8 +696,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;
 
index d9f53c3..b67ce83 100644 (file)
@@ -654,11 +654,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,
index 9a5e0d1..dc74b18 100644 (file)
@@ -100,13 +100,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;
 }
 
 /**
@@ -132,8 +133,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;
 
@@ -155,9 +159,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),