aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2013-06-12 22:38:04 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-06-12 22:38:04 -0400
commit4418e14112e3ca85e8492a4489a3552b0cc526a8 (patch)
tree93abfabff161cc2f5b09d7aaf6aa4ae09ba13c7b /fs/ext4
parent06a407f13daf9e48f0ef7189c7e54082b53940c7 (diff)
ext4: Fix fsync error handling after filesystem abort
If filesystem was aborted after inode's write back is complete but before its metadata was updated we may return success results in data loss. In order to handle fs abort correctly we have to check fs state once we discover that it is in MS_RDONLY state Test case: http://patchwork.ozlabs.org/patch/244297 Reviewed-by: Jan Kara <jack@suse.cz> 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/fsync.c7
-rw-r--r--fs/ext4/super.c12
2 files changed, 17 insertions, 2 deletions
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index fc938ebbddec..a8bc47f75fa0 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -98,8 +98,13 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
98 98
99 trace_ext4_sync_file_enter(file, datasync); 99 trace_ext4_sync_file_enter(file, datasync);
100 100
101 if (inode->i_sb->s_flags & MS_RDONLY) 101 if (inode->i_sb->s_flags & MS_RDONLY) {
102 /* Make sure that we read updated s_mount_flags value */
103 smp_rmb();
104 if (EXT4_SB(inode->i_sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
105 ret = -EROFS;
102 goto out; 106 goto out;
107 }
103 108
104 if (!journal) { 109 if (!journal) {
105 ret = generic_file_fsync(file, start, end, datasync); 110 ret = generic_file_fsync(file, start, end, datasync);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 0f77c2e4b888..eb52a7be1fc1 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -399,6 +399,11 @@ static void ext4_handle_error(struct super_block *sb)
399 } 399 }
400 if (test_opt(sb, ERRORS_RO)) { 400 if (test_opt(sb, ERRORS_RO)) {
401 ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); 401 ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
402 /*
403 * Make sure updated value of ->s_mount_flags will be visible
404 * before ->s_flags update
405 */
406 smp_wmb();
402 sb->s_flags |= MS_RDONLY; 407 sb->s_flags |= MS_RDONLY;
403 } 408 }
404 if (test_opt(sb, ERRORS_PANIC)) 409 if (test_opt(sb, ERRORS_PANIC))
@@ -571,8 +576,13 @@ void __ext4_abort(struct super_block *sb, const char *function,
571 576
572 if ((sb->s_flags & MS_RDONLY) == 0) { 577 if ((sb->s_flags & MS_RDONLY) == 0) {
573 ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); 578 ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
574 sb->s_flags |= MS_RDONLY;
575 EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED; 579 EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
580 /*
581 * Make sure updated value of ->s_mount_flags will be visible
582 * before ->s_flags update
583 */
584 smp_wmb();
585 sb->s_flags |= MS_RDONLY;
576 if (EXT4_SB(sb)->s_journal) 586 if (EXT4_SB(sb)->s_journal)
577 jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); 587 jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
578 save_error_info(sb, function, line); 588 save_error_info(sb, function, line);