Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-25 Thread Michael Halcrow
On Fri, Sep 21, 2007 at 03:05:40PM -0700, Andrew Morton wrote:
> btw, I'm not really a great admirer of the whole patchset: it does
> some pretty nasty-looking things: allocating dynamic memory,
> grabbing the underlying pageframes with virt_to_page(), passing them
> back into kernel APIs which are supposed to be called from
> userspace, etc.  It's all rather ugly and abusive-looking.

Functions higher up the execution stack should be the ones mucking
with the Uptodate flag. The patch below addresses some of these
issues. I also whipped up a post-patch partial call graph to help
illustrate what is going on with the page mapping and Uptodate status
in the various eCryptfs read/write paths:

http://ecryptfs.sourceforge.net/ecryptfs-pageuptodate-call-graph.png

---

The functions that eventually call down to ecryptfs_read_lower(),
ecryptfs_decrypt_page(), and ecryptfs_copy_up_encrypted_with_header()
should have the responsibility of managing the page Uptodate
status. This patch gets rid of some of the ugliness that resulted from
trying to push some of the page flag setting too far down the stack.

Signed-off-by: Michael Halcrow <[EMAIL PROTECTED]>
---
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index b3795f6..bbec711 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -605,14 +605,14 @@ int ecryptfs_decrypt_page(struct page *page)
printk(KERN_ERR "%s: Error attempting to copy "
   "page at index [%ld]\n", __FUNCTION__,
   page->index);
-   goto out_clear_uptodate;
+   goto out;
}
enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);
if (!enc_extent_virt) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Error allocating memory for "
"encrypted extent\n");
-   goto out_clear_uptodate;
+   goto out;
}
enc_extent_page = virt_to_page(enc_extent_virt);
for (extent_offset = 0;
@@ -631,21 +631,17 @@ int ecryptfs_decrypt_page(struct page *page)
ecryptfs_printk(KERN_ERR, "Error attempting "
"to read lower page; rc = [%d]"
"\n", rc);
-   goto out_clear_uptodate;
+   goto out;
}
rc = ecryptfs_decrypt_extent(page, crypt_stat, enc_extent_page,
 extent_offset);
if (rc) {
printk(KERN_ERR "%s: Error encrypting extent; "
   "rc = [%d]\n", __FUNCTION__, rc);
-   goto out_clear_uptodate;
+   goto out;
}
extent_offset++;
}
-   SetPageUptodate(page);
-   goto out;
-out_clear_uptodate:
-   ClearPageUptodate(page);
 out:
kfree(enc_extent_virt);
return rc;
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index bb92b74..ce7a5d4 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -648,6 +648,6 @@ int ecryptfs_read_lower_page_segment(struct page 
*page_for_ecryptfs,
 struct inode *ecryptfs_inode);
 int ecryptfs_read(char *data, loff_t offset, size_t size,
  struct file *ecryptfs_file);
-struct page *ecryptfs_get1page(struct file *file, loff_t index);
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 4eb09c1..16a7a55 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -37,23 +37,27 @@
 struct kmem_cache *ecryptfs_lower_page_cache;
 
 /**
- * ecryptfs_get1page
+ * ecryptfs_get_locked_page
  *
  * Get one page from cache or lower f/s, return error otherwise.
  *
- * Returns unlocked and up-to-date page (if ok), with increased
+ * Returns locked and up-to-date page (if ok), with increased
  * refcnt.
  */
-struct page *ecryptfs_get1page(struct file *file, loff_t index)
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index)
 {
struct dentry *dentry;
struct inode *inode;
struct address_space *mapping;
+   struct page *page;
 
dentry = file->f_path.dentry;
inode = dentry->d_inode;
mapping = inode->i_mapping;
-   return read_mapping_page(mapping, index, (void *)file);
+   page = read_mapping_page(mapping, index, (void *)file);
+   if (!IS_ERR(page))
+   lock_page(page);
+   return page;
 }
 
 /**
@@ -146,12 +150,10 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
kunmap_atomic(page_virt, KM_USER0);
flush_dcache_page(page);
if (rc) {
-   ClearPageUptodate(page);

Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-25 Thread Michael Halcrow
On Fri, Sep 21, 2007 at 03:05:40PM -0700, Andrew Morton wrote:
 btw, I'm not really a great admirer of the whole patchset: it does
 some pretty nasty-looking things: allocating dynamic memory,
 grabbing the underlying pageframes with virt_to_page(), passing them
 back into kernel APIs which are supposed to be called from
 userspace, etc.  It's all rather ugly and abusive-looking.

Functions higher up the execution stack should be the ones mucking
with the Uptodate flag. The patch below addresses some of these
issues. I also whipped up a post-patch partial call graph to help
illustrate what is going on with the page mapping and Uptodate status
in the various eCryptfs read/write paths:

http://ecryptfs.sourceforge.net/ecryptfs-pageuptodate-call-graph.png

---

The functions that eventually call down to ecryptfs_read_lower(),
ecryptfs_decrypt_page(), and ecryptfs_copy_up_encrypted_with_header()
should have the responsibility of managing the page Uptodate
status. This patch gets rid of some of the ugliness that resulted from
trying to push some of the page flag setting too far down the stack.

Signed-off-by: Michael Halcrow [EMAIL PROTECTED]
---
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index b3795f6..bbec711 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -605,14 +605,14 @@ int ecryptfs_decrypt_page(struct page *page)
printk(KERN_ERR %s: Error attempting to copy 
   page at index [%ld]\n, __FUNCTION__,
   page-index);
-   goto out_clear_uptodate;
+   goto out;
}
enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER);
if (!enc_extent_virt) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, Error allocating memory for 
encrypted extent\n);
-   goto out_clear_uptodate;
+   goto out;
}
enc_extent_page = virt_to_page(enc_extent_virt);
for (extent_offset = 0;
@@ -631,21 +631,17 @@ int ecryptfs_decrypt_page(struct page *page)
ecryptfs_printk(KERN_ERR, Error attempting 
to read lower page; rc = [%d]
\n, rc);
-   goto out_clear_uptodate;
+   goto out;
}
rc = ecryptfs_decrypt_extent(page, crypt_stat, enc_extent_page,
 extent_offset);
if (rc) {
printk(KERN_ERR %s: Error encrypting extent; 
   rc = [%d]\n, __FUNCTION__, rc);
-   goto out_clear_uptodate;
+   goto out;
}
extent_offset++;
}
-   SetPageUptodate(page);
-   goto out;
-out_clear_uptodate:
-   ClearPageUptodate(page);
 out:
kfree(enc_extent_virt);
return rc;
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index bb92b74..ce7a5d4 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -648,6 +648,6 @@ int ecryptfs_read_lower_page_segment(struct page 
*page_for_ecryptfs,
 struct inode *ecryptfs_inode);
 int ecryptfs_read(char *data, loff_t offset, size_t size,
  struct file *ecryptfs_file);
-struct page *ecryptfs_get1page(struct file *file, loff_t index);
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 4eb09c1..16a7a55 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -37,23 +37,27 @@
 struct kmem_cache *ecryptfs_lower_page_cache;
 
 /**
- * ecryptfs_get1page
+ * ecryptfs_get_locked_page
  *
  * Get one page from cache or lower f/s, return error otherwise.
  *
- * Returns unlocked and up-to-date page (if ok), with increased
+ * Returns locked and up-to-date page (if ok), with increased
  * refcnt.
  */
-struct page *ecryptfs_get1page(struct file *file, loff_t index)
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index)
 {
struct dentry *dentry;
struct inode *inode;
struct address_space *mapping;
+   struct page *page;
 
dentry = file-f_path.dentry;
inode = dentry-d_inode;
mapping = inode-i_mapping;
-   return read_mapping_page(mapping, index, (void *)file);
+   page = read_mapping_page(mapping, index, (void *)file);
+   if (!IS_ERR(page))
+   lock_page(page);
+   return page;
 }
 
 /**
@@ -146,12 +150,10 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
kunmap_atomic(page_virt, KM_USER0);
flush_dcache_page(page);
if (rc) {
-   ClearPageUptodate(page);
 

Re: [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-24 Thread Michael Halcrow
On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
> > +   offset = (page_for_lower->index << PAGE_CACHE_SHIFT) + offset_in_page;
> 
> bug.  You need to cast page.index to loff_t before shifting.
> 
> I'd fix it on the spot, but this would be a good time to review the
> whole patchset and perhaps the whole fs for this easy-to-do,
> hard-to-find bug.

Update data types and add casts in order to avoid potential overflow
issues.

Signed-off-by: Michael Halcrow <[EMAIL PROTECTED]>
---
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 5d27cf9..4bf1a95 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -149,7 +149,7 @@ out:
  * ecryptfs_derive_iv
  * @iv: destination for the derived iv vale
  * @crypt_stat: Pointer to crypt_stat struct for the current inode
- * @offset: Offset of the page whose's iv we are to derive
+ * @offset: Offset of the extent whose IV we are to derive
  *
  * Generate the initialization vector from the given root IV and page
  * offset.
@@ -157,7 +157,7 @@ out:
  * Returns zero on success; non-zero on error.
  */
 static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
- pgoff_t offset)
+ loff_t offset)
 {
int rc = 0;
char dst[MD5_DIGEST_SIZE];
@@ -173,7 +173,7 @@ static int ecryptfs_derive_iv(char *iv, struct 
ecryptfs_crypt_stat *crypt_stat,
 * hashing business. -Halcrow */
memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes);
memset((src + crypt_stat->iv_bytes), 0, 16);
-   snprintf((src + crypt_stat->iv_bytes), 16, "%ld", offset);
+   snprintf((src + crypt_stat->iv_bytes), 16, "%lld", offset);
if (unlikely(ecryptfs_verbosity > 0)) {
ecryptfs_printk(KERN_DEBUG, "source:\n");
ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16));
@@ -384,11 +384,11 @@ static int ecryptfs_encrypt_extent(struct page 
*enc_extent_page,
   struct page *page,
   unsigned long extent_offset)
 {
-   unsigned long extent_base;
+   loff_t extent_base;
char extent_iv[ECRYPTFS_MAX_IV_BYTES];
int rc;
 
-   extent_base = (page->index
+   extent_base = (((loff_t)page->index)
   * (PAGE_CACHE_SIZE / crypt_stat->extent_size));
rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
(extent_base + extent_offset));
@@ -492,8 +492,9 @@ int ecryptfs_encrypt_page(struct page *page)
goto out;
}
ecryptfs_lower_offset_for_extent(
-   , ((page->index * (PAGE_CACHE_SIZE
- / crypt_stat->extent_size))
+   , loff_t)page->index)
+  * (PAGE_CACHE_SIZE
+ / crypt_stat->extent_size))
  + extent_offset), crypt_stat);
rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt,
  offset, crypt_stat->extent_size);
@@ -515,11 +516,11 @@ static int ecryptfs_decrypt_extent(struct page *page,
   struct page *enc_extent_page,
   unsigned long extent_offset)
 {
-   unsigned long extent_base;
+   loff_t extent_base;
char extent_iv[ECRYPTFS_MAX_IV_BYTES];
int rc;
 
-   extent_base = (page->index
+   extent_base = (((loff_t)page->index)
   * (PAGE_CACHE_SIZE / crypt_stat->extent_size));
rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
(extent_base + extent_offset));
@@ -1320,7 +1321,7 @@ ecryptfs_write_metadata_to_contents(struct 
ecryptfs_crypt_stat *crypt_stat,
while (current_header_page < header_pages) {
loff_t offset;
 
-   offset = (current_header_page << PAGE_CACHE_SHIFT);
+   offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT);
if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
   page_virt, offset,
   PAGE_CACHE_SIZE))) {
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index c6a8a33..4eb09c1 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -127,7 +127,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
int rc = 0;
 
while (extent_num_in_page < num_extents_per_page) {
-   loff_t view_extent_num = ((page->index * num_extents_per_page)
+   loff_t view_extent_num = loff_t)page->index)
+  * num_extents_per_page)
  + extent_num_in_page);
 
if (view_extent_num < crypt_stat->num_header_extents_at_front) {
@@ -418,7 +419,7 @@ 

Re: [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-24 Thread Michael Halcrow
On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
  +   offset = (page_for_lower-index  PAGE_CACHE_SHIFT) + offset_in_page;
 
 bug.  You need to cast page.index to loff_t before shifting.
 
 I'd fix it on the spot, but this would be a good time to review the
 whole patchset and perhaps the whole fs for this easy-to-do,
 hard-to-find bug.

Update data types and add casts in order to avoid potential overflow
issues.

Signed-off-by: Michael Halcrow [EMAIL PROTECTED]
---
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 5d27cf9..4bf1a95 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -149,7 +149,7 @@ out:
  * ecryptfs_derive_iv
  * @iv: destination for the derived iv vale
  * @crypt_stat: Pointer to crypt_stat struct for the current inode
- * @offset: Offset of the page whose's iv we are to derive
+ * @offset: Offset of the extent whose IV we are to derive
  *
  * Generate the initialization vector from the given root IV and page
  * offset.
@@ -157,7 +157,7 @@ out:
  * Returns zero on success; non-zero on error.
  */
 static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
- pgoff_t offset)
+ loff_t offset)
 {
int rc = 0;
char dst[MD5_DIGEST_SIZE];
@@ -173,7 +173,7 @@ static int ecryptfs_derive_iv(char *iv, struct 
ecryptfs_crypt_stat *crypt_stat,
 * hashing business. -Halcrow */
memcpy(src, crypt_stat-root_iv, crypt_stat-iv_bytes);
memset((src + crypt_stat-iv_bytes), 0, 16);
-   snprintf((src + crypt_stat-iv_bytes), 16, %ld, offset);
+   snprintf((src + crypt_stat-iv_bytes), 16, %lld, offset);
if (unlikely(ecryptfs_verbosity  0)) {
ecryptfs_printk(KERN_DEBUG, source:\n);
ecryptfs_dump_hex(src, (crypt_stat-iv_bytes + 16));
@@ -384,11 +384,11 @@ static int ecryptfs_encrypt_extent(struct page 
*enc_extent_page,
   struct page *page,
   unsigned long extent_offset)
 {
-   unsigned long extent_base;
+   loff_t extent_base;
char extent_iv[ECRYPTFS_MAX_IV_BYTES];
int rc;
 
-   extent_base = (page-index
+   extent_base = (((loff_t)page-index)
   * (PAGE_CACHE_SIZE / crypt_stat-extent_size));
rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
(extent_base + extent_offset));
@@ -492,8 +492,9 @@ int ecryptfs_encrypt_page(struct page *page)
goto out;
}
ecryptfs_lower_offset_for_extent(
-   offset, ((page-index * (PAGE_CACHE_SIZE
- / crypt_stat-extent_size))
+   offset, loff_t)page-index)
+  * (PAGE_CACHE_SIZE
+ / crypt_stat-extent_size))
  + extent_offset), crypt_stat);
rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt,
  offset, crypt_stat-extent_size);
@@ -515,11 +516,11 @@ static int ecryptfs_decrypt_extent(struct page *page,
   struct page *enc_extent_page,
   unsigned long extent_offset)
 {
-   unsigned long extent_base;
+   loff_t extent_base;
char extent_iv[ECRYPTFS_MAX_IV_BYTES];
int rc;
 
-   extent_base = (page-index
+   extent_base = (((loff_t)page-index)
   * (PAGE_CACHE_SIZE / crypt_stat-extent_size));
rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
(extent_base + extent_offset));
@@ -1320,7 +1321,7 @@ ecryptfs_write_metadata_to_contents(struct 
ecryptfs_crypt_stat *crypt_stat,
while (current_header_page  header_pages) {
loff_t offset;
 
-   offset = (current_header_page  PAGE_CACHE_SHIFT);
+   offset = (((loff_t)current_header_page)  PAGE_CACHE_SHIFT);
if ((rc = ecryptfs_write_lower(ecryptfs_dentry-d_inode,
   page_virt, offset,
   PAGE_CACHE_SIZE))) {
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index c6a8a33..4eb09c1 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -127,7 +127,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
int rc = 0;
 
while (extent_num_in_page  num_extents_per_page) {
-   loff_t view_extent_num = ((page-index * num_extents_per_page)
+   loff_t view_extent_num = loff_t)page-index)
+  * num_extents_per_page)
  + extent_num_in_page);
 
if (view_extent_num  crypt_stat-num_header_extents_at_front) {
@@ -418,7 +419,7 @@ static int 

Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-21 Thread Andrew Morton
On Fri, 21 Sep 2007 16:51:25 -0500
Michael Halcrow <[EMAIL PROTECTED]> wrote:

> On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
> > > + virt = kmap(page_for_lower);
> > > + rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
> > > + kunmap(page_for_lower);
> > > + return rc;
> > > +}
> > 
> > argh, kmap.  http://lkml.org/lkml/2007/9/15/55
> 
> Here is a patch that moves to kmap_atomic(), adding an intermediate
> copy. Although I would really like to find a way to avoid having to do
> this extra copy.

We might as well stick with kmap.  I was just having a whine - I don't know
what to do about this really, apart from perhaps giving in to reality and
making kmap work better.


btw, I'm not really a great admirer of the whole patchset: it does some
pretty nasty-looking things: allocating dynamic memory, grabbing the
underlying pageframes with virt_to_page(), passing them back into kernel
APIs which are supposed to be called from userspace, etc.  It's all rather
ugly and abusive-looking.

But given that you're trying to do things which the kernel just isn't set
up to do, it isn't immediately obvious what can be done to fix it.

Perhaps there are problems whcih I didn't have time to spot, and perhaps
there are things which could be done to improve it.  But I don't have time
to sit down and absorb it all to a sufficient level of detail to be able to
suggest anything, and nobody else seems to be interested in reading the
patches so whoop, in it all goes.

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


Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-21 Thread Michael Halcrow
On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
> > +   virt = kmap(page_for_lower);
> > +   rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
> > +   kunmap(page_for_lower);
> > +   return rc;
> > +}
> 
> argh, kmap.  http://lkml.org/lkml/2007/9/15/55

Here is a patch that moves to kmap_atomic(), adding an intermediate
copy. Although I would really like to find a way to avoid having to do
this extra copy.

---

Replace kmap() with kmap_atomic() for read_write.c routines

kmap() can lead to deadlock when multiple tasks attempt to take more
than one simultaneously:

http://lkml.org/lkml/2007/9/15/55

In order to avoid this possibility, eCryptfs must allocate an
intermediate block of memory to use with vfs_read() and vfs_write(),
copying the data through this memory region, since kmap_atomic()
cannot be held during calls which may block.

Signed-off-by: Michael Halcrow <[EMAIL PROTECTED]>
---
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index bb92b74..ce7a5d4 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -648,6 +648,6 @@ int ecryptfs_read_lower_page_segment(struct page 
*page_for_ecryptfs,
 struct inode *ecryptfs_inode);
 int ecryptfs_read(char *data, loff_t offset, size_t size,
  struct file *ecryptfs_file);
-struct page *ecryptfs_get1page(struct file *file, loff_t index);
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index c6a8a33..6abf805 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -37,23 +37,30 @@
 struct kmem_cache *ecryptfs_lower_page_cache;
 
 /**
- * ecryptfs_get1page
+ * ecryptfs_get_locked_page
  *
  * Get one page from cache or lower f/s, return error otherwise.
  *
- * Returns unlocked and up-to-date page (if ok), with increased
+ * Returns a locked and up-to-date page (if ok), with increased
  * refcnt.
  */
-struct page *ecryptfs_get1page(struct file *file, loff_t index)
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index)
 {
struct dentry *dentry;
struct inode *inode;
struct address_space *mapping;
+   struct page *page;
 
dentry = file->f_path.dentry;
inode = dentry->d_inode;
mapping = inode->i_mapping;
-   return read_mapping_page(mapping, index, (void *)file);
+   page = read_mapping_page(mapping, index, (void *)file);
+   if (!IS_ERR(page))
+   lock_page(page);
+   else
+   printk(KERN_ERR "%s: Error from read_mapping_page()\n",
+  __FUNCTION__);
+   return page;
 }
 
 /**
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index ccd2599..6732a4c 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -83,14 +83,24 @@ int ecryptfs_write_lower_page_segment(struct inode 
*ecryptfs_inode,
  struct page *page_for_lower,
  size_t offset_in_page, size_t size)
 {
-   char *virt;
+   char *page_for_lower_virt;
+   char *tmp_virt;
loff_t offset;
int rc;
 
-   offset = (page_for_lower->index << PAGE_CACHE_SHIFT) + offset_in_page;
-   virt = kmap(page_for_lower);
-   rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
-   kunmap(page_for_lower);
+   tmp_virt = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
+   if (!tmp_virt) {
+   rc = -ENOMEM;
+   goto out;
+   }
+   offset = loff_t)page_for_lower->index) << PAGE_CACHE_SHIFT)
+ + offset_in_page);
+   page_for_lower_virt = kmap_atomic(page_for_lower, KM_USER0);
+   memcpy(tmp_virt, page_for_lower_virt, PAGE_CACHE_SIZE);
+   kunmap_atomic(page_for_lower_virt, KM_USER0);
+   rc = ecryptfs_write_lower(ecryptfs_inode, tmp_virt, offset, size);
+   kfree(tmp_virt);
+out:
return rc;
 }
 
@@ -140,8 +150,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, 
loff_t offset,
if (num_bytes > total_remaining_zeros)
num_bytes = total_remaining_zeros;
}
-   ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
- ecryptfs_page_idx);
+   ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,
+ecryptfs_page_idx);
if (IS_ERR(ecryptfs_page)) {
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
@@ -159,6 +169,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, 
loff_t offset,
printk(KERN_ERR "%s: Error decrypting "
   "page; rc = [%d]\n",
 

Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-21 Thread Michael Halcrow
On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
  +   virt = kmap(page_for_lower);
  +   rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
  +   kunmap(page_for_lower);
  +   return rc;
  +}
 
 argh, kmap.  http://lkml.org/lkml/2007/9/15/55

Here is a patch that moves to kmap_atomic(), adding an intermediate
copy. Although I would really like to find a way to avoid having to do
this extra copy.

---

Replace kmap() with kmap_atomic() for read_write.c routines

kmap() can lead to deadlock when multiple tasks attempt to take more
than one simultaneously:

http://lkml.org/lkml/2007/9/15/55

In order to avoid this possibility, eCryptfs must allocate an
intermediate block of memory to use with vfs_read() and vfs_write(),
copying the data through this memory region, since kmap_atomic()
cannot be held during calls which may block.

Signed-off-by: Michael Halcrow [EMAIL PROTECTED]
---
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index bb92b74..ce7a5d4 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -648,6 +648,6 @@ int ecryptfs_read_lower_page_segment(struct page 
*page_for_ecryptfs,
 struct inode *ecryptfs_inode);
 int ecryptfs_read(char *data, loff_t offset, size_t size,
  struct file *ecryptfs_file);
-struct page *ecryptfs_get1page(struct file *file, loff_t index);
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index c6a8a33..6abf805 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -37,23 +37,30 @@
 struct kmem_cache *ecryptfs_lower_page_cache;
 
 /**
- * ecryptfs_get1page
+ * ecryptfs_get_locked_page
  *
  * Get one page from cache or lower f/s, return error otherwise.
  *
- * Returns unlocked and up-to-date page (if ok), with increased
+ * Returns a locked and up-to-date page (if ok), with increased
  * refcnt.
  */
-struct page *ecryptfs_get1page(struct file *file, loff_t index)
+struct page *ecryptfs_get_locked_page(struct file *file, loff_t index)
 {
struct dentry *dentry;
struct inode *inode;
struct address_space *mapping;
+   struct page *page;
 
dentry = file-f_path.dentry;
inode = dentry-d_inode;
mapping = inode-i_mapping;
-   return read_mapping_page(mapping, index, (void *)file);
+   page = read_mapping_page(mapping, index, (void *)file);
+   if (!IS_ERR(page))
+   lock_page(page);
+   else
+   printk(KERN_ERR %s: Error from read_mapping_page()\n,
+  __FUNCTION__);
+   return page;
 }
 
 /**
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index ccd2599..6732a4c 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -83,14 +83,24 @@ int ecryptfs_write_lower_page_segment(struct inode 
*ecryptfs_inode,
  struct page *page_for_lower,
  size_t offset_in_page, size_t size)
 {
-   char *virt;
+   char *page_for_lower_virt;
+   char *tmp_virt;
loff_t offset;
int rc;
 
-   offset = (page_for_lower-index  PAGE_CACHE_SHIFT) + offset_in_page;
-   virt = kmap(page_for_lower);
-   rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
-   kunmap(page_for_lower);
+   tmp_virt = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
+   if (!tmp_virt) {
+   rc = -ENOMEM;
+   goto out;
+   }
+   offset = loff_t)page_for_lower-index)  PAGE_CACHE_SHIFT)
+ + offset_in_page);
+   page_for_lower_virt = kmap_atomic(page_for_lower, KM_USER0);
+   memcpy(tmp_virt, page_for_lower_virt, PAGE_CACHE_SIZE);
+   kunmap_atomic(page_for_lower_virt, KM_USER0);
+   rc = ecryptfs_write_lower(ecryptfs_inode, tmp_virt, offset, size);
+   kfree(tmp_virt);
+out:
return rc;
 }
 
@@ -140,8 +150,8 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, 
loff_t offset,
if (num_bytes  total_remaining_zeros)
num_bytes = total_remaining_zeros;
}
-   ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
- ecryptfs_page_idx);
+   ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,
+ecryptfs_page_idx);
if (IS_ERR(ecryptfs_page)) {
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR %s: Error getting page at 
@@ -159,6 +169,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, 
loff_t offset,
printk(KERN_ERR %s: Error decrypting 
   page; rc = [%d]\n,
   __FUNCTION__, 

Re: [Ecryptfs-devel] [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-21 Thread Andrew Morton
On Fri, 21 Sep 2007 16:51:25 -0500
Michael Halcrow [EMAIL PROTECTED] wrote:

 On Wed, Sep 19, 2007 at 10:38:50PM -0700, Andrew Morton wrote:
   + virt = kmap(page_for_lower);
   + rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
   + kunmap(page_for_lower);
   + return rc;
   +}
  
  argh, kmap.  http://lkml.org/lkml/2007/9/15/55
 
 Here is a patch that moves to kmap_atomic(), adding an intermediate
 copy. Although I would really like to find a way to avoid having to do
 this extra copy.

We might as well stick with kmap.  I was just having a whine - I don't know
what to do about this really, apart from perhaps giving in to reality and
making kmap work better.


btw, I'm not really a great admirer of the whole patchset: it does some
pretty nasty-looking things: allocating dynamic memory, grabbing the
underlying pageframes with virt_to_page(), passing them back into kernel
APIs which are supposed to be called from userspace, etc.  It's all rather
ugly and abusive-looking.

But given that you're trying to do things which the kernel just isn't set
up to do, it isn't immediately obvious what can be done to fix it.

Perhaps there are problems whcih I didn't have time to spot, and perhaps
there are things which could be done to improve it.  But I don't have time
to sit down and absorb it all to a sufficient level of detail to be able to
suggest anything, and nobody else seems to be interested in reading the
patches so whoop, in it all goes.

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


Re: [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-19 Thread Andrew Morton
On Mon, 17 Sep 2007 16:46:32 -0500 Michael Halcrow <[EMAIL PROTECTED]> wrote:

> Add a set of functions through which all I/O to lower files is
> consolidated. This patch adds a new inode_info reference to a
> persistent lower file for each eCryptfs inode; another patch later in
> this series will set that up. This persistent lower file is what the
> read_write.c functions use to call vfs_read() and vfs_write() on the
> lower filesystem, so even when reads and writes come in through
> aops->readpage and aops->writepage, we can satisfy them without
> resorting to direct access to the lower inode's address space.
> Several function declarations are going to be changing with this
> patchset. For now, in order to keep from breaking the build, I am
> putting dummy parameters in for those functions.
> 
> ..
>
> +/**
> + * ecryptfs_write_lower_page_segment
> + * @ecryptfs_inode: The eCryptfs inode
> + * @page_for_lower: The page containing the data to be written to the
> + *  lower file
> + * @offset_in_page: The offset in the @page_for_lower from which to
> + *  start writing the data
> + * @size: The amount of data from @page_for_lower to write to the
> + *lower file
> + *
> + * Determines the byte offset in the file for the given page and
> + * offset within the page, maps the page, and makes the call to write
> + * the contents of @page_for_lower to the lower inode.
> + *
> + * Returns zero on success; non-zero otherwise
> + */
> +int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
> +   struct page *page_for_lower,
> +   size_t offset_in_page, size_t size)
> +{
> + char *virt;
> + loff_t offset;
> + int rc;
> +
> + offset = (page_for_lower->index << PAGE_CACHE_SHIFT) + offset_in_page;

bug.  You need to cast page.index to loff_t before shifting.

I'd fix it on the spot, but this would be a good time to review the whole
patchset and perhaps the whole fs for this easy-to-do, hard-to-find bug.

> + virt = kmap(page_for_lower);
> + rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
> + kunmap(page_for_lower);
> + return rc;
> +}

argh, kmap.  http://lkml.org/lkml/2007/9/15/55

> +/**
> + * ecryptfs_write
> + * @ecryptfs_file: The eCryptfs file into which to write
> + * @data: Virtual address where data to write is located
> + * @offset: Offset in the eCryptfs file at which to begin writing the
> + *  data from @data
> + * @size: The number of bytes to write from @data
> + *
> + * Write an arbitrary amount of data to an arbitrary location in the
> + * eCryptfs inode page cache. This is done on a page-by-page, and then
> + * by an extent-by-extent, basis; individual extents are encrypted and
> + * written to the lower page cache (via VFS writes). This function
> + * takes care of all the address translation to locations in the lower
> + * filesystem; it also handles truncate events, writing out zeros
> + * where necessary.
> + *
> + * Returns zero on success; non-zero otherwise
> + */
> +int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
> +size_t size)
> +{
> + struct page *ecryptfs_page;
> + char *ecryptfs_page_virt;
> + u64 ecryptfs_file_size = i_size_read(ecryptfs_file->f_dentry->d_inode);

Not loff_t?

> + loff_t data_offset = 0;
> + loff_t pos;
> + int rc = 0;
> +
> + if (offset > ecryptfs_file_size)
> + pos = ecryptfs_file_size;

loff_t = u64.  The typing seems a bit confused?

> + else
> + pos = offset;
> + while (pos < (offset + size)) {
> + pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);
> + size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK);
> + size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);
> + size_t total_remaining_bytes = ((offset + size) - pos);
> +
> + if (num_bytes > total_remaining_bytes)
> + num_bytes = total_remaining_bytes;
> + if (pos < offset) {
> + size_t total_remaining_zeros = (offset - pos);
> +
> + if (num_bytes > total_remaining_zeros)
> + num_bytes = total_remaining_zeros;
> + }
> + ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
> +   ecryptfs_page_idx);
> + if (IS_ERR(ecryptfs_page)) {
> + rc = PTR_ERR(ecryptfs_page);
> + printk(KERN_ERR "%s: Error getting page at "
> +"index [%ld] from eCryptfs inode "
> +"mapping; rc = [%d]\n", __FUNCTION__,
> +ecryptfs_page_idx, rc);
> + goto out;
> + }
> + if (start_offset_in_page) {
> + /* Read in the page from the lower
> +

Re: [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-19 Thread Andrew Morton
On Mon, 17 Sep 2007 16:46:32 -0500 Michael Halcrow <[EMAIL PROTECTED]> wrote:

> +/**
> + * ecryptfs_write_lower
> + * @ecryptfs_inode: The eCryptfs inode
> + * @data: Data to write
> + * @offset: Byte offset in the lower file to which to write the data
> + * @size: Number of bytes from @data to write at @offset in the lower
> + *file
> + *
> + * Write data to the lower file.
> + *
> + * Returns zero on success; non-zero on error
> + */

That might come out looking odd in the kernel doc?  Normally the documentation
would start out with

+/**
+ * ecryptfs_write_lower - write data to the lower file

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


Re: [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-19 Thread Andrew Morton
On Mon, 17 Sep 2007 16:46:32 -0500 Michael Halcrow [EMAIL PROTECTED] wrote:

 +/**
 + * ecryptfs_write_lower
 + * @ecryptfs_inode: The eCryptfs inode
 + * @data: Data to write
 + * @offset: Byte offset in the lower file to which to write the data
 + * @size: Number of bytes from @data to write at @offset in the lower
 + *file
 + *
 + * Write data to the lower file.
 + *
 + * Returns zero on success; non-zero on error
 + */

That might come out looking odd in the kernel doc?  Normally the documentation
would start out with

+/**
+ * ecryptfs_write_lower - write data to the lower file

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


Re: [PATCH 3/11] eCryptfs: read_write.c routines

2007-09-19 Thread Andrew Morton
On Mon, 17 Sep 2007 16:46:32 -0500 Michael Halcrow [EMAIL PROTECTED] wrote:

 Add a set of functions through which all I/O to lower files is
 consolidated. This patch adds a new inode_info reference to a
 persistent lower file for each eCryptfs inode; another patch later in
 this series will set that up. This persistent lower file is what the
 read_write.c functions use to call vfs_read() and vfs_write() on the
 lower filesystem, so even when reads and writes come in through
 aops-readpage and aops-writepage, we can satisfy them without
 resorting to direct access to the lower inode's address space.
 Several function declarations are going to be changing with this
 patchset. For now, in order to keep from breaking the build, I am
 putting dummy parameters in for those functions.
 
 ..

 +/**
 + * ecryptfs_write_lower_page_segment
 + * @ecryptfs_inode: The eCryptfs inode
 + * @page_for_lower: The page containing the data to be written to the
 + *  lower file
 + * @offset_in_page: The offset in the @page_for_lower from which to
 + *  start writing the data
 + * @size: The amount of data from @page_for_lower to write to the
 + *lower file
 + *
 + * Determines the byte offset in the file for the given page and
 + * offset within the page, maps the page, and makes the call to write
 + * the contents of @page_for_lower to the lower inode.
 + *
 + * Returns zero on success; non-zero otherwise
 + */
 +int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
 +   struct page *page_for_lower,
 +   size_t offset_in_page, size_t size)
 +{
 + char *virt;
 + loff_t offset;
 + int rc;
 +
 + offset = (page_for_lower-index  PAGE_CACHE_SHIFT) + offset_in_page;

bug.  You need to cast page.index to loff_t before shifting.

I'd fix it on the spot, but this would be a good time to review the whole
patchset and perhaps the whole fs for this easy-to-do, hard-to-find bug.

 + virt = kmap(page_for_lower);
 + rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
 + kunmap(page_for_lower);
 + return rc;
 +}

argh, kmap.  http://lkml.org/lkml/2007/9/15/55

 +/**
 + * ecryptfs_write
 + * @ecryptfs_file: The eCryptfs file into which to write
 + * @data: Virtual address where data to write is located
 + * @offset: Offset in the eCryptfs file at which to begin writing the
 + *  data from @data
 + * @size: The number of bytes to write from @data
 + *
 + * Write an arbitrary amount of data to an arbitrary location in the
 + * eCryptfs inode page cache. This is done on a page-by-page, and then
 + * by an extent-by-extent, basis; individual extents are encrypted and
 + * written to the lower page cache (via VFS writes). This function
 + * takes care of all the address translation to locations in the lower
 + * filesystem; it also handles truncate events, writing out zeros
 + * where necessary.
 + *
 + * Returns zero on success; non-zero otherwise
 + */
 +int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
 +size_t size)
 +{
 + struct page *ecryptfs_page;
 + char *ecryptfs_page_virt;
 + u64 ecryptfs_file_size = i_size_read(ecryptfs_file-f_dentry-d_inode);

Not loff_t?

 + loff_t data_offset = 0;
 + loff_t pos;
 + int rc = 0;
 +
 + if (offset  ecryptfs_file_size)
 + pos = ecryptfs_file_size;

loff_t = u64.  The typing seems a bit confused?

 + else
 + pos = offset;
 + while (pos  (offset + size)) {
 + pgoff_t ecryptfs_page_idx = (pos  PAGE_CACHE_SHIFT);
 + size_t start_offset_in_page = (pos  ~PAGE_CACHE_MASK);
 + size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);
 + size_t total_remaining_bytes = ((offset + size) - pos);
 +
 + if (num_bytes  total_remaining_bytes)
 + num_bytes = total_remaining_bytes;
 + if (pos  offset) {
 + size_t total_remaining_zeros = (offset - pos);
 +
 + if (num_bytes  total_remaining_zeros)
 + num_bytes = total_remaining_zeros;
 + }
 + ecryptfs_page = ecryptfs_get1page(ecryptfs_file,
 +   ecryptfs_page_idx);
 + if (IS_ERR(ecryptfs_page)) {
 + rc = PTR_ERR(ecryptfs_page);
 + printk(KERN_ERR %s: Error getting page at 
 +index [%ld] from eCryptfs inode 
 +mapping; rc = [%d]\n, __FUNCTION__,
 +ecryptfs_page_idx, rc);
 + goto out;
 + }
 + if (start_offset_in_page) {
 + /* Read in the page from the lower
 +  * into the eCryptfs inode page cache,
 +  * decrypting */
 + if ((rc = 

[PATCH 3/11] eCryptfs: read_write.c routines

2007-09-17 Thread Michael Halcrow
Add a set of functions through which all I/O to lower files is
consolidated. This patch adds a new inode_info reference to a
persistent lower file for each eCryptfs inode; another patch later in
this series will set that up. This persistent lower file is what the
read_write.c functions use to call vfs_read() and vfs_write() on the
lower filesystem, so even when reads and writes come in through
aops->readpage and aops->writepage, we can satisfy them without
resorting to direct access to the lower inode's address space.
Several function declarations are going to be changing with this
patchset. For now, in order to keep from breaking the build, I am
putting dummy parameters in for those functions.

Signed-off-by: Michael Halcrow <[EMAIL PROTECTED]>
---
 fs/ecryptfs/Makefile  |2 +-
 fs/ecryptfs/ecryptfs_kernel.h |   18 ++
 fs/ecryptfs/mmap.c|2 +-
 fs/ecryptfs/read_write.c  |  359 +
 4 files changed, 379 insertions(+), 2 deletions(-)
 create mode 100644 fs/ecryptfs/read_write.c

diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
index 1f11072..7688570 100644
--- a/fs/ecryptfs/Makefile
+++ b/fs/ecryptfs/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
 
-ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o 
keystore.o messaging.o netlink.o debug.o
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o 
crypto.o keystore.o messaging.o netlink.o debug.o
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index a618ab7..e6a68a8 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -260,6 +260,8 @@ struct ecryptfs_crypt_stat {
 struct ecryptfs_inode_info {
struct inode vfs_inode;
struct inode *wii_inode;
+   struct file *lower_file;
+   struct mutex lower_file_mutex;
struct ecryptfs_crypt_stat crypt_stat;
 };
 
@@ -653,5 +655,21 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key 
**auth_tok_key,
  char *sig);
 int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start,
 int num_zeros);
+int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
+loff_t offset, size_t size);
+int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
+ struct page *page_for_lower,
+ size_t offset_in_page, size_t size);
+int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
+  size_t size);
+int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
+   struct inode *ecryptfs_inode);
+int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
+pgoff_t page_index,
+size_t offset_in_page, size_t size,
+struct inode *ecryptfs_inode);
+int ecryptfs_read(char *data, loff_t offset, size_t size,
+ struct file *ecryptfs_file);
+struct page *ecryptfs_get1page(struct file *file, loff_t index);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 307f7ee..0c53320 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -44,7 +44,7 @@ struct kmem_cache *ecryptfs_lower_page_cache;
  * Returns unlocked and up-to-date page (if ok), with increased
  * refcnt.
  */
-static struct page *ecryptfs_get1page(struct file *file, int index)
+struct page *ecryptfs_get1page(struct file *file, loff_t index)
 {
struct dentry *dentry;
struct inode *inode;
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
new file mode 100644
index 000..e59c94a
--- /dev/null
+++ b/fs/ecryptfs/read_write.c
@@ -0,0 +1,359 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 2007 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include 
+#include 
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_write_lower
+ * @ecryptfs_inode: The eCryptfs inode
+ * @data: Data to write
+ * @offset: Byte offset in the lower file 

[PATCH 3/11] eCryptfs: read_write.c routines

2007-09-17 Thread Michael Halcrow
Add a set of functions through which all I/O to lower files is
consolidated. This patch adds a new inode_info reference to a
persistent lower file for each eCryptfs inode; another patch later in
this series will set that up. This persistent lower file is what the
read_write.c functions use to call vfs_read() and vfs_write() on the
lower filesystem, so even when reads and writes come in through
aops-readpage and aops-writepage, we can satisfy them without
resorting to direct access to the lower inode's address space.
Several function declarations are going to be changing with this
patchset. For now, in order to keep from breaking the build, I am
putting dummy parameters in for those functions.

Signed-off-by: Michael Halcrow [EMAIL PROTECTED]
---
 fs/ecryptfs/Makefile  |2 +-
 fs/ecryptfs/ecryptfs_kernel.h |   18 ++
 fs/ecryptfs/mmap.c|2 +-
 fs/ecryptfs/read_write.c  |  359 +
 4 files changed, 379 insertions(+), 2 deletions(-)
 create mode 100644 fs/ecryptfs/read_write.c

diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
index 1f11072..7688570 100644
--- a/fs/ecryptfs/Makefile
+++ b/fs/ecryptfs/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
 
-ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o 
keystore.o messaging.o netlink.o debug.o
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o 
crypto.o keystore.o messaging.o netlink.o debug.o
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index a618ab7..e6a68a8 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -260,6 +260,8 @@ struct ecryptfs_crypt_stat {
 struct ecryptfs_inode_info {
struct inode vfs_inode;
struct inode *wii_inode;
+   struct file *lower_file;
+   struct mutex lower_file_mutex;
struct ecryptfs_crypt_stat crypt_stat;
 };
 
@@ -653,5 +655,21 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key 
**auth_tok_key,
  char *sig);
 int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start,
 int num_zeros);
+int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
+loff_t offset, size_t size);
+int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
+ struct page *page_for_lower,
+ size_t offset_in_page, size_t size);
+int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
+  size_t size);
+int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
+   struct inode *ecryptfs_inode);
+int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
+pgoff_t page_index,
+size_t offset_in_page, size_t size,
+struct inode *ecryptfs_inode);
+int ecryptfs_read(char *data, loff_t offset, size_t size,
+ struct file *ecryptfs_file);
+struct page *ecryptfs_get1page(struct file *file, loff_t index);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 307f7ee..0c53320 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -44,7 +44,7 @@ struct kmem_cache *ecryptfs_lower_page_cache;
  * Returns unlocked and up-to-date page (if ok), with increased
  * refcnt.
  */
-static struct page *ecryptfs_get1page(struct file *file, int index)
+struct page *ecryptfs_get1page(struct file *file, loff_t index)
 {
struct dentry *dentry;
struct inode *inode;
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
new file mode 100644
index 000..e59c94a
--- /dev/null
+++ b/fs/ecryptfs/read_write.c
@@ -0,0 +1,359 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 2007 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow [EMAIL PROTECTED]
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include linux/fs.h
+#include linux/pagemap.h
+#include ecryptfs_kernel.h
+
+/**
+ * ecryptfs_write_lower
+ * @ecryptfs_inode: The eCryptfs inode
+ * @data: Data to write
+ * @offset: Byte offset