Commit 0bc9bc1d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull ext4 fixes from Ted Ts'o:
 "A number of bug fixes for ext4:

   - Fix for the new fast_commit feature

   - Fix some error handling codepaths in whiteout handling and
     mountpoint sampling

   - Fix how we write ext4_error information so it goes through the
     journal when journalling is active, to avoid races that can lead to
     lost error information, superblock checksum failures, or DIF/DIX
     features"

* tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: remove expensive flush on fast commit
  ext4: fix bug for rename with RENAME_WHITEOUT
  ext4: fix wrong list_splice in ext4_fc_cleanup
  ext4: use IS_ERR instead of IS_ERR_OR_NULL and set inode null when IS_ERR
  ext4: don't leak old mountpoint samples
  ext4: drop ext4_handle_dirty_super()
  ext4: fix superblock checksum failure when setting password salt
  ext4: use sbi instead of EXT4_SB(sb) in ext4_update_super()
  ext4: save error info to sb through journal if available
  ext4: protect superblock modifications with a buffer lock
  ext4: drop sync argument of ext4_commit_super()
  ext4: combine ext4_handle_error() and save_error_info()
parents 7cd3c412 e9f53353
...@@ -372,20 +372,3 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, ...@@ -372,20 +372,3 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
} }
return err; return err;
} }
int __ext4_handle_dirty_super(const char *where, unsigned int line,
handle_t *handle, struct super_block *sb)
{
struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
int err = 0;
ext4_superblock_csum_set(sb);
if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh);
if (err)
ext4_journal_abort_handle(where, line, __func__,
bh, handle, err);
} else
mark_buffer_dirty(bh);
return err;
}
...@@ -244,9 +244,6 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, ...@@ -244,9 +244,6 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
handle_t *handle, struct inode *inode, handle_t *handle, struct inode *inode,
struct buffer_head *bh); struct buffer_head *bh);
int __ext4_handle_dirty_super(const char *where, unsigned int line,
handle_t *handle, struct super_block *sb);
#define ext4_journal_get_write_access(handle, bh) \ #define ext4_journal_get_write_access(handle, bh) \
__ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh)) __ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh))
#define ext4_forget(handle, is_metadata, inode, bh, block_nr) \ #define ext4_forget(handle, is_metadata, inode, bh, block_nr) \
...@@ -257,8 +254,6 @@ int __ext4_handle_dirty_super(const char *where, unsigned int line, ...@@ -257,8 +254,6 @@ int __ext4_handle_dirty_super(const char *where, unsigned int line,
#define ext4_handle_dirty_metadata(handle, inode, bh) \ #define ext4_handle_dirty_metadata(handle, inode, bh) \
__ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \ __ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \
(bh)) (bh))
#define ext4_handle_dirty_super(handle, sb) \
__ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb))
handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line, handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
int type, int blocks, int rsv_blocks, int type, int blocks, int rsv_blocks,
......
...@@ -604,13 +604,13 @@ void ext4_fc_track_range(handle_t *handle, struct inode *inode, ext4_lblk_t star ...@@ -604,13 +604,13 @@ void ext4_fc_track_range(handle_t *handle, struct inode *inode, ext4_lblk_t star
trace_ext4_fc_track_range(inode, start, end, ret); trace_ext4_fc_track_range(inode, start, end, ret);
} }
static void ext4_fc_submit_bh(struct super_block *sb) static void ext4_fc_submit_bh(struct super_block *sb, bool is_tail)
{ {
int write_flags = REQ_SYNC; int write_flags = REQ_SYNC;
struct buffer_head *bh = EXT4_SB(sb)->s_fc_bh; struct buffer_head *bh = EXT4_SB(sb)->s_fc_bh;
/* TODO: REQ_FUA | REQ_PREFLUSH is unnecessarily expensive. */ /* Add REQ_FUA | REQ_PREFLUSH only its tail */
if (test_opt(sb, BARRIER)) if (test_opt(sb, BARRIER) && is_tail)
write_flags |= REQ_FUA | REQ_PREFLUSH; write_flags |= REQ_FUA | REQ_PREFLUSH;
lock_buffer(bh); lock_buffer(bh);
set_buffer_dirty(bh); set_buffer_dirty(bh);
...@@ -684,7 +684,7 @@ static u8 *ext4_fc_reserve_space(struct super_block *sb, int len, u32 *crc) ...@@ -684,7 +684,7 @@ static u8 *ext4_fc_reserve_space(struct super_block *sb, int len, u32 *crc)
*crc = ext4_chksum(sbi, *crc, tl, sizeof(*tl)); *crc = ext4_chksum(sbi, *crc, tl, sizeof(*tl));
if (pad_len > 0) if (pad_len > 0)
ext4_fc_memzero(sb, tl + 1, pad_len, crc); ext4_fc_memzero(sb, tl + 1, pad_len, crc);
ext4_fc_submit_bh(sb); ext4_fc_submit_bh(sb, false);
ret = jbd2_fc_get_buf(EXT4_SB(sb)->s_journal, &bh); ret = jbd2_fc_get_buf(EXT4_SB(sb)->s_journal, &bh);
if (ret) if (ret)
...@@ -741,7 +741,7 @@ static int ext4_fc_write_tail(struct super_block *sb, u32 crc) ...@@ -741,7 +741,7 @@ static int ext4_fc_write_tail(struct super_block *sb, u32 crc)
tail.fc_crc = cpu_to_le32(crc); tail.fc_crc = cpu_to_le32(crc);
ext4_fc_memcpy(sb, dst, &tail.fc_crc, sizeof(tail.fc_crc), NULL); ext4_fc_memcpy(sb, dst, &tail.fc_crc, sizeof(tail.fc_crc), NULL);
ext4_fc_submit_bh(sb); ext4_fc_submit_bh(sb, true);
return 0; return 0;
} }
...@@ -1268,7 +1268,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full) ...@@ -1268,7 +1268,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
list_splice_init(&sbi->s_fc_dentry_q[FC_Q_STAGING], list_splice_init(&sbi->s_fc_dentry_q[FC_Q_STAGING],
&sbi->s_fc_dentry_q[FC_Q_MAIN]); &sbi->s_fc_dentry_q[FC_Q_MAIN]);
list_splice_init(&sbi->s_fc_q[FC_Q_STAGING], list_splice_init(&sbi->s_fc_q[FC_Q_STAGING],
&sbi->s_fc_q[FC_Q_STAGING]); &sbi->s_fc_q[FC_Q_MAIN]);
ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING); ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
...@@ -1318,14 +1318,14 @@ static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl) ...@@ -1318,14 +1318,14 @@ static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl)
entry.len = darg.dname_len; entry.len = darg.dname_len;
inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL); inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(inode)) { if (IS_ERR(inode)) {
jbd_debug(1, "Inode %d not found", darg.ino); jbd_debug(1, "Inode %d not found", darg.ino);
return 0; return 0;
} }
old_parent = ext4_iget(sb, darg.parent_ino, old_parent = ext4_iget(sb, darg.parent_ino,
EXT4_IGET_NORMAL); EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(old_parent)) { if (IS_ERR(old_parent)) {
jbd_debug(1, "Dir with inode %d not found", darg.parent_ino); jbd_debug(1, "Dir with inode %d not found", darg.parent_ino);
iput(inode); iput(inode);
return 0; return 0;
...@@ -1410,7 +1410,7 @@ static int ext4_fc_replay_link(struct super_block *sb, struct ext4_fc_tl *tl) ...@@ -1410,7 +1410,7 @@ static int ext4_fc_replay_link(struct super_block *sb, struct ext4_fc_tl *tl)
darg.parent_ino, darg.dname_len); darg.parent_ino, darg.dname_len);
inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL); inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(inode)) { if (IS_ERR(inode)) {
jbd_debug(1, "Inode not found."); jbd_debug(1, "Inode not found.");
return 0; return 0;
} }
...@@ -1466,10 +1466,11 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl) ...@@ -1466,10 +1466,11 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
trace_ext4_fc_replay(sb, tag, ino, 0, 0); trace_ext4_fc_replay(sb, tag, ino, 0, 0);
inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL); inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
if (!IS_ERR_OR_NULL(inode)) { if (!IS_ERR(inode)) {
ext4_ext_clear_bb(inode); ext4_ext_clear_bb(inode);
iput(inode); iput(inode);
} }
inode = NULL;
ext4_fc_record_modified_inode(sb, ino); ext4_fc_record_modified_inode(sb, ino);
...@@ -1512,7 +1513,7 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl) ...@@ -1512,7 +1513,7 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
/* Given that we just wrote the inode on disk, this SHOULD succeed. */ /* Given that we just wrote the inode on disk, this SHOULD succeed. */
inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL); inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(inode)) { if (IS_ERR(inode)) {
jbd_debug(1, "Inode not found."); jbd_debug(1, "Inode not found.");
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -1564,7 +1565,7 @@ static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl) ...@@ -1564,7 +1565,7 @@ static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl)
goto out; goto out;
inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL); inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(inode)) { if (IS_ERR(inode)) {
jbd_debug(1, "inode %d not found.", darg.ino); jbd_debug(1, "inode %d not found.", darg.ino);
inode = NULL; inode = NULL;
ret = -EINVAL; ret = -EINVAL;
...@@ -1577,7 +1578,7 @@ static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl) ...@@ -1577,7 +1578,7 @@ static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl)
* dot and dot dot dirents are setup properly. * dot and dot dot dirents are setup properly.
*/ */
dir = ext4_iget(sb, darg.parent_ino, EXT4_IGET_NORMAL); dir = ext4_iget(sb, darg.parent_ino, EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(dir)) { if (IS_ERR(dir)) {
jbd_debug(1, "Dir %d not found.", darg.ino); jbd_debug(1, "Dir %d not found.", darg.ino);
goto out; goto out;
} }
...@@ -1653,7 +1654,7 @@ static int ext4_fc_replay_add_range(struct super_block *sb, ...@@ -1653,7 +1654,7 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
inode = ext4_iget(sb, le32_to_cpu(fc_add_ex->fc_ino), inode = ext4_iget(sb, le32_to_cpu(fc_add_ex->fc_ino),
EXT4_IGET_NORMAL); EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(inode)) { if (IS_ERR(inode)) {
jbd_debug(1, "Inode not found."); jbd_debug(1, "Inode not found.");
return 0; return 0;
} }
...@@ -1777,7 +1778,7 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl) ...@@ -1777,7 +1778,7 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl)
le32_to_cpu(lrange->fc_ino), cur, remaining); le32_to_cpu(lrange->fc_ino), cur, remaining);
inode = ext4_iget(sb, le32_to_cpu(lrange->fc_ino), EXT4_IGET_NORMAL); inode = ext4_iget(sb, le32_to_cpu(lrange->fc_ino), EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(inode)) { if (IS_ERR(inode)) {
jbd_debug(1, "Inode %d not found", le32_to_cpu(lrange->fc_ino)); jbd_debug(1, "Inode %d not found", le32_to_cpu(lrange->fc_ino));
return 0; return 0;
} }
...@@ -1832,7 +1833,7 @@ static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb) ...@@ -1832,7 +1833,7 @@ static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
for (i = 0; i < state->fc_modified_inodes_used; i++) { for (i = 0; i < state->fc_modified_inodes_used; i++) {
inode = ext4_iget(sb, state->fc_modified_inodes[i], inode = ext4_iget(sb, state->fc_modified_inodes[i],
EXT4_IGET_NORMAL); EXT4_IGET_NORMAL);
if (IS_ERR_OR_NULL(inode)) { if (IS_ERR(inode)) {
jbd_debug(1, "Inode %d not found.", jbd_debug(1, "Inode %d not found.",
state->fc_modified_inodes[i]); state->fc_modified_inodes[i]);
continue; continue;
...@@ -1849,7 +1850,7 @@ static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb) ...@@ -1849,7 +1850,7 @@ static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
if (ret > 0) { if (ret > 0) {
path = ext4_find_extent(inode, map.m_lblk, NULL, 0); path = ext4_find_extent(inode, map.m_lblk, NULL, 0);
if (!IS_ERR_OR_NULL(path)) { if (!IS_ERR(path)) {
for (j = 0; j < path->p_depth; j++) for (j = 0; j < path->p_depth; j++)
ext4_mb_mark_bb(inode->i_sb, ext4_mb_mark_bb(inode->i_sb,
path[j].p_block, 1, 1); path[j].p_block, 1, 1);
......
...@@ -809,9 +809,12 @@ static int ext4_sample_last_mounted(struct super_block *sb, ...@@ -809,9 +809,12 @@ static int ext4_sample_last_mounted(struct super_block *sb,
err = ext4_journal_get_write_access(handle, sbi->s_sbh); err = ext4_journal_get_write_access(handle, sbi->s_sbh);
if (err) if (err)
goto out_journal; goto out_journal;
strlcpy(sbi->s_es->s_last_mounted, cp, lock_buffer(sbi->s_sbh);
strncpy(sbi->s_es->s_last_mounted, cp,
sizeof(sbi->s_es->s_last_mounted)); sizeof(sbi->s_es->s_last_mounted));
ext4_handle_dirty_super(handle, sb); ext4_superblock_csum_set(sb);
unlock_buffer(sbi->s_sbh);
ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
out_journal: out_journal:
ext4_journal_stop(handle); ext4_journal_stop(handle);
out: out:
......
...@@ -5150,9 +5150,13 @@ static int ext4_do_update_inode(handle_t *handle, ...@@ -5150,9 +5150,13 @@ static int ext4_do_update_inode(handle_t *handle,
err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
if (err) if (err)
goto out_brelse; goto out_brelse;
lock_buffer(EXT4_SB(sb)->s_sbh);
ext4_set_feature_large_file(sb); ext4_set_feature_large_file(sb);
ext4_superblock_csum_set(sb);
unlock_buffer(EXT4_SB(sb)->s_sbh);
ext4_handle_sync(handle); ext4_handle_sync(handle);
err = ext4_handle_dirty_super(handle, sb); err = ext4_handle_dirty_metadata(handle, NULL,
EXT4_SB(sb)->s_sbh);
} }
ext4_update_inode_fsync_trans(handle, inode, need_datasync); ext4_update_inode_fsync_trans(handle, inode, need_datasync);
out_brelse: out_brelse:
......
...@@ -1157,7 +1157,10 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -1157,7 +1157,10 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
err = ext4_journal_get_write_access(handle, sbi->s_sbh); err = ext4_journal_get_write_access(handle, sbi->s_sbh);
if (err) if (err)
goto pwsalt_err_journal; goto pwsalt_err_journal;
lock_buffer(sbi->s_sbh);
generate_random_uuid(sbi->s_es->s_encrypt_pw_salt); generate_random_uuid(sbi->s_es->s_encrypt_pw_salt);
ext4_superblock_csum_set(sb);
unlock_buffer(sbi->s_sbh);
err = ext4_handle_dirty_metadata(handle, NULL, err = ext4_handle_dirty_metadata(handle, NULL,
sbi->s_sbh); sbi->s_sbh);
pwsalt_err_journal: pwsalt_err_journal:
......
...@@ -2976,14 +2976,17 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) ...@@ -2976,14 +2976,17 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
(le32_to_cpu(sbi->s_es->s_inodes_count))) { (le32_to_cpu(sbi->s_es->s_inodes_count))) {
/* Insert this inode at the head of the on-disk orphan list */ /* Insert this inode at the head of the on-disk orphan list */
NEXT_ORPHAN(inode) = le32_to_cpu(sbi->s_es->s_last_orphan); NEXT_ORPHAN(inode) = le32_to_cpu(sbi->s_es->s_last_orphan);
lock_buffer(sbi->s_sbh);
sbi->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); sbi->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
ext4_superblock_csum_set(sb);
unlock_buffer(sbi->s_sbh);
dirty = true; dirty = true;
} }
list_add(&EXT4_I(inode)->i_orphan, &sbi->s_orphan); list_add(&EXT4_I(inode)->i_orphan, &sbi->s_orphan);
mutex_unlock(&sbi->s_orphan_lock); mutex_unlock(&sbi->s_orphan_lock);
if (dirty) { if (dirty) {
err = ext4_handle_dirty_super(handle, sb); err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
rc = ext4_mark_iloc_dirty(handle, inode, &iloc); rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
if (!err) if (!err)
err = rc; err = rc;
...@@ -3059,9 +3062,12 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) ...@@ -3059,9 +3062,12 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
mutex_unlock(&sbi->s_orphan_lock); mutex_unlock(&sbi->s_orphan_lock);
goto out_brelse; goto out_brelse;
} }
lock_buffer(sbi->s_sbh);
sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);
ext4_superblock_csum_set(inode->i_sb);
unlock_buffer(sbi->s_sbh);
mutex_unlock(&sbi->s_orphan_lock); mutex_unlock(&sbi->s_orphan_lock);
err = ext4_handle_dirty_super(handle, inode->i_sb); err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
} else { } else {
struct ext4_iloc iloc2; struct ext4_iloc iloc2;
struct inode *i_prev = struct inode *i_prev =
...@@ -3593,9 +3599,6 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent, ...@@ -3593,9 +3599,6 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
return retval2; return retval2;
} }
} }
brelse(ent->bh);
ent->bh = NULL;
return retval; return retval;
} }
...@@ -3794,6 +3797,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -3794,6 +3797,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
} }
old_file_type = old.de->file_type;
if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir))
ext4_handle_sync(handle); ext4_handle_sync(handle);
...@@ -3821,7 +3825,6 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -3821,7 +3825,6 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
force_reread = (new.dir->i_ino == old.dir->i_ino && force_reread = (new.dir->i_ino == old.dir->i_ino &&
ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA));
old_file_type = old.de->file_type;
if (whiteout) { if (whiteout) {
/* /*
* Do this before adding a new entry, so the old entry is sure * Do this before adding a new entry, so the old entry is sure
...@@ -3919,15 +3922,19 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -3919,15 +3922,19 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
retval = 0; retval = 0;
end_rename: end_rename:
brelse(old.dir_bh);
brelse(old.bh);
brelse(new.bh);
if (whiteout) { if (whiteout) {
if (retval) if (retval) {
ext4_setent(handle, &old,
old.inode->i_ino, old_file_type);
drop_nlink(whiteout); drop_nlink(whiteout);
}
unlock_new_inode(whiteout); unlock_new_inode(whiteout);
iput(whiteout); iput(whiteout);
} }
brelse(old.dir_bh);
brelse(old.bh);
brelse(new.bh);
if (handle) if (handle)
ext4_journal_stop(handle); ext4_journal_stop(handle);
return retval; return retval;
......
...@@ -899,8 +899,11 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, ...@@ -899,8 +899,11 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
EXT4_SB(sb)->s_gdb_count++; EXT4_SB(sb)->s_gdb_count++;
ext4_kvfree_array_rcu(o_group_desc); ext4_kvfree_array_rcu(o_group_desc);
lock_buffer(EXT4_SB(sb)->s_sbh);
le16_add_cpu(&es->s_reserved_gdt_blocks, -1); le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
err = ext4_handle_dirty_super(handle, sb); ext4_superblock_csum_set(sb);
unlock_buffer(EXT4_SB(sb)->s_sbh);
err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
if (err) if (err)
ext4_std_error(sb, err); ext4_std_error(sb, err);
return err; return err;
...@@ -1384,6 +1387,7 @@ static void ext4_update_super(struct super_block *sb, ...@@ -1384,6 +1387,7 @@ static void ext4_update_super(struct super_block *sb,
reserved_blocks *= blocks_count; reserved_blocks *= blocks_count;
do_div(reserved_blocks, 100); do_div(reserved_blocks, 100);
lock_buffer(sbi->s_sbh);
ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count); ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count);
ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + free_blocks); ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + free_blocks);
le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) * le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) *
...@@ -1421,6 +1425,8 @@ static void ext4_update_super(struct super_block *sb, ...@@ -1421,6 +1425,8 @@ static void ext4_update_super(struct super_block *sb,
* active. */ * active. */
ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) + ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +
reserved_blocks); reserved_blocks);
ext4_superblock_csum_set(sb);
unlock_buffer(sbi->s_sbh);
/* Update the free space counts */ /* Update the free space counts */
percpu_counter_add(&sbi->s_freeclusters_counter, percpu_counter_add(&sbi->s_freeclusters_counter,
...@@ -1515,7 +1521,7 @@ static int ext4_flex_group_add(struct super_block *sb, ...@@ -1515,7 +1521,7 @@ static int ext4_flex_group_add(struct super_block *sb,
ext4_update_super(sb, flex_gd); ext4_update_super(sb, flex_gd);
err = ext4_handle_dirty_super(handle, sb); err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
exit_journal: exit_journal:
err2 = ext4_journal_stop(handle); err2 = ext4_journal_stop(handle);
...@@ -1717,15 +1723,18 @@ static int ext4_group_extend_no_check(struct super_block *sb, ...@@ -1717,15 +1723,18 @@ static int ext4_group_extend_no_check(struct super_block *sb,
goto errout; goto errout;
} }
lock_buffer(EXT4_SB(sb)->s_sbh);
ext4_blocks_count_set(es, o_blocks_count + add); ext4_blocks_count_set(es, o_blocks_count + add);
ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + add); ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + add);
ext4_superblock_csum_set(sb);
unlock_buffer(EXT4_SB(sb)->s_sbh);
ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count, ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
o_blocks_count + add); o_blocks_count + add);
/* We add the blocks to the bitmap and set the group need init bit */ /* We add the blocks to the bitmap and set the group need init bit */
err = ext4_group_add_blocks(handle, sb, o_blocks_count, add); err = ext4_group_add_blocks(handle, sb, o_blocks_count, add);
if (err) if (err)
goto errout; goto errout;
ext4_handle_dirty_super(handle, sb); ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
ext4_debug("freed blocks %llu through %llu\n", o_blocks_count, ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
o_blocks_count + add); o_blocks_count + add);
errout: errout:
...@@ -1874,12 +1883,15 @@ static int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode) ...@@ -1874,12 +1883,15 @@ static int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode)
if (err) if (err)
goto errout; goto errout;
lock_buffer(sbi->s_sbh);
ext4_clear_feature_resize_inode(sb); ext4_clear_feature_resize_inode(sb);
ext4_set_feature_meta_bg(sb); ext4_set_feature_meta_bg(sb);
sbi->s_es->s_first_meta_bg = sbi->s_es->s_first_meta_bg =
cpu_to_le32(num_desc_blocks(sb, sbi->s_groups_count)); cpu_to_le32(num_desc_blocks(sb, sbi->s_groups_count));
ext4_superblock_csum_set(sb);
unlock_buffer(sbi->s_sbh);
err = ext4_handle_dirty_super(handle, sb); err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
if (err) { if (err) {
ext4_std_error(sb, err); ext4_std_error(sb, err);
goto errout; goto errout;
......
...@@ -65,7 +65,8 @@ static struct ratelimit_state ext4_mount_msg_ratelimit; ...@@ -65,7 +65,8 @@ static struct ratelimit_state ext4_mount_msg_ratelimit;
static int ext4_load_journal(struct super_block *, struct ext4_super_block *, static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
unsigned long journal_devnum); unsigned long journal_devnum);
static int ext4_show_options(struct seq_file *seq, struct dentry *root); static int ext4_show_options(struct seq_file *seq, struct dentry *root);
static int ext4_commit_super(struct super_block *sb, int sync); static void ext4_update_super(struct super_block *sb);
static int ext4_commit_super(struct super_block *sb);
static int ext4_mark_recovery_complete(struct super_block *sb, static int ext4_mark_recovery_complete(struct super_block *sb,
struct ext4_super_block *es); struct ext4_super_block *es);
static int ext4_clear_journal_err(struct super_block *sb, static int ext4_clear_journal_err(struct super_block *sb,
...@@ -586,15 +587,12 @@ static int ext4_errno_to_code(int errno) ...@@ -586,15 +587,12 @@ static int ext4_errno_to_code(int errno)
return EXT4_ERR_UNKNOWN; return EXT4_ERR_UNKNOWN;
} }
static void __save_error_info(struct super_block *sb, int error, static void save_error_info(struct super_block *sb, int error,
__u32 ino, __u64 block, __u32 ino, __u64 block,
const char *func, unsigned int line) const char *func, unsigned int line)
{ {
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
if (bdev_read_only(sb->s_bdev))
return;
/* We default to EFSCORRUPTED error... */ /* We default to EFSCORRUPTED error... */
if (error == 0) if (error == 0)
error = EFSCORRUPTED; error = EFSCORRUPTED;
...@@ -618,15 +616,6 @@ static void __save_error_info(struct super_block *sb, int error, ...@@ -618,15 +616,6 @@ static void __save_error_info(struct super_block *sb, int error,
spin_unlock(&sbi->s_error_lock); spin_unlock(&sbi->s_error_lock);
} }
static void save_error_info(struct super_block *sb, int error,
__u32 ino, __u64 block,
const char *func, unsigned int line)
{
__save_error_info(sb, error, ino, block, func, line);
if (!bdev_read_only(sb->s_bdev))
ext4_commit_super(sb, 1);
}
/* Deal with the reporting of failure conditions on a filesystem such as /* Deal with the reporting of failure conditions on a filesystem such as
* inconsistencies detected or read IO failures. * inconsistencies detected or read IO failures.
* *
...@@ -647,19 +636,40 @@ static void save_error_info(struct super_block *sb, int error, ...@@ -647,19 +636,40 @@ static void save_error_info(struct super_block *sb, int error,
* used to deal with unrecoverable failures such as journal IO errors or ENOMEM * used to deal with unrecoverable failures such as journal IO errors or ENOMEM
* at a critical moment in log management. * at a critical moment in log management.
*/ */
static void ext4_handle_error(struct super_block *sb, bool force_ro) static void ext4_handle_error(struct super_block *sb, bool force_ro, int error,
__u32 ino, __u64 block,
const char *func, unsigned int line)
{ {
journal_t *journal = EXT4_SB(sb)->s_journal; journal_t *journal = EXT4_SB(sb)->s_journal;
bool continue_fs = !force_ro && test_opt(sb, ERRORS_CONT);
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
if (test_opt(sb, WARN_ON_ERROR)) if (test_opt(sb, WARN_ON_ERROR))
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
if (sb_rdonly(sb) || (!force_ro && test_opt(sb, ERRORS_CONT))) if (!continue_fs && !sb_rdonly(sb)) {
return;
ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED); ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED);
if (journal) if (journal)
jbd2_journal_abort(journal, -EIO); jbd2_journal_abort(journal, -EIO);
}
if (!bdev_read_only(sb->s_bdev)) {
save_error_info(sb, error, ino, block, func, line);
/*
* In case the fs should keep running, we need to writeout
* superblock through the journal. Due to lock ordering
* constraints, it may not be safe to do it right here so we
* defer superblock flushing to a workqueue.
*/
if (continue_fs)
schedule_work(&EXT4_SB(sb)->s_error_work);
else
ext4_commit_super(sb);
}
if (sb_rdonly(sb) || continue_fs)
return;
/* /*
* We force ERRORS_RO behavior when system is rebooting. Otherwise we * We force ERRORS_RO behavior when system is rebooting. Otherwise we
* could panic during 'reboot -f' as the underlying device got already * could panic during 'reboot -f' as the underlying device got already
...@@ -682,8 +692,39 @@ static void flush_stashed_error_work(struct work_struct *work) ...@@ -682,8 +692,39 @@ static void flush_stashed_error_work(struct work_struct *work)
{ {
struct ext4_sb_info *sbi = container_of(work, struct ext4_sb_info, struct ext4_sb_info *sbi = container_of(work, struct ext4_sb_info,
s_error_work); s_error_work);
journal_t *journal = sbi->s_journal;
handle_t *handle;
ext4_commit_super(sbi->s_sb, 1); /*
* If the journal is still running, we have to write out superblock
* through the journal to avoid collisions of other journalled sb
* updates.
*
* We use directly jbd2 functions here to avoid recursing back into
* ext4 error handling code during handling of previous errors.
*/
if (!sb_rdonly(sbi->s_sb) && journal) {
handle = jbd2_journal_start(journal, 1);
if (IS_ERR(handle))
goto write_directly;
if (jbd2_journal_get_write_access(handle, sbi->s_sbh)) {
jbd2_journal_stop(handle);
goto write_directly;
}
ext4_update_super(sbi->s_sb);
if (jbd2_journal_dirty_metadata(handle, sbi->s_sbh)) {
jbd2_journal_stop(handle);
goto write_directly;
}
jbd2_journal_stop(handle);
return;
}
write_directly:
/*
* Write through journal failed. Write sb directly to get error info
* out and hope for the best.
*/
ext4_commit_super(sbi->s_sb);
} }
#define ext4_error_ratelimit(sb) \ #define ext4_error_ratelimit(sb) \
...@@ -710,8 +751,7 @@ void __ext4_error(struct super_block *sb, const char *function, ...@@ -710,8 +751,7 @@ void __ext4_error(struct super_block *sb, const char *function,
sb->s_id, function, line, current->comm, &vaf); sb->s_id, function, line, current->comm, &vaf);
va_end(args); va_end(args);
} }
save_error_info(sb, error, 0, block, function, line); ext4_handle_error(sb, force_ro, error, 0, block, function, line);
ext4_handle_error(sb, force_ro);
} }
void __ext4_error_inode(struct inode *inode, const char *function, void __ext4_error_inode(struct inode *inode, const char *function,
...@@ -741,9 +781,8 @@ void __ext4_error_inode(struct inode *inode, const char *function, ...@@ -741,9 +781,8 @@ void __ext4_error_inode(struct inode *inode, const char *function,
current->comm, &vaf); current->comm, &vaf);
va_end(args); va_end(args);
} }
save_error_info(inode->i_sb, error, inode->i_ino, block, ext4_handle_error(inode->i_sb, false, error, inode->i_ino, block,
function, line); function, line);
ext4_handle_error(inode->i_sb, false);
} }
void __ext4_error_file(struct file *file, const char *function, void __ext4_error_file(struct file *file, const char *function,
...@@ -780,9 +819,8 @@ void __ext4_error_file(struct file *file, const char *function, ...@@ -780,9 +819,8 @@ void __ext4_error_file(struct file *file, const char *function,
current->comm, path, &vaf); current->comm, path, &vaf);
va_end(args); va_end(args);
} }
save_error_info(inode->i_sb, EFSCORRUPTED, inode->i_ino, block, ext4_handle_error(inode->i_sb, false, EFSCORRUPTED, inode->i_ino, block,
function, line); function, line);
ext4_handle_error(inode->i_sb, false);
} }
const char *ext4_decode_error(struct super_block *sb, int errno, const char *ext4_decode_error(struct super_block *sb, int errno,
...@@ -849,8 +887,7 @@ void __ext4_std_error(struct super_block *sb, const char *function, ...@@ -849,8 +887,7 @@ void __ext4_std_error(struct super_block *sb, const char *function,
sb->s_id, function, line, errstr); sb->s_id, function, line, errstr);
} }
save_error_info(sb, -errno, 0, 0, function, line); ext4_handle_error(sb, false, -errno, 0, 0, function, line);
ext4_handle_error(sb, false);
} }
void __ext4_msg(struct super_block *sb, void __ext4_msg(struct super_block *sb,
...@@ -944,13 +981,16 @@ __acquires(bitlock) ...@@ -944,13 +981,16 @@ __acquires(bitlock)
if (test_opt(sb, ERRORS_CONT)) { if (test_opt(sb, ERRORS_CONT)) {
if (test_opt(sb, WARN_ON_ERROR)) if (test_opt(sb, WARN_ON_ERROR))
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
__save_error_info(sb, EFSCORRUPTED, ino, block, function, line); EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
if (!bdev_read_only(sb->s_bdev)) {
save_error_info(sb, EFSCORRUPTED, ino, block, function,
line);
schedule_work(&EXT4_SB(sb)->s_error_work); schedule_work(&EXT4_SB(sb)->s_error_work);
}
return; return;
} }
ext4_unlock_group(sb, grp); ext4_unlock_group(sb, grp);
save_error_info(sb, EFSCORRUPTED, ino, block, function, line); ext4_handle_error(sb, false, EFSCORRUPTED, ino, block, function, line);
ext4_handle_error(sb, false);
/* /*
* We only get here in the ERRORS_RO case; relocking the group * We only get here in the ERRORS_RO case; relocking the group
* may be dangerous, but nothing bad will happen since the * may be dangerous, but nothing bad will happen since the
...@@ -1152,7 +1192,7 @@ static void ext4_put_super(struct super_block *sb) ...@@ -1152,7 +1192,7 @@ static void ext4_put_super(struct super_block *sb)
es->s_state = cpu_to_le16(sbi->s_mount_state); es->s_state = cpu_to_le16(sbi->s_mount_state);
} }
if (!sb_rdonly(sb)) if (!sb_rdonly(sb))
ext4_commit_super(sb, 1); ext4_commit_super(sb);
rcu_read_lock(); rcu_read_lock();
group_desc = rcu_dereference(sbi->s_group_desc); group_desc = rcu_dereference(sbi->s_group_desc);
...@@ -2642,7 +2682,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, ...@@ -2642,7 +2682,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
if (sbi->s_journal) if (sbi->s_journal)
ext4_set_feature_journal_needs_recovery(sb); ext4_set_feature_journal_needs_recovery(sb);
err = ext4_commit_super(sb, 1); err = ext4_commit_super(sb);
done: done:
if (test_opt(sb, DEBUG)) if (test_opt(sb, DEBUG))
printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, "
...@@ -4868,7 +4908,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -4868,7 +4908,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
if (DUMMY_ENCRYPTION_ENABLED(sbi) && !sb_rdonly(sb) && if (DUMMY_ENCRYPTION_ENABLED(sbi) && !sb_rdonly(sb) &&
!ext4_has_feature_encrypt(sb)) { !ext4_has_feature_encrypt(sb)) {
ext4_set_feature_encrypt(sb); ext4_set_feature_encrypt(sb);
ext4_commit_super(sb, 1); ext4_commit_super(sb);
} }
/* /*
...@@ -5418,7 +5458,7 @@ static int ext4_load_journal(struct super_block *sb, ...@@ -5418,7 +5458,7 @@ static int ext4_load_journal(struct super_block *sb,
es->s_journal_dev = cpu_to_le32(journal_devnum); es->s_journal_dev = cpu_to_le32(journal_devnum);
/* Make sure we flush the recovery flag to disk. */ /* Make sure we flush the recovery flag to disk. */
ext4_commit_super(sb, 1); ext4_commit_super(sb);
} }
return 0; return 0;
...@@ -5428,16 +5468,14 @@ static int ext4_load_journal(struct super_block *sb, ...@@ -5428,16 +5468,14 @@ static int ext4_load_journal(struct super_block *sb,
return err; return err;
} }
static int ext4_commit_super(struct super_block *sb, int sync) /* Copy state of EXT4_SB(sb) into buffer for on-disk superblock */
static void ext4_update_super(struct super_block *sb)
{ {
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = EXT4_SB(sb)->s_es; struct ext4_super_block *es = sbi->s_es;
struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; struct buffer_head *sbh = sbi->s_sbh;
int error = 0;
if (!sbh || block_device_ejected(sb))
return error;
lock_buffer(sbh);
/* /*
* If the file system is mounted read-only, don't update the * If the file system is mounted read-only, don't update the
* superblock write time. This avoids updating the superblock * superblock write time. This avoids updating the superblock
...@@ -5451,17 +5489,17 @@ static int ext4_commit_super(struct super_block *sb, int sync) ...@@ -5451,17 +5489,17 @@ static int ext4_commit_super(struct super_block *sb, int sync)
if (!(sb->s_flags & SB_RDONLY)) if (!(sb->s_flags & SB_RDONLY))
ext4_update_tstamp(es, s_wtime); ext4_update_tstamp(es, s_wtime);
es->s_kbytes_written = es->s_kbytes_written =
cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + cpu_to_le64(sbi->s_kbytes_written +
((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) - ((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -
EXT4_SB(sb)->s_sectors_written_start) >> 1)); sbi->s_sectors_written_start) >> 1));
if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeclusters_counter)) if (percpu_counter_initialized(&sbi->s_freeclusters_counter))
ext4_free_blocks_count_set(es, ext4_free_blocks_count_set(es,
EXT4_C2B(EXT4_SB(sb), percpu_counter_sum_positive( EXT4_C2B(sbi, percpu_counter_sum_positive(
&EXT4_SB(sb)->s_freeclusters_counter))); &sbi->s_freeclusters_counter)));
if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter)) if (percpu_counter_initialized(&sbi->s_freeinodes_counter))
es->s_free_inodes_count = es->s_free_inodes_count =
cpu_to_le32(percpu_counter_sum_positive( cpu_to_le32(percpu_counter_sum_positive(
&EXT4_SB(sb)->s_freeinodes_counter)); &sbi->s_freeinodes_counter));
/* Copy error information to the on-disk superblock */ /* Copy error information to the on-disk superblock */
spin_lock(&sbi->s_error_lock); spin_lock(&sbi->s_error_lock);
if (sbi->s_add_error_count > 0) { if (sbi->s_add_error_count > 0) {
...@@ -5502,10 +5540,20 @@ static int ext4_commit_super(struct super_block *sb, int sync) ...@@ -5502,10 +5540,20 @@ static int ext4_commit_super(struct super_block *sb, int sync)
} }
spin_unlock(&sbi->s_error_lock); spin_unlock(&sbi->s_error_lock);
BUFFER_TRACE(sbh, "marking dirty");
ext4_superblock_csum_set(sb); ext4_superblock_csum_set(sb);
if (sync) unlock_buffer(sbh);
lock_buffer(sbh); }
static int ext4_commit_super(struct super_block *sb)
{
struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
int error = 0;
if (!sbh || block_device_ejected(sb))
return error;
ext4_update_super(sb);
if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) { if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) {
/* /*
* Oh, dear. A previous attempt to write the * Oh, dear. A previous attempt to write the
...@@ -5520,9 +5568,8 @@ static int ext4_commit_super(struct super_block *sb, int sync) ...@@ -5520,9 +5568,8 @@ static int ext4_commit_super(struct super_block *sb, int sync)
clear_buffer_write_io_error(sbh); clear_buffer_write_io_error(sbh);
set_buffer_uptodate(sbh); set_buffer_uptodate(sbh);
} }
BUFFER_TRACE(sbh, "marking dirty");
mark_buffer_dirty(sbh); mark_buffer_dirty(sbh);
if (sync) {
unlock_buffer(sbh);
error = __sync_dirty_buffer(sbh, error = __sync_dirty_buffer(sbh,
REQ_SYNC | (test_opt(sb, BARRIER) ? REQ_FUA : 0)); REQ_SYNC | (test_opt(sb, BARRIER) ? REQ_FUA : 0));
if (buffer_write_io_error(sbh)) { if (buffer_write_io_error(sbh)) {
...@@ -5531,7 +5578,6 @@ static int ext4_commit_super(struct super_block *sb, int sync) ...@@ -5531,7 +5578,6 @@ static int ext4_commit_super(struct super_block *sb, int sync)
clear_buffer_write_io_error(sbh); clear_buffer_write_io_error(sbh);
set_buffer_uptodate(sbh); set_buffer_uptodate(sbh);
} }
}
return error; return error;
} }
...@@ -5561,7 +5607,7 @@ static int ext4_mark_recovery_complete(struct super_block *sb, ...@@ -5561,7 +5607,7 @@ static int ext4_mark_recovery_complete(struct super_block *sb,
if (ext4_has_feature_journal_needs_recovery(sb) && sb_rdonly(sb)) { if (ext4_has_feature_journal_needs_recovery(sb) && sb_rdonly(sb)) {
ext4_clear_feature_journal_needs_recovery(sb); ext4_clear_feature_journal_needs_recovery(sb);
ext4_commit_super(sb, 1); ext4_commit_super(sb);
} }
out: out:
jbd2_journal_unlock_updates(journal); jbd2_journal_unlock_updates(journal);
...@@ -5603,7 +5649,7 @@ static int ext4_clear_journal_err(struct super_block *sb, ...@@ -5603,7 +5649,7 @@ static int ext4_clear_journal_err(struct super_block *sb,
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
es->s_state |= cpu_to_le16(EXT4_ERROR_FS); es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
ext4_commit_super(sb, 1); ext4_commit_super(sb);
jbd2_journal_clear_err(journal); jbd2_journal_clear_err(journal);
jbd2_journal_update_sb_errno(journal); jbd2_journal_update_sb_errno(journal);
...@@ -5705,7 +5751,7 @@ static int ext4_freeze(struct super_block *sb) ...@@ -5705,7 +5751,7 @@ static int ext4_freeze(struct super_block *sb)
ext4_clear_feature_journal_needs_recovery(sb); ext4_clear_feature_journal_needs_recovery(sb);
} }
error = ext4_commit_super(sb, 1); error = ext4_commit_super(sb);
out: out:
if (journal) if (journal)
/* we rely on upper layer to stop further updates */ /* we rely on upper layer to stop further updates */
...@@ -5727,7 +5773,7 @@ static int ext4_unfreeze(struct super_block *sb) ...@@ -5727,7 +5773,7 @@ static int ext4_unfreeze(struct super_block *sb)
ext4_set_feature_journal_needs_recovery(sb); ext4_set_feature_journal_needs_recovery(sb);
} }
ext4_commit_super(sb, 1); ext4_commit_super(sb);
return 0; return 0;
} }
...@@ -5987,7 +6033,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) ...@@ -5987,7 +6033,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
} }
if (sbi->s_journal == NULL && !(old_sb_flags & SB_RDONLY)) { if (sbi->s_journal == NULL && !(old_sb_flags & SB_RDONLY)) {
err = ext4_commit_super(sb, 1); err = ext4_commit_super(sb);
if (err) if (err)
goto restore_opts; goto restore_opts;
} }
......
...@@ -792,8 +792,11 @@ static void ext4_xattr_update_super_block(handle_t *handle, ...@@ -792,8 +792,11 @@ static void ext4_xattr_update_super_block(handle_t *handle,
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) { if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
lock_buffer(EXT4_SB(sb)->s_sbh);
ext4_set_feature_xattr(sb); ext4_set_feature_xattr(sb);
ext4_handle_dirty_super(handle, sb); ext4_superblock_csum_set(sb);
unlock_buffer(EXT4_SB(sb)->s_sbh);
ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
} }
} }
......
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