|
@@ -121,6 +121,33 @@ void ext4_evict_inode(struct inode *inode)
|
|
|
|
|
|
trace_ext4_evict_inode(inode);
|
|
|
if (inode->i_nlink) {
|
|
|
+ /*
|
|
|
+ * When journalling data dirty buffers are tracked only in the
|
|
|
+ * journal. So although mm thinks everything is clean and
|
|
|
+ * ready for reaping the inode might still have some pages to
|
|
|
+ * write in the running transaction or waiting to be
|
|
|
+ * checkpointed. Thus calling jbd2_journal_invalidatepage()
|
|
|
+ * (via truncate_inode_pages()) to discard these buffers can
|
|
|
+ * cause data loss. Also even if we did not discard these
|
|
|
+ * buffers, we would have no way to find them after the inode
|
|
|
+ * is reaped and thus user could see stale data if he tries to
|
|
|
+ * read them before the transaction is checkpointed. So be
|
|
|
+ * careful and force everything to disk here... We use
|
|
|
+ * ei->i_datasync_tid to store the newest transaction
|
|
|
+ * containing inode's data.
|
|
|
+ *
|
|
|
+ * Note that directories do not have this problem because they
|
|
|
+ * don't use page cache.
|
|
|
+ */
|
|
|
+ if (ext4_should_journal_data(inode) &&
|
|
|
+ (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) {
|
|
|
+ journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
|
|
|
+ tid_t commit_tid = EXT4_I(inode)->i_datasync_tid;
|
|
|
+
|
|
|
+ jbd2_log_start_commit(journal, commit_tid);
|
|
|
+ jbd2_log_wait_commit(journal, commit_tid);
|
|
|
+ filemap_write_and_wait(&inode->i_data);
|
|
|
+ }
|
|
|
truncate_inode_pages(&inode->i_data, 0);
|
|
|
goto no_delete;
|
|
|
}
|
|
@@ -970,6 +997,7 @@ static int ext4_journalled_write_end(struct file *file,
|
|
|
if (new_i_size > inode->i_size)
|
|
|
i_size_write(inode, pos+copied);
|
|
|
ext4_set_inode_state(inode, EXT4_STATE_JDATA);
|
|
|
+ EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;
|
|
|
if (new_i_size > EXT4_I(inode)->i_disksize) {
|
|
|
ext4_update_i_disksize(inode, new_i_size);
|
|
|
ret2 = ext4_mark_inode_dirty(handle, inode);
|
|
@@ -1678,6 +1706,7 @@ static int __ext4_journalled_writepage(struct page *page,
|
|
|
write_end_fn);
|
|
|
if (ret == 0)
|
|
|
ret = err;
|
|
|
+ EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;
|
|
|
err = ext4_journal_stop(handle);
|
|
|
if (!ret)
|
|
|
ret = err;
|