diff options
-rw-r--r-- | fs/ext3/inode.c | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index d2e4547c7806..f57c87b0cb83 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -197,6 +197,7 @@ static int truncate_restart_transaction(handle_t *handle, struct inode *inode) | |||
197 | */ | 197 | */ |
198 | void ext3_evict_inode (struct inode *inode) | 198 | void ext3_evict_inode (struct inode *inode) |
199 | { | 199 | { |
200 | struct ext3_inode_info *ei = EXT3_I(inode); | ||
200 | struct ext3_block_alloc_info *rsv; | 201 | struct ext3_block_alloc_info *rsv; |
201 | handle_t *handle; | 202 | handle_t *handle; |
202 | int want_delete = 0; | 203 | int want_delete = 0; |
@@ -207,11 +208,36 @@ void ext3_evict_inode (struct inode *inode) | |||
207 | want_delete = 1; | 208 | want_delete = 1; |
208 | } | 209 | } |
209 | 210 | ||
211 | /* | ||
212 | * When journalling data dirty buffers are tracked only in the journal. | ||
213 | * So although mm thinks everything is clean and ready for reaping the | ||
214 | * inode might still have some pages to write in the running | ||
215 | * transaction or waiting to be checkpointed. Thus calling | ||
216 | * journal_invalidatepage() (via truncate_inode_pages()) to discard | ||
217 | * these buffers can cause data loss. Also even if we did not discard | ||
218 | * these buffers, we would have no way to find them after the inode | ||
219 | * is reaped and thus user could see stale data if he tries to read | ||
220 | * them before the transaction is checkpointed. So be careful and | ||
221 | * force everything to disk here... We use ei->i_datasync_tid to | ||
222 | * store the newest transaction containing inode's data. | ||
223 | * | ||
224 | * Note that directories do not have this problem because they don't | ||
225 | * use page cache. | ||
226 | */ | ||
227 | if (inode->i_nlink && ext3_should_journal_data(inode) && | ||
228 | (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) { | ||
229 | tid_t commit_tid = atomic_read(&ei->i_datasync_tid); | ||
230 | journal_t *journal = EXT3_SB(inode->i_sb)->s_journal; | ||
231 | |||
232 | log_start_commit(journal, commit_tid); | ||
233 | log_wait_commit(journal, commit_tid); | ||
234 | filemap_write_and_wait(&inode->i_data); | ||
235 | } | ||
210 | truncate_inode_pages(&inode->i_data, 0); | 236 | truncate_inode_pages(&inode->i_data, 0); |
211 | 237 | ||
212 | ext3_discard_reservation(inode); | 238 | ext3_discard_reservation(inode); |
213 | rsv = EXT3_I(inode)->i_block_alloc_info; | 239 | rsv = ei->i_block_alloc_info; |
214 | EXT3_I(inode)->i_block_alloc_info = NULL; | 240 | ei->i_block_alloc_info = NULL; |
215 | if (unlikely(rsv)) | 241 | if (unlikely(rsv)) |
216 | kfree(rsv); | 242 | kfree(rsv); |
217 | 243 | ||
@@ -241,7 +267,7 @@ void ext3_evict_inode (struct inode *inode) | |||
241 | * have removed the record. | 267 | * have removed the record. |
242 | */ | 268 | */ |
243 | ext3_orphan_del(handle, inode); | 269 | ext3_orphan_del(handle, inode); |
244 | EXT3_I(inode)->i_dtime = get_seconds(); | 270 | ei->i_dtime = get_seconds(); |
245 | 271 | ||
246 | /* | 272 | /* |
247 | * One subtle ordering requirement: if anything has gone wrong | 273 | * One subtle ordering requirement: if anything has gone wrong |
@@ -1411,6 +1437,7 @@ static int ext3_journalled_write_end(struct file *file, | |||
1411 | { | 1437 | { |
1412 | handle_t *handle = ext3_journal_current_handle(); | 1438 | handle_t *handle = ext3_journal_current_handle(); |
1413 | struct inode *inode = mapping->host; | 1439 | struct inode *inode = mapping->host; |
1440 | struct ext3_inode_info *ei = EXT3_I(inode); | ||
1414 | int ret = 0, ret2; | 1441 | int ret = 0, ret2; |
1415 | int partial = 0; | 1442 | int partial = 0; |
1416 | unsigned from, to; | 1443 | unsigned from, to; |
@@ -1440,8 +1467,9 @@ static int ext3_journalled_write_end(struct file *file, | |||
1440 | if (pos + len > inode->i_size && ext3_can_truncate(inode)) | 1467 | if (pos + len > inode->i_size && ext3_can_truncate(inode)) |
1441 | ext3_orphan_add(handle, inode); | 1468 | ext3_orphan_add(handle, inode); |
1442 | ext3_set_inode_state(inode, EXT3_STATE_JDATA); | 1469 | ext3_set_inode_state(inode, EXT3_STATE_JDATA); |
1443 | if (inode->i_size > EXT3_I(inode)->i_disksize) { | 1470 | atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid); |
1444 | EXT3_I(inode)->i_disksize = inode->i_size; | 1471 | if (inode->i_size > ei->i_disksize) { |
1472 | ei->i_disksize = inode->i_size; | ||
1445 | ret2 = ext3_mark_inode_dirty(handle, inode); | 1473 | ret2 = ext3_mark_inode_dirty(handle, inode); |
1446 | if (!ret) | 1474 | if (!ret) |
1447 | ret = ret2; | 1475 | ret = ret2; |
@@ -1739,6 +1767,8 @@ static int ext3_journalled_writepage(struct page *page, | |||
1739 | if (ret == 0) | 1767 | if (ret == 0) |
1740 | ret = err; | 1768 | ret = err; |
1741 | ext3_set_inode_state(inode, EXT3_STATE_JDATA); | 1769 | ext3_set_inode_state(inode, EXT3_STATE_JDATA); |
1770 | atomic_set(&EXT3_I(inode)->i_datasync_tid, | ||
1771 | handle->h_transaction->t_tid); | ||
1742 | unlock_page(page); | 1772 | unlock_page(page); |
1743 | } else { | 1773 | } else { |
1744 | /* | 1774 | /* |