Cc: Linux Filesystems <linux-fsdevel@vger.kernel.org>
Cc: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]
Signed-off-by: Nick Piggin <[EMAIL PROTECTED]>

 fs/ecryptfs/crypto.c          |   32 +++---
 fs/ecryptfs/ecryptfs_kernel.h |    4 
 fs/ecryptfs/mmap.c            |  213 +++++++++++++++++++-----------------------
 3 files changed, 119 insertions(+), 130 deletions(-)

Index: linux-2.6/fs/ecryptfs/mmap.c
===================================================================
--- linux-2.6.orig/fs/ecryptfs/mmap.c
+++ linux-2.6/fs/ecryptfs/mmap.c
@@ -36,26 +36,6 @@
 
 struct kmem_cache *ecryptfs_lower_page_cache;
 
-/**
- * ecryptfs_get1page
- *
- * Get one page from cache or lower f/s, return error otherwise.
- *
- * Returns unlocked and up-to-date page (if ok), with increased
- * refcnt.
- */
-static struct page *ecryptfs_get1page(struct file *file, int index)
-{
-       struct dentry *dentry;
-       struct inode *inode;
-       struct address_space *mapping;
-
-       dentry = file->f_path.dentry;
-       inode = dentry->d_inode;
-       mapping = inode->i_mapping;
-       return read_mapping_page(mapping, index, (void *)file);
-}
-
 static
 int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros);
 
@@ -360,17 +340,14 @@ out:
 /**
  * Called with lower inode mutex held.
  */
-static int fill_zeros_to_end_of_page(struct page *page, unsigned int to)
+static int fill_zeros_to_end_of_page(struct page *page, loff_t new_isize)
 {
-       struct inode *inode = page->mapping->host;
        int end_byte_in_page;
        char *page_virt;
 
-       if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index)
+       if ((new_isize >> PAGE_CACHE_SHIFT) != page->index)
                goto out;
-       end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
-       if (to > end_byte_in_page)
-               end_byte_in_page = to;
+       end_byte_in_page = new_isize % PAGE_CACHE_SIZE;
        page_virt = kmap_atomic(page, KM_USER0);
        memset((page_virt + end_byte_in_page), 0,
               (PAGE_CACHE_SIZE - end_byte_in_page));
@@ -380,16 +357,35 @@ out:
        return 0;
 }
 
-static int ecryptfs_prepare_write(struct file *file, struct page *page,
-                                 unsigned from, unsigned to)
+static int ecryptfs_write_begin(struct file *file,struct address_space 
*mapping,
+                               loff_t pos, unsigned len, unsigned flags,
+                               struct page **pagep, void **fsdata)
 {
+       struct page *page;
+       pgoff_t index;
        int rc = 0;
 
-       if (from == 0 && to == PAGE_CACHE_SIZE)
-               goto out;       /* If we are writing a full page, it will be
-                                  up to date. */
-       if (!PageUptodate(page))
-               rc = ecryptfs_do_readpage(file, page, page->index);
+       index = pos >> PAGE_CACHE_SHIFT;
+       page = __grab_cache_page(mapping, index);
+       if (!page) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * If we are writing a full page (with no possibility of a short
+        * write), it will be guaranteed to end up being uptodate at
+        * write_end-time
+        */
+       if (flags & AOP_FLAG_UNINTERRUPTIBLE && len == PAGE_CACHE_SIZE)
+               goto out;
+       if (!PageUptodate(page)) {
+               rc = ecryptfs_do_readpage(file, page, index);
+               if (rc) {
+                       unlock_page(page);
+                       page_cache_release(page);
+               }
+       }
 out:
        return rc;
 }
@@ -412,12 +408,6 @@ out:
        return rc;
 }
 
-static void ecryptfs_release_lower_page(struct page *lower_page)
-{
-       unlock_page(lower_page);
-       page_cache_release(lower_page);
-}
-
 /**
  * ecryptfs_write_inode_size_to_header
  *
@@ -431,23 +421,17 @@ static int ecryptfs_write_inode_size_to_
 {
        int rc = 0;
        struct page *header_page;
+       void *fsdata;
        char *header_virt;
-       const struct address_space_operations *lower_a_ops;
+       struct address_space *lower_mapping = lower_inode->i_mapping;
        u64 file_size;
 
-       header_page = grab_cache_page(lower_inode->i_mapping, 0);
-       if (!header_page) {
-               ecryptfs_printk(KERN_ERR, "grab_cache_page for "
-                               "lower_page_index 0 failed\n");
-               rc = -EINVAL;
-               goto out;
-       }
-       lower_a_ops = lower_inode->i_mapping->a_ops;
-       rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
-       if (rc) {
-               ecryptfs_release_lower_page(header_page);
+       rc = pagecache_write_begin(lower_file, lower_mapping, 0, sizeof(u64),
+                                       AOP_FLAG_UNINTERRUPTIBLE,
+                                       &header_page, &fsdata);
+       if (rc)
                goto out;
-       }
+
        file_size = (u64)i_size_read(inode);
        ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
        file_size = cpu_to_be64(file_size);
@@ -455,13 +439,17 @@ static int ecryptfs_write_inode_size_to_
        memcpy(header_virt, &file_size, sizeof(u64));
        kunmap_atomic(header_virt, KM_USER0);
        flush_dcache_page(header_page);
-       rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8);
-       if (rc < 0)
+
+       rc = pagecache_write_end(lower_file, lower_mapping, 0, sizeof(u64),
+                                       sizeof(u64), header_page, fsdata);
+       if (rc != sizeof(u64)) {
                ecryptfs_printk(KERN_ERR, "Error commiting header page "
                                "write\n");
-       ecryptfs_release_lower_page(header_page);
+               if (rc > 0)
+                       rc = -EINVAL; /* XXX: can we do better? */
+       }
        lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
-       mark_inode_dirty_sync(inode);
+       mark_inode_dirty_sync(inode); /* XXX: lower_inode? */
 out:
        return rc;
 }
@@ -544,31 +532,21 @@ ecryptfs_write_inode_size_to_metadata(st
 int ecryptfs_get_lower_page(struct page **lower_page, struct inode 
*lower_inode,
                            struct file *lower_file,
                            unsigned long lower_page_index, int byte_offset,
-                           int region_bytes)
+                           int region_bytes, void **fsdata)
 {
-       int rc = 0;
+       int rc;
+       struct address_space *lower_mapping = lower_inode->i_mapping;
+       loff_t pos = (lower_page_index << PAGE_CACHE_SHIFT) + byte_offset;
 
-retry:
-       *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index);
-       if (!(*lower_page)) {
-               rc = -EINVAL;
-               ecryptfs_printk(KERN_ERR, "Error attempting to grab "
-                               "lower page with index [0x%.16x]\n",
-                               lower_page_index);
-               goto out;
-       }
-       rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file,
-                                                         (*lower_page),
-                                                         byte_offset,
-                                                         region_bytes);
+       rc = pagecache_write_begin(lower_file, lower_mapping, pos, region_bytes,
+                               AOP_FLAG_UNINTERRUPTIBLE, /* XXX: ok? */
+                               lower_page, fsdata);
        if (rc) {
-               ecryptfs_printk(KERN_ERR, "prepare_write for "
+               ecryptfs_printk(KERN_ERR, "pagecache_write_begin for "
                        "lower_page_index = [0x%.16x] failed; rc = "
                        "[%d]\n", lower_page_index, rc);
-               ecryptfs_release_lower_page(*lower_page);
                (*lower_page) = NULL;
        }
-out:
        return rc;
 }
 
@@ -580,18 +558,21 @@ out:
 int
 ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
                           struct file *lower_file, int byte_offset,
-                          int region_size)
+                          int region_size, void *fsdata)
 {
-       int rc = 0;
+       int rc;
+       struct address_space *lower_mapping = lower_inode->i_mapping;
+       loff_t pos = (lower_page->index << PAGE_CACHE_SHIFT) + byte_offset;
 
-       rc = lower_inode->i_mapping->a_ops->commit_write(
-               lower_file, lower_page, byte_offset, region_size);
-       if (rc < 0) {
+       rc = pagecache_write_end(lower_file, lower_mapping, pos, region_size,
+                                       region_size, lower_page, fsdata);
+       if (rc != region_size) {
                ecryptfs_printk(KERN_ERR,
                                "Error committing write; rc = [%d]\n", rc);
+               if (rc > 0)
+                       rc = -EINVAL;
        } else
                rc = 0;
-       ecryptfs_release_lower_page(lower_page);
        return rc;
 }
 
@@ -606,9 +587,10 @@ int ecryptfs_copy_page_to_lower(struct p
 {
        int rc = 0;
        struct page *lower_page;
+       void *fsdata;
 
        rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file,
-                                    page->index, 0, PAGE_CACHE_SIZE);
+                                    page->index, 0, PAGE_CACHE_SIZE, &fsdata);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Error attempting to get page "
                                "at index [0x%.16x]\n", page->index);
@@ -618,7 +600,7 @@ int ecryptfs_copy_page_to_lower(struct p
        memcpy((char *)page_address(lower_page), page_address(page),
               PAGE_CACHE_SIZE);
        rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file,
-                                       0, PAGE_CACHE_SIZE);
+                                       0, PAGE_CACHE_SIZE, fsdata);
        if (rc)
                ecryptfs_printk(KERN_ERR, "Error attempting to commit page "
                                "at index [0x%.16x]\n", page->index);
@@ -629,31 +611,37 @@ out:
 struct kmem_cache *ecryptfs_xattr_cache;
 
 /**
- * ecryptfs_commit_write
+ * ecryptfs_write_end
  * @file: The eCryptfs file object
- * @page: The eCryptfs page
- * @from: Ignored (we rotate the page IV on each write)
- * @to: Ignored
+ * @mapping: The eCryptfs address_space
+ * @pos: The start of the write
+ * @len: The length passed to write_begin (unused)
+ * @copied: The actual amount copied
+ * @page: The eCryptfs page returned by write_begin
+ * @fsdata: Filesystem private data (unused)
  *
  * This is where we encrypt the data and pass the encrypted data to
  * the lower filesystem.  In OpenPGP-compatible mode, we operate on
  * entire underlying packets.
  */
-static int ecryptfs_commit_write(struct file *file, struct page *page,
-                                unsigned from, unsigned to)
+static int ecryptfs_write_end(struct file *file,
+                                       struct address_space *mapping,
+                               loff_t pos, unsigned len, unsigned copied,
+                               struct page *page, void *fsdata)
 {
        struct ecryptfs_page_crypt_context ctx;
-       loff_t pos;
+       loff_t isize;
        struct inode *inode;
        struct inode *lower_inode;
        struct file *lower_file;
        struct ecryptfs_crypt_stat *crypt_stat;
        int rc;
 
-       inode = page->mapping->host;
+       inode = mapping->host;
+       isize = inode->i_size; /* i_mutex is held */
        lower_inode = ecryptfs_inode_to_lower(inode);
        lower_file = ecryptfs_file_to_lower(file);
-       mutex_lock(&lower_inode->i_mutex);
+       mutex_lock(&lower_inode->i_mutex); /* XXX: put this in write_begin? */
        crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
                                ->crypt_stat;
        if (crypt_stat->flags & ECRYPTFS_NEW_FILE) {
@@ -664,8 +652,8 @@ static int ecryptfs_commit_write(struct 
                ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
        ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
                        "(page w/ index = [0x%.16x], to = [%d])\n", page->index,
-                       to);
-       rc = fill_zeros_to_end_of_page(page, to);
+                       max(isize, pos+copied));
+       rc = fill_zeros_to_end_of_page(page, max(isize, pos+copied));
        if (rc) {
                ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
                                "zeros in page with index = [0x%.16x]\n",
@@ -682,11 +670,10 @@ static int ecryptfs_commit_write(struct 
                goto out;
        }
        inode->i_blocks = lower_inode->i_blocks;
-       pos = (page->index << PAGE_CACHE_SHIFT) + to;
-       if (pos > i_size_read(inode)) {
-               i_size_write(inode, pos);
+       if (pos + copied > isize) {
+               i_size_write(inode, pos + copied);
                ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
-                               "[0x%.16x]\n", i_size_read(inode));
+                               "[0x%.16x]\n", pos + copied);
        }
        rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode,
                                                   inode, file->f_dentry,
@@ -702,6 +689,9 @@ out:
        else
                SetPageUptodate(page);
        mutex_unlock(&lower_inode->i_mutex);
+       unlock_page(page);
+       page_cache_release(page);
+
        return rc;
 }
 
@@ -722,32 +712,31 @@ int write_zeros(struct file *file, pgoff
        int rc = 0;
        struct page *tmp_page;
        char *tmp_page_virt;
-
-       tmp_page = ecryptfs_get1page(file, index);
-       if (IS_ERR(tmp_page)) {
-               ecryptfs_printk(KERN_ERR, "Error getting page at index "
-                               "[0x%.16x]\n", index);
-               rc = PTR_ERR(tmp_page);
-               goto out;
-       }
-       rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
+       void *fsdata;
+       struct address_space *mapping = file->f_path.dentry->d_inode->i_mapping;
+       loff_t pos = (index << PAGE_CACHE_SHIFT) + start;
+
+       rc = pagecache_write_begin(file, mapping, pos, num_zeros,
+                                       AOP_FLAG_UNINTERRUPTIBLE,
+                                       &tmp_page, &fsdata);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
                                "to remainder of page at index [0x%.16x]\n",
                                index);
-               page_cache_release(tmp_page);
                goto out;
        }
        tmp_page_virt = kmap_atomic(tmp_page, KM_USER0);
        memset(((char *)tmp_page_virt + start), 0, num_zeros);
        kunmap_atomic(tmp_page_virt, KM_USER0);
        flush_dcache_page(tmp_page);
-       rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros);
-       if (rc < 0) {
+       rc = pagecache_write_end(file, mapping, pos, num_zeros, num_zeros,
+                                       tmp_page, fsdata);
+       if (rc != num_zeros) {
                ecryptfs_printk(KERN_ERR, "Error attempting to write zero's "
                                "to remainder of page at index [0x%.16x]\n",
                                index);
-               page_cache_release(tmp_page);
+               if (rc > 0)
+                       rc = -EINVAL;
                goto out;
        }
        rc = 0;
@@ -795,8 +784,8 @@ static void ecryptfs_sync_page(struct pa
 struct address_space_operations ecryptfs_aops = {
        .writepage = ecryptfs_writepage,
        .readpage = ecryptfs_readpage,
-       .prepare_write = ecryptfs_prepare_write,
-       .commit_write = ecryptfs_commit_write,
+       .write_begin = ecryptfs_write_begin,
+       .write_end = ecryptfs_write_end,
        .bmap = ecryptfs_bmap,
        .sync_page = ecryptfs_sync_page,
 };
Index: linux-2.6/fs/ecryptfs/crypto.c
===================================================================
--- linux-2.6.orig/fs/ecryptfs/crypto.c
+++ linux-2.6/fs/ecryptfs/crypto.c
@@ -375,7 +375,8 @@ ecryptfs_extent_to_lwr_pg_idx_and_offset
 static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx,
                                   struct page *lower_page,
                                   struct inode *lower_inode,
-                                  int byte_offset_in_page, int bytes_to_write)
+                                  int byte_offset_in_page, int bytes_to_write,
+                                  void *fsdata)
 {
        int rc = 0;
 
@@ -383,7 +384,7 @@ static int ecryptfs_write_out_page(struc
                rc = ecryptfs_commit_lower_page(lower_page, lower_inode,
                                                ctx->param.lower_file,
                                                byte_offset_in_page,
-                                               bytes_to_write);
+                                               bytes_to_write, fsdata);
                if (rc) {
                        ecryptfs_printk(KERN_ERR, "Error calling lower "
                                        "commit; rc = [%d]\n", rc);
@@ -407,7 +408,7 @@ static int ecryptfs_read_in_page(struct 
                                 struct page **lower_page,
                                 struct inode *lower_inode,
                                 unsigned long lower_page_idx,
-                                int byte_offset_in_page)
+                                int byte_offset_in_page, void **fsdata)
 {
        int rc = 0;
 
@@ -419,13 +420,12 @@ static int ecryptfs_read_in_page(struct 
                                             lower_page_idx,
                                             byte_offset_in_page,
                                             (PAGE_CACHE_SIZE
-                                             - byte_offset_in_page));
+                                             - byte_offset_in_page), fsdata);
                if (rc) {
                        ecryptfs_printk(
-                               KERN_ERR, "Error attempting to grab, map, "
-                               "and prepare_write lower page with index "
+                               KERN_ERR, "Error in ecryptfs_get_lower_page "
+                               "lower page with index "
                                "[0x%.16x]; rc = [%d]\n", lower_page_idx, rc);
-                       goto out;
                }
        } else {
                *lower_page = grab_cache_page(lower_inode->i_mapping,
@@ -436,10 +436,9 @@ static int ecryptfs_read_in_page(struct 
                                KERN_ERR, "Error attempting to grab and map "
                                "lower page with index [0x%.16x]; rc = [%d]\n",
                                lower_page_idx, rc);
-                       goto out;
                }
        }
-out:
+
        return rc;
 }
 
@@ -475,6 +474,8 @@ int ecryptfs_encrypt_page(struct ecryptf
        int lower_byte_offset = 0;
        int orig_byte_offset = 0;
        int num_extents_per_page;
+       void *fsdata;
+
 #define ECRYPTFS_PAGE_STATE_UNREAD    0
 #define ECRYPTFS_PAGE_STATE_READ      1
 #define ECRYPTFS_PAGE_STATE_MODIFIED  2
@@ -503,10 +504,9 @@ int ecryptfs_encrypt_page(struct ecryptf
                if (prior_lower_page_idx != lower_page_idx
                    && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) {
                        rc = ecryptfs_write_out_page(ctx, lower_page,
-                                                    lower_inode,
-                                                    orig_byte_offset,
-                                                    (PAGE_CACHE_SIZE
-                                                     - orig_byte_offset));
+                                       lower_inode, orig_byte_offset,
+                                       (PAGE_CACHE_SIZE - orig_byte_offset),
+                                       fsdata);
                        if (rc) {
                                ecryptfs_printk(KERN_ERR, "Error attempting "
                                                "to write out page; rc = [%d]"
@@ -519,7 +519,7 @@ int ecryptfs_encrypt_page(struct ecryptf
                    || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) {
                        rc = ecryptfs_read_in_page(ctx, &lower_page,
                                                   lower_inode, lower_page_idx,
-                                                  lower_byte_offset);
+                                                  lower_byte_offset, &fsdata);
                        if (rc) {
                                ecryptfs_printk(KERN_ERR, "Error attempting "
                                                "to read in lower page with "
@@ -571,8 +571,8 @@ int ecryptfs_encrypt_page(struct ecryptf
        }
        BUG_ON(orig_byte_offset != 0);
        rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0,
-                                    (lower_byte_offset
-                                     + crypt_stat->extent_size));
+                               (lower_byte_offset + crypt_stat->extent_size),
+                               fsdata);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Error attempting to write out "
                                "page; rc = [%d]\n", rc);
Index: linux-2.6/fs/ecryptfs/ecryptfs_kernel.h
===================================================================
--- linux-2.6.orig/fs/ecryptfs/ecryptfs_kernel.h
+++ linux-2.6/fs/ecryptfs/ecryptfs_kernel.h
@@ -503,11 +503,11 @@ int ecryptfs_write_inode_size_to_metadat
 int ecryptfs_get_lower_page(struct page **lower_page, struct inode 
*lower_inode,
                            struct file *lower_file,
                            unsigned long lower_page_index, int byte_offset,
-                           int region_bytes);
+                           int region_bytes, void **fsdata);
 int
 ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
                           struct file *lower_file, int byte_offset,
-                          int region_size);
+                          int region_size, void *fsdata);
 int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
                                struct file *lower_file);
 int ecryptfs_do_readpage(struct file *file, struct page *page,

-- 

-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to