Commit 17403fa2 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:
 "Miscellaneous ext4 bug fixes for 5.1"

* tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: prohibit fstrim in norecovery mode
  ext4: cleanup bh release code in ext4_ind_remove_space()
  ext4: brelse all indirect buffer in ext4_ind_remove_space()
  ext4: report real fs size after failed resize
  ext4: add missing brelse() in add_new_gdb_meta_bg()
  ext4: remove useless ext4_pin_inode()
  ext4: avoid panic during forced reboot
  ext4: fix data corruption caused by unaligned direct AIO
  ext4: fix NULL pointer dereference while journal is aborted
parents 231c807a 18915b58
......@@ -384,7 +384,7 @@ static inline void ext4_update_inode_fsync_trans(handle_t *handle,
{
struct ext4_inode_info *ei = EXT4_I(inode);
if (ext4_handle_valid(handle)) {
if (ext4_handle_valid(handle) && !is_handle_aborted(handle)) {
ei->i_sync_tid = handle->h_transaction->t_tid;
if (datasync)
ei->i_datasync_tid = handle->h_transaction->t_tid;
......
......@@ -125,7 +125,7 @@ ext4_unaligned_aio(struct inode *inode, struct iov_iter *from, loff_t pos)
struct super_block *sb = inode->i_sb;
int blockmask = sb->s_blocksize - 1;
if (pos >= i_size_read(inode))
if (pos >= ALIGN(i_size_read(inode), sb->s_blocksize))
return 0;
if ((pos | iov_iter_alignment(from)) & blockmask)
......
......@@ -1222,6 +1222,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
ext4_lblk_t offsets[4], offsets2[4];
Indirect chain[4], chain2[4];
Indirect *partial, *partial2;
Indirect *p = NULL, *p2 = NULL;
ext4_lblk_t max_block;
__le32 nr = 0, nr2 = 0;
int n = 0, n2 = 0;
......@@ -1263,7 +1264,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
}
partial = ext4_find_shared(inode, n, offsets, chain, &nr);
partial = p = ext4_find_shared(inode, n, offsets, chain, &nr);
if (nr) {
if (partial == chain) {
/* Shared branch grows from the inode */
......@@ -1288,13 +1289,11 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
partial->p + 1,
(__le32 *)partial->bh->b_data+addr_per_block,
(chain+n-1) - partial);
BUFFER_TRACE(partial->bh, "call brelse");
brelse(partial->bh);
partial--;
}
end_range:
partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
partial2 = p2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
if (nr2) {
if (partial2 == chain2) {
/*
......@@ -1324,16 +1323,14 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
(__le32 *)partial2->bh->b_data,
partial2->p,
(chain2+n2-1) - partial2);
BUFFER_TRACE(partial2->bh, "call brelse");
brelse(partial2->bh);
partial2--;
}
goto do_indirects;
}
/* Punch happened within the same level (n == n2) */
partial = ext4_find_shared(inode, n, offsets, chain, &nr);
partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
partial = p = ext4_find_shared(inode, n, offsets, chain, &nr);
partial2 = p2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
/* Free top, but only if partial2 isn't its subtree. */
if (nr) {
......@@ -1390,11 +1387,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
partial->p + 1,
partial2->p,
(chain+n-1) - partial);
BUFFER_TRACE(partial->bh, "call brelse");
brelse(partial->bh);
BUFFER_TRACE(partial2->bh, "call brelse");
brelse(partial2->bh);
return 0;
goto cleanup;
}
/*
......@@ -1409,8 +1402,6 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
partial->p + 1,
(__le32 *)partial->bh->b_data+addr_per_block,
(chain+n-1) - partial);
BUFFER_TRACE(partial->bh, "call brelse");
brelse(partial->bh);
partial--;
}
if (partial2 > chain2 && depth2 <= depth) {
......@@ -1418,11 +1409,21 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
(__le32 *)partial2->bh->b_data,
partial2->p,
(chain2+n2-1) - partial2);
BUFFER_TRACE(partial2->bh, "call brelse");
brelse(partial2->bh);
partial2--;
}
}
cleanup:
while (p && p > chain) {
BUFFER_TRACE(p->bh, "call brelse");
brelse(p->bh);
p--;
}
while (p2 && p2 > chain2) {
BUFFER_TRACE(p2->bh, "call brelse");
brelse(p2->bh);
p2--;
}
return 0;
do_indirects:
......@@ -1430,7 +1431,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
switch (offsets[0]) {
default:
if (++n >= n2)
return 0;
break;
nr = i_data[EXT4_IND_BLOCK];
if (nr) {
ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
......@@ -1439,7 +1440,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
/* fall through */
case EXT4_IND_BLOCK:
if (++n >= n2)
return 0;
break;
nr = i_data[EXT4_DIND_BLOCK];
if (nr) {
ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
......@@ -1448,7 +1449,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
/* fall through */
case EXT4_DIND_BLOCK:
if (++n >= n2)
return 0;
break;
nr = i_data[EXT4_TIND_BLOCK];
if (nr) {
ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
......@@ -1458,5 +1459,5 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
case EXT4_TIND_BLOCK:
;
}
return 0;
goto cleanup;
}
......@@ -6080,36 +6080,6 @@ void ext4_dirty_inode(struct inode *inode, int flags)
return;
}
#if 0
/*
* Bind an inode's backing buffer_head into this transaction, to prevent
* it from being flushed to disk early. Unlike
* ext4_reserve_inode_write, this leaves behind no bh reference and
* returns no iloc structure, so the caller needs to repeat the iloc
* lookup to mark the inode dirty later.
*/
static int ext4_pin_inode(handle_t *handle, struct inode *inode)
{
struct ext4_iloc iloc;
int err = 0;
if (handle) {
err = ext4_get_inode_loc(inode, &iloc);
if (!err) {
BUFFER_TRACE(iloc.bh, "get_write_access");
err = jbd2_journal_get_write_access(handle, iloc.bh);
if (!err)
err = ext4_handle_dirty_metadata(handle,
NULL,
iloc.bh);
brelse(iloc.bh);
}
}
ext4_std_error(inode->i_sb, err);
return err;
}
#endif
int ext4_change_inode_journal_flag(struct inode *inode, int val)
{
journal_t *journal;
......
......@@ -1000,6 +1000,13 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (!blk_queue_discard(q))
return -EOPNOTSUPP;
/*
* We haven't replayed the journal, so we cannot use our
* block-bitmap-guided storage zapping commands.
*/
if (test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb))
return -EROFS;
if (copy_from_user(&range, (struct fstrim_range __user *)arg,
sizeof(range)))
return -EFAULT;
......
......@@ -932,11 +932,18 @@ static int add_new_gdb_meta_bg(struct super_block *sb,
memcpy(n_group_desc, o_group_desc,
EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *));
n_group_desc[gdb_num] = gdb_bh;
BUFFER_TRACE(gdb_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, gdb_bh);
if (err) {
kvfree(n_group_desc);
brelse(gdb_bh);
return err;
}
EXT4_SB(sb)->s_group_desc = n_group_desc;
EXT4_SB(sb)->s_gdb_count++;
kvfree(o_group_desc);
BUFFER_TRACE(gdb_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, gdb_bh);
return err;
}
......@@ -2073,6 +2080,10 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
free_flex_gd(flex_gd);
if (resize_inode != NULL)
iput(resize_inode);
ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", n_blocks_count);
if (err)
ext4_warning(sb, "error (%d) occurred during "
"file system resize", err);
ext4_msg(sb, KERN_INFO, "resized filesystem to %llu",
ext4_blocks_count(es));
return err;
}
......@@ -430,6 +430,12 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
spin_unlock(&sbi->s_md_lock);
}
static bool system_going_down(void)
{
return system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF
|| system_state == SYSTEM_RESTART;
}
/* Deal with the reporting of failure conditions on a filesystem such as
* inconsistencies detected or read IO failures.
*
......@@ -460,7 +466,12 @@ static void ext4_handle_error(struct super_block *sb)
if (journal)
jbd2_journal_abort(journal, -EIO);
}
if (test_opt(sb, ERRORS_RO)) {
/*
* We force ERRORS_RO behavior when system is rebooting. Otherwise we
* could panic during 'reboot -f' as the underlying device got already
* disabled.
*/
if (test_opt(sb, ERRORS_RO) || system_going_down()) {
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
/*
* Make sure updated value of ->s_mount_flags will be visible
......@@ -468,8 +479,7 @@ static void ext4_handle_error(struct super_block *sb)
*/
smp_wmb();
sb->s_flags |= SB_RDONLY;
}
if (test_opt(sb, ERRORS_PANIC)) {
} else if (test_opt(sb, ERRORS_PANIC)) {
if (EXT4_SB(sb)->s_journal &&
!(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
return;
......
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