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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABCAAGBQJVV1l1AAoJEPL5WVaVDYGjdPwH/RzNut4bfgq7yK2yUVNqPpPN QzjR848fT1lj7C1eN7eEh+NRG+KNM2QnmMJBU8jVnwq2l3r8AGFV/bDRC+Zx4U8L cz9mZJMU7ZDP5TH/WVyimySGAXpaFKruXA+3L8CyC3LQEI6TUOxKt5CqNi0/9nND B8HoF+Ei7jIILrcW7KKj55/fSfh4iiy+iUb0kjrSnZj0y5sROfFG2QhQwIhJRk7I /8aeg2HYbhWXCKQHnQ5F4lLNCf44kdJ/EoCpz6aOHtVwrnBcQ44yeqm5MtHSh6Qw lj8iPCIlcHYGZE4im+pWAavDMeHBm/VnOnH9545t6nNFq6W7WNdkD99ZJ/AQyWQ= =JJxO -----END PGP SIGNATURE----- Merge tag 'for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/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
This commit is contained in:
commit
6a8098a447
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue