aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ecryptfs/mmap.c
diff options
context:
space:
mode:
authorMichael Halcrow <mhalcrow@us.ibm.com>2007-06-27 17:09:44 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-06-28 14:34:53 -0400
commit240e2df5c740d73fc08cac9989872212deb2d20e (patch)
tree538dc70281c5401f3843ac8c752b2092f79ba9ee /fs/ecryptfs/mmap.c
parentb75ae8603568ae18f270213693758c78fb8a29ff (diff)
eCryptfs: fix write zeros behavior
This patch fixes the processes involved in wiping regions of the data during truncate and write events, fixing a kernel hang in 2.6.22-rc4 while assuring that zero values are written out to the appropriate locations during events in which the i_size will change. The range passed to ecryptfs_truncate() from ecryptfs_prepare_write() includes the page that is the object of ecryptfs_prepare_write(). This leads to a kernel hang as read_cache_page() is executed on the same page in the ecryptfs_truncate() execution path. This patch remedies this by limiting the range passed to ecryptfs_truncate() so as to exclude the page that is the object of ecryptfs_prepare_write(); it also adds code to ecryptfs_prepare_write() to zero out the region of its own page when writing past the i_size position. This patch also modifies ecryptfs_truncate() so that when a file is truncated to a smaller size, eCryptfs will zero out the contents of the new last page from the new size through to the end of the last page. 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>
Diffstat (limited to 'fs/ecryptfs/mmap.c')
-rw-r--r--fs/ecryptfs/mmap.c53
1 files changed, 29 insertions, 24 deletions
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 55cec98a84e7..6df410c77264 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -56,9 +56,6 @@ static struct page *ecryptfs_get1page(struct file *file, int index)
56 return read_mapping_page(mapping, index, (void *)file); 56 return read_mapping_page(mapping, index, (void *)file);
57} 57}
58 58
59static
60int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros);
61
62/** 59/**
63 * ecryptfs_fill_zeros 60 * ecryptfs_fill_zeros
64 * @file: The ecryptfs file 61 * @file: The ecryptfs file
@@ -101,10 +98,13 @@ int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
101 if (old_end_page_index == new_end_page_index) { 98 if (old_end_page_index == new_end_page_index) {
102 /* Start and end are in the same page; we just need to 99 /* Start and end are in the same page; we just need to
103 * set a portion of the existing page to zero's */ 100 * set a portion of the existing page to zero's */
104 rc = write_zeros(file, index, (old_end_pos_in_page + 1), 101 rc = ecryptfs_write_zeros(file, index,
105 (new_end_pos_in_page - old_end_pos_in_page)); 102 (old_end_pos_in_page + 1),
103 (new_end_pos_in_page
104 - old_end_pos_in_page));
106 if (rc) 105 if (rc)
107 ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " 106 ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros("
107 "file=[%p], "
108 "index=[0x%.16x], " 108 "index=[0x%.16x], "
109 "old_end_pos_in_page=[d], " 109 "old_end_pos_in_page=[d], "
110 "(PAGE_CACHE_SIZE - new_end_pos_in_page" 110 "(PAGE_CACHE_SIZE - new_end_pos_in_page"
@@ -117,10 +117,10 @@ int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
117 goto out; 117 goto out;
118 } 118 }
119 /* Fill the remainder of the previous last page with zeros */ 119 /* Fill the remainder of the previous last page with zeros */
120 rc = write_zeros(file, index, (old_end_pos_in_page + 1), 120 rc = ecryptfs_write_zeros(file, index, (old_end_pos_in_page + 1),
121 ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page)); 121 ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page));
122 if (rc) { 122 if (rc) {
123 ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " 123 ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(file=[%p], "
124 "index=[0x%.16x], old_end_pos_in_page=[d], " 124 "index=[0x%.16x], old_end_pos_in_page=[d], "
125 "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) " 125 "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) "
126 "returned [%d]\n", file, index, 126 "returned [%d]\n", file, index,
@@ -131,9 +131,10 @@ int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
131 index++; 131 index++;
132 while (index < new_end_page_index) { 132 while (index < new_end_page_index) {
133 /* Fill all intermediate pages with zeros */ 133 /* Fill all intermediate pages with zeros */
134 rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE); 134 rc = ecryptfs_write_zeros(file, index, 0, PAGE_CACHE_SIZE);
135 if (rc) { 135 if (rc) {
136 ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " 136 ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros("
137 "file=[%p], "
137 "index=[0x%.16x], " 138 "index=[0x%.16x], "
138 "old_end_pos_in_page=[d], " 139 "old_end_pos_in_page=[d], "
139 "(PAGE_CACHE_SIZE - new_end_pos_in_page" 140 "(PAGE_CACHE_SIZE - new_end_pos_in_page"
@@ -149,9 +150,9 @@ int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
149 } 150 }
150 /* Fill the portion at the beginning of the last new page with 151 /* Fill the portion at the beginning of the last new page with
151 * zero's */ 152 * zero's */
152 rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1)); 153 rc = ecryptfs_write_zeros(file, index, 0, (new_end_pos_in_page + 1));
153 if (rc) { 154 if (rc) {
154 ecryptfs_printk(KERN_ERR, "write_zeros(file=" 155 ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(file="
155 "[%p], index=[0x%.16x], 0, " 156 "[%p], index=[0x%.16x], 0, "
156 "new_end_pos_in_page=[%d]" 157 "new_end_pos_in_page=[%d]"
157 "returned [%d]\n", file, index, 158 "returned [%d]\n", file, index,
@@ -400,7 +401,6 @@ out:
400static int ecryptfs_prepare_write(struct file *file, struct page *page, 401static int ecryptfs_prepare_write(struct file *file, struct page *page,
401 unsigned from, unsigned to) 402 unsigned from, unsigned to)
402{ 403{
403 loff_t pos;
404 int rc = 0; 404 int rc = 0;
405 405
406 if (from == 0 && to == PAGE_CACHE_SIZE) 406 if (from == 0 && to == PAGE_CACHE_SIZE)
@@ -408,14 +408,19 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
408 up to date. */ 408 up to date. */
409 if (!PageUptodate(page)) 409 if (!PageUptodate(page))
410 rc = ecryptfs_do_readpage(file, page, page->index); 410 rc = ecryptfs_do_readpage(file, page, page->index);
411 pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; 411 if (page->index != 0) {
412 if (pos > i_size_read(page->mapping->host)) { 412 loff_t end_of_prev_pg_pos =
413 rc = ecryptfs_truncate(file->f_path.dentry, pos); 413 (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1);
414 if (rc) { 414
415 printk(KERN_ERR "Error on attempt to " 415 if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) {
416 "truncate to (higher) offset [%lld];" 416 rc = ecryptfs_truncate(file->f_path.dentry,
417 " rc = [%d]\n", pos, rc); 417 end_of_prev_pg_pos);
418 goto out; 418 if (rc) {
419 printk(KERN_ERR "Error on attempt to "
420 "truncate to (higher) offset [%lld];"
421 " rc = [%d]\n", end_of_prev_pg_pos, rc);
422 goto out;
423 }
419 } 424 }
420 } 425 }
421out: 426out:
@@ -753,7 +758,7 @@ out:
753} 758}
754 759
755/** 760/**
756 * write_zeros 761 * ecryptfs_write_zeros
757 * @file: The ecryptfs file 762 * @file: The ecryptfs file
758 * @index: The index in which we are writing 763 * @index: The index in which we are writing
759 * @start: The position after the last block of data 764 * @start: The position after the last block of data
@@ -763,8 +768,8 @@ out:
763 * 768 *
764 * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE 769 * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE
765 */ 770 */
766static 771int
767int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) 772ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
768{ 773{
769 int rc = 0; 774 int rc = 0;
770 struct page *tmp_page; 775 struct page *tmp_page;