2007-05-21 23:00:39

by Michael Halcrow

[permalink] [raw]
Subject: [PATCH] eCryptfs: Delay writing 0's after llseek until write

Delay writing 0's out in eCryptfs after a seek past the end of the
file until data is actually written.

Signed-off-by: Michael Halcrow <[email protected]>

diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 9881b5c..59288d8 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -33,63 +33,6 @@
#include "ecryptfs_kernel.h"

/**
- * ecryptfs_llseek
- * @file: File we are seeking in
- * @offset: The offset to seek to
- * @origin: 2 - offset from i_size; 1 - offset from f_pos
- *
- * Returns the position we have seeked to, or negative on error
- */
-static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
-{
- loff_t rv;
- loff_t new_end_pos;
- int rc;
- int expanding_file = 0;
- struct inode *inode = file->f_mapping->host;
-
- /* If our offset is past the end of our file, we're going to
- * need to grow it so we have a valid length of 0's */
- new_end_pos = offset;
- switch (origin) {
- case 2:
- new_end_pos += i_size_read(inode);
- expanding_file = 1;
- break;
- case 1:
- new_end_pos += file->f_pos;
- if (new_end_pos > i_size_read(inode)) {
- ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
- "> i_size_read(inode)(=[0x%.16x])\n",
- new_end_pos, i_size_read(inode));
- expanding_file = 1;
- }
- break;
- default:
- if (new_end_pos > i_size_read(inode)) {
- ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
- "> i_size_read(inode)(=[0x%.16x])\n",
- new_end_pos, i_size_read(inode));
- expanding_file = 1;
- }
- }
- ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos);
- if (expanding_file) {
- rc = ecryptfs_truncate(file->f_path.dentry, new_end_pos);
- if (rc) {
- rv = rc;
- ecryptfs_printk(KERN_ERR, "Error on attempt to "
- "truncate to (higher) offset [0x%.16x];"
- " rc = [%d]\n", new_end_pos, rc);
- goto out;
- }
- }
- rv = generic_file_llseek(file, offset, origin);
-out:
- return rv;
-}
-
-/**
* ecryptfs_read_update_atime
*
* generic_file_read updates the atime of upper layer inode. But, it
@@ -425,7 +368,7 @@ const struct file_operations ecryptfs_dir_fops = {
};

const struct file_operations ecryptfs_main_fops = {
- .llseek = ecryptfs_llseek,
+ .llseek = generic_file_llseek,
.read = do_sync_read,
.aio_read = ecryptfs_read_update_atime,
.write = do_sync_write,
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 88ea669..55cec98 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -376,9 +376,31 @@ out:
return 0;
}

+/**
+ * eCryptfs does not currently support holes. When writing after a
+ * seek past the end of the file, eCryptfs fills in 0's through to the
+ * current location. The code to fill in the 0's to all the
+ * intermediate pages calls ecryptfs_prepare_write_no_truncate().
+ */
+static int
+ecryptfs_prepare_write_no_truncate(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ 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);
+out:
+ return rc;
+}
+
static int ecryptfs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
+ loff_t pos;
int rc = 0;

if (from == 0 && to == PAGE_CACHE_SIZE)
@@ -386,6 +408,16 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
up to date. */
if (!PageUptodate(page))
rc = ecryptfs_do_readpage(file, page, page->index);
+ pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+ if (pos > i_size_read(page->mapping->host)) {
+ rc = ecryptfs_truncate(file->f_path.dentry, pos);
+ if (rc) {
+ printk(KERN_ERR "Error on attempt to "
+ "truncate to (higher) offset [%lld];"
+ " rc = [%d]\n", pos, rc);
+ goto out;
+ }
+ }
out:
return rc;
}
@@ -744,10 +776,10 @@ int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
rc = PTR_ERR(tmp_page);
goto out;
}
- rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
- if (rc) {
+ if ((rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start,
+ (start + num_zeros)))) {
ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
- "to remainder of page at index [0x%.16x]\n",
+ "to page at index [0x%.16x]\n",
index);
page_cache_release(tmp_page);
goto out;


2007-05-22 04:09:19

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] eCryptfs: Delay writing 0's after llseek until write

On Mon, 21 May 2007 18:00:21 -0500 Michael Halcrow <[email protected]> wrote:

> Delay writing 0's out in eCryptfs after a seek past the end of the
> file until data is actually written.

a) why?

b) what is the impact upon a user of them not having this patch?

2007-05-22 14:52:09

by Michael Halcrow

[permalink] [raw]
Subject: Re: [PATCH] eCryptfs: Delay writing 0's after llseek until write

On Mon, May 21, 2007 at 09:07:08PM -0700, Andrew Morton wrote:
> On Mon, 21 May 2007 18:00:21 -0500 Michael Halcrow <[email protected]> wrote:
>
> > Delay writing 0's out in eCryptfs after a seek past the end of the
> > file until data is actually written.
>
> a) why?

http://www.opengroup.org/onlinepubs/009695399/functions/lseek.html

``The lseek() function shall not, by itself, extend the size of a
file.''

> b) what is the impact upon a user of them not having this patch?

Applications that lseek() past the end of the file without writing
will experience unexpected behavior.

Mike

2007-05-22 15:01:37

by Nish Aravamudan

[permalink] [raw]
Subject: Re: [PATCH] eCryptfs: Delay writing 0's after llseek until write

On 5/22/07, Michael Halcrow <[email protected]> wrote:
> On Mon, May 21, 2007 at 09:07:08PM -0700, Andrew Morton wrote:
> > On Mon, 21 May 2007 18:00:21 -0500 Michael Halcrow <[email protected]> wrote:
> >
> > > Delay writing 0's out in eCryptfs after a seek past the end of the
> > > file until data is actually written.
> >
> > a) why?
>
> http://www.opengroup.org/onlinepubs/009695399/functions/lseek.html
>
> ``The lseek() function shall not, by itself, extend the size of a
> file.''
>
> > b) what is the impact upon a user of them not having this patch?
>
> Applications that lseek() past the end of the file without writing
> will experience unexpected behavior.

FWIW, I believe Andrew's point was that critical information for Joe
Enduser (and Joe Patch-Ho) was lacking in the original changelog.

Thanks,
Nish

2007-05-22 16:42:39

by Zach Brown

[permalink] [raw]
Subject: Re: [PATCH] eCryptfs: Delay writing 0's after llseek until write

> FWIW, I believe Andrew's point was that critical information for Joe
> Enduser (and Joe Patch-Ho) was lacking in the original changelog.

and don't forget Joe eCryptfs-Maintainer-2-Years-In-The-Future.

- z