diff options
author | Michael Halcrow <mhalcrow@us.ibm.com> | 2007-05-23 16:58:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-23 23:14:15 -0400 |
commit | 53a2731f9310a66beaf55677229ab067c85ce4fa (patch) | |
tree | 6166f49b9205541a96696f648217c606cc9d9a0a | |
parent | 4acb3e2f97f41cf9b53182b494384467d3ceb304 (diff) |
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>
-rw-r--r-- | fs/ecryptfs/file.c | 59 | ||||
-rw-r--r-- | fs/ecryptfs/mmap.c | 38 |
2 files changed, 36 insertions, 61 deletions
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 9881b5c5de59..59288d817078 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c | |||
@@ -33,63 +33,6 @@ | |||
33 | #include "ecryptfs_kernel.h" | 33 | #include "ecryptfs_kernel.h" |
34 | 34 | ||
35 | /** | 35 | /** |
36 | * ecryptfs_llseek | ||
37 | * @file: File we are seeking in | ||
38 | * @offset: The offset to seek to | ||
39 | * @origin: 2 - offset from i_size; 1 - offset from f_pos | ||
40 | * | ||
41 | * Returns the position we have seeked to, or negative on error | ||
42 | */ | ||
43 | static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin) | ||
44 | { | ||
45 | loff_t rv; | ||
46 | loff_t new_end_pos; | ||
47 | int rc; | ||
48 | int expanding_file = 0; | ||
49 | struct inode *inode = file->f_mapping->host; | ||
50 | |||
51 | /* If our offset is past the end of our file, we're going to | ||
52 | * need to grow it so we have a valid length of 0's */ | ||
53 | new_end_pos = offset; | ||
54 | switch (origin) { | ||
55 | case 2: | ||
56 | new_end_pos += i_size_read(inode); | ||
57 | expanding_file = 1; | ||
58 | break; | ||
59 | case 1: | ||
60 | new_end_pos += file->f_pos; | ||
61 | if (new_end_pos > i_size_read(inode)) { | ||
62 | ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) " | ||
63 | "> i_size_read(inode)(=[0x%.16x])\n", | ||
64 | new_end_pos, i_size_read(inode)); | ||
65 | expanding_file = 1; | ||
66 | } | ||
67 | break; | ||
68 | default: | ||
69 | if (new_end_pos > i_size_read(inode)) { | ||
70 | ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) " | ||
71 | "> i_size_read(inode)(=[0x%.16x])\n", | ||
72 | new_end_pos, i_size_read(inode)); | ||
73 | expanding_file = 1; | ||
74 | } | ||
75 | } | ||
76 | ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos); | ||
77 | if (expanding_file) { | ||
78 | rc = ecryptfs_truncate(file->f_path.dentry, new_end_pos); | ||
79 | if (rc) { | ||
80 | rv = rc; | ||
81 | ecryptfs_printk(KERN_ERR, "Error on attempt to " | ||
82 | "truncate to (higher) offset [0x%.16x];" | ||
83 | " rc = [%d]\n", new_end_pos, rc); | ||
84 | goto out; | ||
85 | } | ||
86 | } | ||
87 | rv = generic_file_llseek(file, offset, origin); | ||
88 | out: | ||
89 | return rv; | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * ecryptfs_read_update_atime | 36 | * ecryptfs_read_update_atime |
94 | * | 37 | * |
95 | * generic_file_read updates the atime of upper layer inode. But, it | 38 | * generic_file_read updates the atime of upper layer inode. But, it |
@@ -425,7 +368,7 @@ const struct file_operations ecryptfs_dir_fops = { | |||
425 | }; | 368 | }; |
426 | 369 | ||
427 | const struct file_operations ecryptfs_main_fops = { | 370 | const struct file_operations ecryptfs_main_fops = { |
428 | .llseek = ecryptfs_llseek, | 371 | .llseek = generic_file_llseek, |
429 | .read = do_sync_read, | 372 | .read = do_sync_read, |
430 | .aio_read = ecryptfs_read_update_atime, | 373 | .aio_read = ecryptfs_read_update_atime, |
431 | .write = do_sync_write, | 374 | .write = do_sync_write, |
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 88ea6697908f..55cec98a84e7 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c | |||
@@ -376,9 +376,31 @@ out: | |||
376 | return 0; | 376 | return 0; |
377 | } | 377 | } |
378 | 378 | ||
379 | /** | ||
380 | * eCryptfs does not currently support holes. When writing after a | ||
381 | * seek past the end of the file, eCryptfs fills in 0's through to the | ||
382 | * current location. The code to fill in the 0's to all the | ||
383 | * intermediate pages calls ecryptfs_prepare_write_no_truncate(). | ||
384 | */ | ||
385 | static int | ||
386 | ecryptfs_prepare_write_no_truncate(struct file *file, struct page *page, | ||
387 | unsigned from, unsigned to) | ||
388 | { | ||
389 | int rc = 0; | ||
390 | |||
391 | if (from == 0 && to == PAGE_CACHE_SIZE) | ||
392 | goto out; /* If we are writing a full page, it will be | ||
393 | up to date. */ | ||
394 | if (!PageUptodate(page)) | ||
395 | rc = ecryptfs_do_readpage(file, page, page->index); | ||
396 | out: | ||
397 | return rc; | ||
398 | } | ||
399 | |||
379 | static int ecryptfs_prepare_write(struct file *file, struct page *page, | 400 | static int ecryptfs_prepare_write(struct file *file, struct page *page, |
380 | unsigned from, unsigned to) | 401 | unsigned from, unsigned to) |
381 | { | 402 | { |
403 | loff_t pos; | ||
382 | int rc = 0; | 404 | int rc = 0; |
383 | 405 | ||
384 | if (from == 0 && to == PAGE_CACHE_SIZE) | 406 | if (from == 0 && to == PAGE_CACHE_SIZE) |
@@ -386,6 +408,16 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page, | |||
386 | up to date. */ | 408 | up to date. */ |
387 | if (!PageUptodate(page)) | 409 | if (!PageUptodate(page)) |
388 | 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; | ||
412 | if (pos > i_size_read(page->mapping->host)) { | ||
413 | rc = ecryptfs_truncate(file->f_path.dentry, pos); | ||
414 | if (rc) { | ||
415 | printk(KERN_ERR "Error on attempt to " | ||
416 | "truncate to (higher) offset [%lld];" | ||
417 | " rc = [%d]\n", pos, rc); | ||
418 | goto out; | ||
419 | } | ||
420 | } | ||
389 | out: | 421 | out: |
390 | return rc; | 422 | return rc; |
391 | } | 423 | } |
@@ -744,10 +776,10 @@ int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) | |||
744 | rc = PTR_ERR(tmp_page); | 776 | rc = PTR_ERR(tmp_page); |
745 | goto out; | 777 | goto out; |
746 | } | 778 | } |
747 | rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros); | 779 | if ((rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start, |
748 | if (rc) { | 780 | (start + num_zeros)))) { |
749 | ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " | 781 | ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " |
750 | "to remainder of page at index [0x%.16x]\n", | 782 | "to page at index [0x%.16x]\n", |
751 | index); | 783 | index); |
752 | page_cache_release(tmp_page); | 784 | page_cache_release(tmp_page); |
753 | goto out; | 785 | goto out; |