aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Mayhar <fmayhar@google.com>2009-09-09 22:33:47 -0400
committerTheodore Ts'o <tytso@mit.edu>2009-09-09 22:33:47 -0400
commit91ac6f43317c0bf99969665f98016548011dfa38 (patch)
tree07a49f2182dd16fdb372e4a14c263cdd2d166578
parentfe188c0e084bdf3038dc0ac963c21d764f53f7da (diff)
ext4: Make non-journal fsync work properly
Teach ext4_write_inode() and ext4_do_update_inode() about non-journal mode: If we're not using a journal, ext4_write_inode() now calls ext4_do_update_inode() (after getting the iloc via ext4_get_inode_loc()) with a new "do_sync" parameter. If that parameter is nonzero _and_ we're not using a journal, ext4_do_update_inode() calls sync_dirty_buffer() instead of ext4_handle_dirty_metadata(). This problem was found in power-fail testing, checking the amount of loss of files and blocks after a power failure when using fsync() and when not using fsync(). It turned out that using fsync() was actually worse than not doing so, possibly because it increased the likelihood that the inodes would remain unflushed and would therefore be lost at the power failure. Signed-off-by: Frank Mayhar <fmayhar@google.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/inode.c54
1 files changed, 40 insertions, 14 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 6253ecdac67f..d04c8428bde2 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4538,7 +4538,8 @@ static int ext4_inode_blocks_set(handle_t *handle,
4538 */ 4538 */
4539static int ext4_do_update_inode(handle_t *handle, 4539static int ext4_do_update_inode(handle_t *handle,
4540 struct inode *inode, 4540 struct inode *inode,
4541 struct ext4_iloc *iloc) 4541 struct ext4_iloc *iloc,
4542 int do_sync)
4542{ 4543{
4543 struct ext4_inode *raw_inode = ext4_raw_inode(iloc); 4544 struct ext4_inode *raw_inode = ext4_raw_inode(iloc);
4544 struct ext4_inode_info *ei = EXT4_I(inode); 4545 struct ext4_inode_info *ei = EXT4_I(inode);
@@ -4640,10 +4641,22 @@ static int ext4_do_update_inode(handle_t *handle,
4640 raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); 4641 raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
4641 } 4642 }
4642 4643
4643 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); 4644 /*
4644 rc = ext4_handle_dirty_metadata(handle, inode, bh); 4645 * If we're not using a journal and we were called from
4645 if (!err) 4646 * ext4_write_inode() to sync the inode (making do_sync true),
4646 err = rc; 4647 * we can just use sync_dirty_buffer() directly to do our dirty
4648 * work. Testing s_journal here is a bit redundant but it's
4649 * worth it to avoid potential future trouble.
4650 */
4651 if (EXT4_SB(inode->i_sb)->s_journal == NULL && do_sync) {
4652 BUFFER_TRACE(bh, "call sync_dirty_buffer");
4653 sync_dirty_buffer(bh);
4654 } else {
4655 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
4656 rc = ext4_handle_dirty_metadata(handle, inode, bh);
4657 if (!err)
4658 err = rc;
4659 }
4647 ei->i_state &= ~EXT4_STATE_NEW; 4660 ei->i_state &= ~EXT4_STATE_NEW;
4648 4661
4649out_brelse: 4662out_brelse:
@@ -4689,19 +4702,32 @@ out_brelse:
4689 */ 4702 */
4690int ext4_write_inode(struct inode *inode, int wait) 4703int ext4_write_inode(struct inode *inode, int wait)
4691{ 4704{
4705 int err;
4706
4692 if (current->flags & PF_MEMALLOC) 4707 if (current->flags & PF_MEMALLOC)
4693 return 0; 4708 return 0;
4694 4709
4695 if (ext4_journal_current_handle()) { 4710 if (EXT4_SB(inode->i_sb)->s_journal) {
4696 jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n"); 4711 if (ext4_journal_current_handle()) {
4697 dump_stack(); 4712 jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n");
4698 return -EIO; 4713 dump_stack();
4699 } 4714 return -EIO;
4715 }
4700 4716
4701 if (!wait) 4717 if (!wait)
4702 return 0; 4718 return 0;
4719
4720 err = ext4_force_commit(inode->i_sb);
4721 } else {
4722 struct ext4_iloc iloc;
4703 4723
4704 return ext4_force_commit(inode->i_sb); 4724 err = ext4_get_inode_loc(inode, &iloc);
4725 if (err)
4726 return err;
4727 err = ext4_do_update_inode(EXT4_NOJOURNAL_HANDLE,
4728 inode, &iloc, wait);
4729 }
4730 return err;
4705} 4731}
4706 4732
4707/* 4733/*
@@ -4995,7 +5021,7 @@ int ext4_mark_iloc_dirty(handle_t *handle,
4995 get_bh(iloc->bh); 5021 get_bh(iloc->bh);
4996 5022
4997 /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */ 5023 /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */
4998 err = ext4_do_update_inode(handle, inode, iloc); 5024 err = ext4_do_update_inode(handle, inode, iloc, 0);
4999 put_bh(iloc->bh); 5025 put_bh(iloc->bh);
5000 return err; 5026 return err;
5001} 5027}