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/read_write.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/read_write.c')
-rw-r--r-- | fs/ecryptfs/read_write.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c index 6b7474a4336a..948f57624c05 100644 --- a/fs/ecryptfs/read_write.c +++ b/fs/ecryptfs/read_write.c | |||
@@ -124,6 +124,10 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset, | |||
124 | loff_t pos; | 124 | loff_t pos; |
125 | int rc = 0; | 125 | int rc = 0; |
126 | 126 | ||
127 | /* | ||
128 | * if we are writing beyond current size, then start pos | ||
129 | * at the current size - we'll fill in zeros from there. | ||
130 | */ | ||
127 | if (offset > ecryptfs_file_size) | 131 | if (offset > ecryptfs_file_size) |
128 | pos = ecryptfs_file_size; | 132 | pos = ecryptfs_file_size; |
129 | else | 133 | else |
@@ -137,6 +141,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset, | |||
137 | if (num_bytes > total_remaining_bytes) | 141 | if (num_bytes > total_remaining_bytes) |
138 | num_bytes = total_remaining_bytes; | 142 | num_bytes = total_remaining_bytes; |
139 | if (pos < offset) { | 143 | if (pos < offset) { |
144 | /* remaining zeros to write, up to destination offset */ | ||
140 | size_t total_remaining_zeros = (offset - pos); | 145 | size_t total_remaining_zeros = (offset - pos); |
141 | 146 | ||
142 | if (num_bytes > total_remaining_zeros) | 147 | if (num_bytes > total_remaining_zeros) |
@@ -167,17 +172,27 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset, | |||
167 | } | 172 | } |
168 | } | 173 | } |
169 | ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0); | 174 | ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0); |
175 | |||
176 | /* | ||
177 | * pos: where we're now writing, offset: where the request was | ||
178 | * If current pos is before request, we are filling zeros | ||
179 | * If we are at or beyond request, we are writing the *data* | ||
180 | * If we're in a fresh page beyond eof, zero it in either case | ||
181 | */ | ||
182 | if (pos < offset || !start_offset_in_page) { | ||
183 | /* We are extending past the previous end of the file. | ||
184 | * Fill in zero values to the end of the page */ | ||
185 | memset(((char *)ecryptfs_page_virt | ||
186 | + start_offset_in_page), 0, | ||
187 | PAGE_CACHE_SIZE - start_offset_in_page); | ||
188 | } | ||
189 | |||
190 | /* pos >= offset, we are now writing the data request */ | ||
170 | if (pos >= offset) { | 191 | if (pos >= offset) { |
171 | memcpy(((char *)ecryptfs_page_virt | 192 | memcpy(((char *)ecryptfs_page_virt |
172 | + start_offset_in_page), | 193 | + start_offset_in_page), |
173 | (data + data_offset), num_bytes); | 194 | (data + data_offset), num_bytes); |
174 | data_offset += num_bytes; | 195 | data_offset += num_bytes; |
175 | } else { | ||
176 | /* We are extending past the previous end of the file. | ||
177 | * Fill in zero values up to the start of where we | ||
178 | * will be writing data. */ | ||
179 | memset(((char *)ecryptfs_page_virt | ||
180 | + start_offset_in_page), 0, num_bytes); | ||
181 | } | 196 | } |
182 | kunmap_atomic(ecryptfs_page_virt, KM_USER0); | 197 | kunmap_atomic(ecryptfs_page_virt, KM_USER0); |
183 | flush_dcache_page(ecryptfs_page); | 198 | flush_dcache_page(ecryptfs_page); |