diff options
author | Eric Sandeen <sandeen@redhat.com> | 2007-12-17 19:20:10 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-12-17 22:28:17 -0500 |
commit | 7a3f595cc8298df14a7c71b0d876bafd8e9e1cbf (patch) | |
tree | e2409b01431e230369182d3a450dcd9c2c6beb0a /fs/ecryptfs/mmap.c | |
parent | 8998979cc1f90da5a48b2e8a13833217c63f7c4a (diff) |
ecryptfs: fix fsx data corruption problems
ecryptfs in 2.6.24-rc3 wasn't surviving fsx for me at all, dying after 4
ops. Generally, encountering problems with stale data and improperly
zeroed pages. An extending truncate + write for example would expose stale
data.
With the changes below I got to a million ops and beyond with all mmap ops
disabled - mmap still needs work. (A version of this patch on a RHEL5
kernel ran for over 110 million fsx ops)
I added a few comments as well, to the best of my understanding
as I read through the code.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Acked-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.c | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 16a7a555f392..32c5711d79a3 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c | |||
@@ -263,14 +263,13 @@ out: | |||
263 | return 0; | 263 | return 0; |
264 | } | 264 | } |
265 | 265 | ||
266 | /* This function must zero any hole we create */ | ||
266 | static int ecryptfs_prepare_write(struct file *file, struct page *page, | 267 | static int ecryptfs_prepare_write(struct file *file, struct page *page, |
267 | unsigned from, unsigned to) | 268 | unsigned from, unsigned to) |
268 | { | 269 | { |
269 | int rc = 0; | 270 | int rc = 0; |
271 | loff_t prev_page_end_size; | ||
270 | 272 | ||
271 | if (from == 0 && to == PAGE_CACHE_SIZE) | ||
272 | goto out; /* If we are writing a full page, it will be | ||
273 | up to date. */ | ||
274 | if (!PageUptodate(page)) { | 273 | if (!PageUptodate(page)) { |
275 | rc = ecryptfs_read_lower_page_segment(page, page->index, 0, | 274 | rc = ecryptfs_read_lower_page_segment(page, page->index, 0, |
276 | PAGE_CACHE_SIZE, | 275 | PAGE_CACHE_SIZE, |
@@ -283,22 +282,32 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page, | |||
283 | } else | 282 | } else |
284 | SetPageUptodate(page); | 283 | SetPageUptodate(page); |
285 | } | 284 | } |
286 | if (page->index != 0) { | ||
287 | loff_t end_of_prev_pg_pos = | ||
288 | (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1); | ||
289 | 285 | ||
290 | if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) { | 286 | prev_page_end_size = ((loff_t)page->index << PAGE_CACHE_SHIFT); |
287 | |||
288 | /* | ||
289 | * If creating a page or more of holes, zero them out via truncate. | ||
290 | * Note, this will increase i_size. | ||
291 | */ | ||
292 | if (page->index != 0) { | ||
293 | if (prev_page_end_size > i_size_read(page->mapping->host)) { | ||
291 | rc = ecryptfs_truncate(file->f_path.dentry, | 294 | rc = ecryptfs_truncate(file->f_path.dentry, |
292 | end_of_prev_pg_pos); | 295 | prev_page_end_size); |
293 | if (rc) { | 296 | if (rc) { |
294 | printk(KERN_ERR "Error on attempt to " | 297 | printk(KERN_ERR "Error on attempt to " |
295 | "truncate to (higher) offset [%lld];" | 298 | "truncate to (higher) offset [%lld];" |
296 | " rc = [%d]\n", end_of_prev_pg_pos, rc); | 299 | " rc = [%d]\n", prev_page_end_size, rc); |
297 | goto out; | 300 | goto out; |
298 | } | 301 | } |
299 | } | 302 | } |
300 | if (end_of_prev_pg_pos + 1 > i_size_read(page->mapping->host)) | 303 | } |
301 | zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0); | 304 | /* |
305 | * Writing to a new page, and creating a small hole from start of page? | ||
306 | * Zero it out. | ||
307 | */ | ||
308 | if ((i_size_read(page->mapping->host) == prev_page_end_size) && | ||
309 | (from != 0)) { | ||
310 | zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0); | ||
302 | } | 311 | } |
303 | out: | 312 | out: |
304 | return rc; | 313 | return rc; |