diff options
author | Dmitry Monakhov <dmonakhov@openvz.org> | 2013-06-12 22:25:07 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-06-12 22:25:07 -0400 |
commit | 06a407f13daf9e48f0ef7189c7e54082b53940c7 (patch) | |
tree | 79ce69f348c778ed64877f549c7b81a2a585848e /fs/ext4 | |
parent | 9ff864462477206bc23b405a6ae506e92fb6dc9c (diff) |
ext4: fix data integrity for ext4_sync_fs
Inode's data or non journaled quota may be written w/o jounral so we
_must_ send a barrier at the end of ext4_sync_fs. But it can be
skipped if journal commit will do it for us.
Also fix data integrity for nojournal mode.
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/super.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 7c8e1713e203..0f77c2e4b888 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -69,6 +69,7 @@ static void ext4_mark_recovery_complete(struct super_block *sb, | |||
69 | static void ext4_clear_journal_err(struct super_block *sb, | 69 | static void ext4_clear_journal_err(struct super_block *sb, |
70 | struct ext4_super_block *es); | 70 | struct ext4_super_block *es); |
71 | static int ext4_sync_fs(struct super_block *sb, int wait); | 71 | static int ext4_sync_fs(struct super_block *sb, int wait); |
72 | static int ext4_sync_fs_nojournal(struct super_block *sb, int wait); | ||
72 | static int ext4_remount(struct super_block *sb, int *flags, char *data); | 73 | static int ext4_remount(struct super_block *sb, int *flags, char *data); |
73 | static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); | 74 | static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); |
74 | static int ext4_unfreeze(struct super_block *sb); | 75 | static int ext4_unfreeze(struct super_block *sb); |
@@ -1097,6 +1098,7 @@ static const struct super_operations ext4_nojournal_sops = { | |||
1097 | .dirty_inode = ext4_dirty_inode, | 1098 | .dirty_inode = ext4_dirty_inode, |
1098 | .drop_inode = ext4_drop_inode, | 1099 | .drop_inode = ext4_drop_inode, |
1099 | .evict_inode = ext4_evict_inode, | 1100 | .evict_inode = ext4_evict_inode, |
1101 | .sync_fs = ext4_sync_fs_nojournal, | ||
1100 | .put_super = ext4_put_super, | 1102 | .put_super = ext4_put_super, |
1101 | .statfs = ext4_statfs, | 1103 | .statfs = ext4_statfs, |
1102 | .remount_fs = ext4_remount, | 1104 | .remount_fs = ext4_remount, |
@@ -4553,6 +4555,7 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
4553 | { | 4555 | { |
4554 | int ret = 0; | 4556 | int ret = 0; |
4555 | tid_t target; | 4557 | tid_t target; |
4558 | bool needs_barrier = false; | ||
4556 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 4559 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
4557 | 4560 | ||
4558 | trace_ext4_sync_fs(sb, wait); | 4561 | trace_ext4_sync_fs(sb, wait); |
@@ -4563,10 +4566,41 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
4563 | * no dirty dquots | 4566 | * no dirty dquots |
4564 | */ | 4567 | */ |
4565 | dquot_writeback_dquots(sb, -1); | 4568 | dquot_writeback_dquots(sb, -1); |
4569 | /* | ||
4570 | * Data writeback is possible w/o journal transaction, so barrier must | ||
4571 | * being sent at the end of the function. But we can skip it if | ||
4572 | * transaction_commit will do it for us. | ||
4573 | */ | ||
4574 | target = jbd2_get_latest_transaction(sbi->s_journal); | ||
4575 | if (wait && sbi->s_journal->j_flags & JBD2_BARRIER && | ||
4576 | !jbd2_trans_will_send_data_barrier(sbi->s_journal, target)) | ||
4577 | needs_barrier = true; | ||
4578 | |||
4566 | if (jbd2_journal_start_commit(sbi->s_journal, &target)) { | 4579 | if (jbd2_journal_start_commit(sbi->s_journal, &target)) { |
4567 | if (wait) | 4580 | if (wait) |
4568 | jbd2_log_wait_commit(sbi->s_journal, target); | 4581 | ret = jbd2_log_wait_commit(sbi->s_journal, target); |
4582 | } | ||
4583 | if (needs_barrier) { | ||
4584 | int err; | ||
4585 | err = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL); | ||
4586 | if (!ret) | ||
4587 | ret = err; | ||
4569 | } | 4588 | } |
4589 | |||
4590 | return ret; | ||
4591 | } | ||
4592 | |||
4593 | static int ext4_sync_fs_nojournal(struct super_block *sb, int wait) | ||
4594 | { | ||
4595 | int ret = 0; | ||
4596 | |||
4597 | trace_ext4_sync_fs(sb, wait); | ||
4598 | flush_workqueue(EXT4_SB(sb)->rsv_conversion_wq); | ||
4599 | flush_workqueue(EXT4_SB(sb)->unrsv_conversion_wq); | ||
4600 | dquot_writeback_dquots(sb, -1); | ||
4601 | if (wait && test_opt(sb, BARRIER)) | ||
4602 | ret = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL); | ||
4603 | |||
4570 | return ret; | 4604 | return ret; |
4571 | } | 4605 | } |
4572 | 4606 | ||