ext3: add checks for errors from jbd
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, ext3_put_super() detects a checkpointing failure from the return value of journal_destroy(), then it invokes ext3_abort() to make the filesystem read only and keep needs_recovery flag. Errors from journal_flush() are also handled by this patch in some places. Signed-off-by: Hidehiro Kawai <hidehiro.kawai.ez@hitachi.com> Cc: Jan Kara <jack@ucw.cz> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: <linux-ext4@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
4afe978530
commit
2d7c820e56
2 changed files with 27 additions and 8 deletions
|
@ -239,7 +239,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
|
||||||
case EXT3_IOC_GROUP_EXTEND: {
|
case EXT3_IOC_GROUP_EXTEND: {
|
||||||
ext3_fsblk_t n_blocks_count;
|
ext3_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;
|
||||||
|
@ -254,8 +254,10 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
|
||||||
}
|
}
|
||||||
err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count);
|
err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count);
|
||||||
journal_lock_updates(EXT3_SB(sb)->s_journal);
|
journal_lock_updates(EXT3_SB(sb)->s_journal);
|
||||||
journal_flush(EXT3_SB(sb)->s_journal);
|
err2 = journal_flush(EXT3_SB(sb)->s_journal);
|
||||||
journal_unlock_updates(EXT3_SB(sb)->s_journal);
|
journal_unlock_updates(EXT3_SB(sb)->s_journal);
|
||||||
|
if (err == 0)
|
||||||
|
err = err2;
|
||||||
group_extend_out:
|
group_extend_out:
|
||||||
mnt_drop_write(filp->f_path.mnt);
|
mnt_drop_write(filp->f_path.mnt);
|
||||||
return err;
|
return err;
|
||||||
|
@ -263,7 +265,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
|
||||||
case EXT3_IOC_GROUP_ADD: {
|
case EXT3_IOC_GROUP_ADD: {
|
||||||
struct ext3_new_group_data input;
|
struct ext3_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;
|
||||||
|
@ -280,8 +282,10 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
|
||||||
|
|
||||||
err = ext3_group_add(sb, &input);
|
err = ext3_group_add(sb, &input);
|
||||||
journal_lock_updates(EXT3_SB(sb)->s_journal);
|
journal_lock_updates(EXT3_SB(sb)->s_journal);
|
||||||
journal_flush(EXT3_SB(sb)->s_journal);
|
err2 = journal_flush(EXT3_SB(sb)->s_journal);
|
||||||
journal_unlock_updates(EXT3_SB(sb)->s_journal);
|
journal_unlock_updates(EXT3_SB(sb)->s_journal);
|
||||||
|
if (err == 0)
|
||||||
|
err = err2;
|
||||||
group_add_out:
|
group_add_out:
|
||||||
mnt_drop_write(filp->f_path.mnt);
|
mnt_drop_write(filp->f_path.mnt);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -393,7 +393,8 @@ static void ext3_put_super (struct super_block * sb)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ext3_xattr_put_super(sb);
|
ext3_xattr_put_super(sb);
|
||||||
journal_destroy(sbi->s_journal);
|
if (journal_destroy(sbi->s_journal) < 0)
|
||||||
|
ext3_abort(sb, __func__, "Couldn't clean up the journal");
|
||||||
if (!(sb->s_flags & MS_RDONLY)) {
|
if (!(sb->s_flags & MS_RDONLY)) {
|
||||||
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
|
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
|
||||||
es->s_state = cpu_to_le16(sbi->s_mount_state);
|
es->s_state = cpu_to_le16(sbi->s_mount_state);
|
||||||
|
@ -2296,7 +2297,9 @@ static void ext3_mark_recovery_complete(struct super_block * sb,
|
||||||
journal_t *journal = EXT3_SB(sb)->s_journal;
|
journal_t *journal = EXT3_SB(sb)->s_journal;
|
||||||
|
|
||||||
journal_lock_updates(journal);
|
journal_lock_updates(journal);
|
||||||
journal_flush(journal);
|
if (journal_flush(journal) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
lock_super(sb);
|
lock_super(sb);
|
||||||
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
|
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
|
||||||
sb->s_flags & MS_RDONLY) {
|
sb->s_flags & MS_RDONLY) {
|
||||||
|
@ -2305,6 +2308,8 @@ static void ext3_mark_recovery_complete(struct super_block * sb,
|
||||||
ext3_commit_super(sb, es, 1);
|
ext3_commit_super(sb, es, 1);
|
||||||
}
|
}
|
||||||
unlock_super(sb);
|
unlock_super(sb);
|
||||||
|
|
||||||
|
out:
|
||||||
journal_unlock_updates(journal);
|
journal_unlock_updates(journal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2404,7 +2409,13 @@ static void ext3_write_super_lockfs(struct super_block *sb)
|
||||||
|
|
||||||
/* Now we set up the journal barrier. */
|
/* Now we set up the journal barrier. */
|
||||||
journal_lock_updates(journal);
|
journal_lock_updates(journal);
|
||||||
journal_flush(journal);
|
|
||||||
|
/*
|
||||||
|
* We don't want to clear needs_recovery flag when we failed
|
||||||
|
* to flush the journal.
|
||||||
|
*/
|
||||||
|
if (journal_flush(journal) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Journal blocked and flushed, clear needs_recovery flag. */
|
/* Journal blocked and flushed, clear needs_recovery flag. */
|
||||||
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
|
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
|
||||||
|
@ -2822,8 +2833,12 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
|
||||||
* otherwise be livelocked...
|
* otherwise be livelocked...
|
||||||
*/
|
*/
|
||||||
journal_lock_updates(EXT3_SB(sb)->s_journal);
|
journal_lock_updates(EXT3_SB(sb)->s_journal);
|
||||||
journal_flush(EXT3_SB(sb)->s_journal);
|
err = journal_flush(EXT3_SB(sb)->s_journal);
|
||||||
journal_unlock_updates(EXT3_SB(sb)->s_journal);
|
journal_unlock_updates(EXT3_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);
|
||||||
|
|
Loading…
Reference in a new issue