Commit 7ffe1ea8 authored by Hidehiro Kawai's avatar Hidehiro Kawai Committed by Theodore Ts'o

ext4: add checks for errors from jbd2

If the journal has aborted due to a checkpointing failure, we
have to keep the contents of the journal space.  Otherwise, the
filesystem will lose uncheckpointed metadata completely and
become inconsistent.  To avoid this, we need to keep needs_recovery
flag if checkpoint has failed.

With this patch, ext4_put_super() detects a checkpointing failure
from the return value of journal_destroy(), then it invokes
ext4_abort() to make the filesystem read only and keep
needs_recovery flag.  Errors from jbd2_journal_flush() are also
handled by this patch in some places.
Signed-off-by: default avatarHidehiro Kawai <hidehiro.kawai.ez@hitachi.com>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 44519faf
...@@ -192,7 +192,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -192,7 +192,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case EXT4_IOC_GROUP_EXTEND: { case EXT4_IOC_GROUP_EXTEND: {
ext4_fsblk_t n_blocks_count; ext4_fsblk_t n_blocks_count;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int err; int err, err2;
if (!capable(CAP_SYS_RESOURCE)) if (!capable(CAP_SYS_RESOURCE))
return -EPERM; return -EPERM;
...@@ -206,8 +206,10 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -206,8 +206,10 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
jbd2_journal_flush(EXT4_SB(sb)->s_journal); err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
if (err == 0)
err = err2;
mnt_drop_write(filp->f_path.mnt); mnt_drop_write(filp->f_path.mnt);
return err; return err;
...@@ -215,7 +217,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -215,7 +217,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case EXT4_IOC_GROUP_ADD: { case EXT4_IOC_GROUP_ADD: {
struct ext4_new_group_data input; struct ext4_new_group_data input;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int err; int err, err2;
if (!capable(CAP_SYS_RESOURCE)) if (!capable(CAP_SYS_RESOURCE))
return -EPERM; return -EPERM;
...@@ -230,8 +232,10 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -230,8 +232,10 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
err = ext4_group_add(sb, &input); err = ext4_group_add(sb, &input);
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
jbd2_journal_flush(EXT4_SB(sb)->s_journal); err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
if (err == 0)
err = err2;
mnt_drop_write(filp->f_path.mnt); mnt_drop_write(filp->f_path.mnt);
return err; return err;
......
...@@ -507,7 +507,8 @@ static void ext4_put_super(struct super_block *sb) ...@@ -507,7 +507,8 @@ static void ext4_put_super(struct super_block *sb)
ext4_mb_release(sb); ext4_mb_release(sb);
ext4_ext_release(sb); ext4_ext_release(sb);
ext4_xattr_put_super(sb); ext4_xattr_put_super(sb);
jbd2_journal_destroy(sbi->s_journal); if (jbd2_journal_destroy(sbi->s_journal) < 0)
ext4_abort(sb, __func__, "Couldn't clean up the journal");
sbi->s_journal = NULL; sbi->s_journal = NULL;
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
...@@ -2853,7 +2854,9 @@ static void ext4_mark_recovery_complete(struct super_block *sb, ...@@ -2853,7 +2854,9 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
journal_t *journal = EXT4_SB(sb)->s_journal; journal_t *journal = EXT4_SB(sb)->s_journal;
jbd2_journal_lock_updates(journal); jbd2_journal_lock_updates(journal);
jbd2_journal_flush(journal); if (jbd2_journal_flush(journal) < 0)
goto out;
lock_super(sb); lock_super(sb);
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) && if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
sb->s_flags & MS_RDONLY) { sb->s_flags & MS_RDONLY) {
...@@ -2862,6 +2865,8 @@ static void ext4_mark_recovery_complete(struct super_block *sb, ...@@ -2862,6 +2865,8 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
ext4_commit_super(sb, es, 1); ext4_commit_super(sb, es, 1);
} }
unlock_super(sb); unlock_super(sb);
out:
jbd2_journal_unlock_updates(journal); jbd2_journal_unlock_updates(journal);
} }
...@@ -2962,7 +2967,13 @@ static void ext4_write_super_lockfs(struct super_block *sb) ...@@ -2962,7 +2967,13 @@ static void ext4_write_super_lockfs(struct super_block *sb)
/* Now we set up the journal barrier. */ /* Now we set up the journal barrier. */
jbd2_journal_lock_updates(journal); jbd2_journal_lock_updates(journal);
jbd2_journal_flush(journal);
/*
* We don't want to clear needs_recovery flag when we failed
* to flush the journal.
*/
if (jbd2_journal_flush(journal) < 0)
return;
/* Journal blocked and flushed, clear needs_recovery flag. */ /* Journal blocked and flushed, clear needs_recovery flag. */
EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
...@@ -3402,8 +3413,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, ...@@ -3402,8 +3413,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
* otherwise be livelocked... * otherwise be livelocked...
*/ */
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
jbd2_journal_flush(EXT4_SB(sb)->s_journal); err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
if (err) {
path_put(&nd.path);
return err;
}
} }
err = vfs_quota_on_path(sb, type, format_id, &nd.path); err = vfs_quota_on_path(sb, type, format_id, &nd.path);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment