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.
http://www.opengroup.org/onlinepubs/009695399/functions/lseek.html
``The lseek() function shall not, by itself, extend the size of a
file.''
Without this fix, applications that lseek() past the end of the file without
writing will experience unexpected behavior.
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>
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,8 +376,15 @@
return 0;
}
-static int ecryptfs_prepare_write(struct file *file, struct page *page,
- unsigned from, unsigned to)
+/**
+ * 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;
@@ -390,6 +397,31 @@
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)
+ 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);
+ 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;
+}
+
int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
struct inode *lower_inode,
struct writeback_control *wbc)
@@ -744,10 +776,10 @@
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;