Skip to content

Commit

Permalink
Merge tag 'for_linus_stable' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/tytso/ext4

Pull ext4 fixes from Ted Ts'o:
 "Fix a number of ext4 bugs; the most serious of which is a bug in the
  lazytime mount optimization code where we could end up updating the
  timestamps to the wrong inode"

* tag 'for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: fix an ext3 collapse range regression in xfstests
  jbd2: fix r_count overflows leading to buffer overflow in journal recovery
  ext4: check for zero length extent explicitly
  ext4: fix NULL pointer dereference when journal restart fails
  ext4: remove unused function prototype from ext4.h
  ext4: don't save the error information if the block device is read-only
  ext4: fix lazytime optimization
  • Loading branch information
Linus Torvalds committed May 16, 2015
2 parents c7309e8 + b9576fc commit 6a8098a
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 21 deletions.
1 change: 0 additions & 1 deletion fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -2889,7 +2889,6 @@ extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map, int flags);
extern int ext4_ext_calc_metadata_amount(struct inode *inode,
ext4_lblk_t lblocks);
extern int ext4_extent_tree_init(handle_t *, struct inode *);
extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
int num,
struct ext4_ext_path *path);
Expand Down
6 changes: 6 additions & 0 deletions fs/ext4/ext4_jbd2.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
ext4_put_nojournal(handle);
return 0;
}

if (!handle->h_transaction) {
err = jbd2_journal_stop(handle);
return handle->h_err ? handle->h_err : err;
}

sb = handle->h_transaction->t_journal->j_private;
err = handle->h_err;
rc = jbd2_journal_stop(handle);
Expand Down
10 changes: 9 additions & 1 deletion fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
ext4_lblk_t lblock = le32_to_cpu(ext->ee_block);
ext4_lblk_t last = lblock + len - 1;

if (lblock > last)
if (len == 0 || lblock > last)
return 0;
return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
}
Expand Down Expand Up @@ -5396,6 +5396,14 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
loff_t new_size, ioffset;
int ret;

/*
* We need to test this early because xfstests assumes that a
* collapse range of (0, 1) will return EOPNOTSUPP if the file
* system does not support collapse range.
*/
if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
return -EOPNOTSUPP;

/* Collapse range works only on fs block size aligned offsets. */
if (offset & (EXT4_CLUSTER_SIZE(sb) - 1) ||
len & (EXT4_CLUSTER_SIZE(sb) - 1))
Expand Down
2 changes: 1 addition & 1 deletion fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -4345,7 +4345,7 @@ static void ext4_update_other_inodes_time(struct super_block *sb,
int inode_size = EXT4_INODE_SIZE(sb);

oi.orig_ino = orig_ino;
ino = orig_ino & ~(inodes_per_block - 1);
ino = (orig_ino & ~(inodes_per_block - 1)) + 1;
for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) {
if (ino == orig_ino)
continue;
Expand Down
2 changes: 2 additions & 0 deletions fs/ext4/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ static void __save_error_info(struct super_block *sb, const char *func,
struct ext4_super_block *es = EXT4_SB(sb)->s_es;

EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
if (bdev_read_only(sb->s_bdev))
return;
es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
es->s_last_error_time = cpu_to_le32(get_seconds());
strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
Expand Down
10 changes: 9 additions & 1 deletion fs/jbd2/recovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -842,15 +842,23 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
{
jbd2_journal_revoke_header_t *header;
int offset, max;
int csum_size = 0;
__u32 rcount;
int record_len = 4;

header = (jbd2_journal_revoke_header_t *) bh->b_data;
offset = sizeof(jbd2_journal_revoke_header_t);
max = be32_to_cpu(header->r_count);
rcount = be32_to_cpu(header->r_count);

if (!jbd2_revoke_block_csum_verify(journal, header))
return -EINVAL;

if (jbd2_journal_has_csum_v2or3(journal))
csum_size = sizeof(struct jbd2_journal_revoke_tail);
if (rcount > journal->j_blocksize - csum_size)
return -EINVAL;
max = rcount;

if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
record_len = 8;

Expand Down
18 changes: 10 additions & 8 deletions fs/jbd2/revoke.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ static void write_one_revoke_record(journal_t *journal,
{
int csum_size = 0;
struct buffer_head *descriptor;
int offset;
int sz, offset;
journal_header_t *header;

/* If we are already aborting, this all becomes a noop. We
Expand All @@ -594,9 +594,14 @@ static void write_one_revoke_record(journal_t *journal,
if (jbd2_journal_has_csum_v2or3(journal))
csum_size = sizeof(struct jbd2_journal_revoke_tail);

if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
sz = 8;
else
sz = 4;

/* Make sure we have a descriptor with space left for the record */
if (descriptor) {
if (offset >= journal->j_blocksize - csum_size) {
if (offset + sz > journal->j_blocksize - csum_size) {
flush_descriptor(journal, descriptor, offset, write_op);
descriptor = NULL;
}
Expand All @@ -619,16 +624,13 @@ static void write_one_revoke_record(journal_t *journal,
*descriptorp = descriptor;
}

if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) {
if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
* ((__be64 *)(&descriptor->b_data[offset])) =
cpu_to_be64(record->blocknr);
offset += 8;

} else {
else
* ((__be32 *)(&descriptor->b_data[offset])) =
cpu_to_be32(record->blocknr);
offset += 4;
}
offset += sz;

*offsetp = offset;
}
Expand Down
25 changes: 16 additions & 9 deletions fs/jbd2/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,6 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
int result;
int wanted;

WARN_ON(!transaction);
if (is_handle_aborted(handle))
return -EROFS;
journal = transaction->t_journal;
Expand Down Expand Up @@ -627,7 +626,6 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask)
tid_t tid;
int need_to_start, ret;

WARN_ON(!transaction);
/* If we've had an abort of any type, don't even think about
* actually doing the restart! */
if (is_handle_aborted(handle))
Expand Down Expand Up @@ -785,7 +783,6 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
int need_copy = 0;
unsigned long start_lock, time_lock;

WARN_ON(!transaction);
if (is_handle_aborted(handle))
return -EROFS;
journal = transaction->t_journal;
Expand Down Expand Up @@ -1051,7 +1048,6 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
int err;

jbd_debug(5, "journal_head %p\n", jh);
WARN_ON(!transaction);
err = -EROFS;
if (is_handle_aborted(handle))
goto out;
Expand Down Expand Up @@ -1266,7 +1262,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
struct journal_head *jh;
int ret = 0;

WARN_ON(!transaction);
if (is_handle_aborted(handle))
return -EROFS;
journal = transaction->t_journal;
Expand Down Expand Up @@ -1397,7 +1392,6 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
int err = 0;
int was_modified = 0;

WARN_ON(!transaction);
if (is_handle_aborted(handle))
return -EROFS;
journal = transaction->t_journal;
Expand Down Expand Up @@ -1530,8 +1524,22 @@ int jbd2_journal_stop(handle_t *handle)
tid_t tid;
pid_t pid;

if (!transaction)
goto free_and_exit;
if (!transaction) {
/*
* Handle is already detached from the transaction so
* there is nothing to do other than decrease a refcount,
* or free the handle if refcount drops to zero
*/
if (--handle->h_ref > 0) {
jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
handle->h_ref);
return err;
} else {
if (handle->h_rsv_handle)
jbd2_free_handle(handle->h_rsv_handle);
goto free_and_exit;
}
}
journal = transaction->t_journal;

J_ASSERT(journal_current_handle() == handle);
Expand Down Expand Up @@ -2373,7 +2381,6 @@ int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode)
transaction_t *transaction = handle->h_transaction;
journal_t *journal;

WARN_ON(!transaction);
if (is_handle_aborted(handle))
return -EROFS;
journal = transaction->t_journal;
Expand Down

0 comments on commit 6a8098a

Please sign in to comment.