A set of miscellaneous ext4 bug fixes for 3.18.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJUVAF/AAoJENNvdpvBGATwEbAQALNiAIChEyJTnQDkAQc2wqqn dv8NQmFr5aefc63A/+n/yJJGrQZtKs0ceh29ty5ksYLFXzUdc2ctFg6vBmllQfbz PQawAk2gOkF8zfVuqiQU7X+wTBpGmGXTa8HY+WJTtk0pBfhl+p0PDCYsWXMwZJ1D tAZpxJ4AmPc7A4hApWOvce6r7Xg24vZk/8UA93Tif9AkeY6VoN272Hx5b/UGmBHY RCEgpowuiIY38bghtLh5+T0J98/EQNof46cEHgGI9nIDZeXRzgvDojE5bLI0/IS/ K07MjYlm/WFWsLFkgNJkTiqEXgnji9BNYRF1xxUjMMBAR4+fnFLw9kXXgcETrPCx U7lHOhs8M2FK40cWhUDz/tukvL4S4lQwPEeqBPlRE8J5/twRyXHeZDp4F7LOobwq mk6AajSJlP+05XwXOuCx7Hcf9uxjw/IpqhBS5IZxy8Nn3T2guPlY9wMhYU1RYFws 54FeE76SJ8EDgjVK/txj7rgh11GggWsjsdXvftSElM2DsKsqYEOKAvDzvwmbm7eV dsFOlRB6B/X4UpiAC2MiPJynYg9TJ7LkVBzDZeZ/fbm7JhTqChSJDzapqdrmNPIY SQqwLmFXnHqaw6HNitZ5Bs+fD6nfvKqy85NeImxE3lhLWDuiTt77Y3o80IW30TgN 5bnuXq8Rkukrxs/VDvPq =kI6P -----END PGP SIGNATURE----- Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4 Pull ext4 bugfixes from Ted Ts'o: "A set of miscellaneous ext4 bug fixes for 3.18" * tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: make ext4_ext_convert_to_initialized() return proper number of blocks ext4: bail early when clearing inode journal flag fails ext4: bail out from make_indexed_dir() on first error jbd2: use a better hash function for the revoke table ext4: prevent bugon on race between write/fcntl ext4: remove extent status procfs files if journal load fails ext4: disallow changing journal_csum option during remount ext4: enable journal checksum when metadata checksum feature enabled ext4: fix oops when loading block bitmap failed ext4: fix overflow when updating superblock backups after resize
This commit is contained in:
commit
32e8fd2f8e
8 changed files with 51 additions and 28 deletions
|
@ -3603,11 +3603,10 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allocated = ext4_split_extent(handle, inode, ppath,
|
err = ext4_split_extent(handle, inode, ppath, &split_map, split_flag,
|
||||||
&split_map, split_flag, flags);
|
flags);
|
||||||
if (allocated < 0)
|
if (err > 0)
|
||||||
err = allocated;
|
err = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
/* If we have gotten a failure, don't zero out status tree */
|
/* If we have gotten a failure, don't zero out status tree */
|
||||||
if (!err)
|
if (!err)
|
||||||
|
|
|
@ -137,10 +137,10 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos);
|
iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iocb->private = &overwrite;
|
||||||
if (o_direct) {
|
if (o_direct) {
|
||||||
blk_start_plug(&plug);
|
blk_start_plug(&plug);
|
||||||
|
|
||||||
iocb->private = &overwrite;
|
|
||||||
|
|
||||||
/* check whether we do a DIO overwrite or not */
|
/* check whether we do a DIO overwrite or not */
|
||||||
if (ext4_should_dioread_nolock(inode) && !aio_mutex &&
|
if (ext4_should_dioread_nolock(inode) && !aio_mutex &&
|
||||||
|
|
|
@ -887,6 +887,10 @@ got:
|
||||||
struct buffer_head *block_bitmap_bh;
|
struct buffer_head *block_bitmap_bh;
|
||||||
|
|
||||||
block_bitmap_bh = ext4_read_block_bitmap(sb, group);
|
block_bitmap_bh = ext4_read_block_bitmap(sb, group);
|
||||||
|
if (!block_bitmap_bh) {
|
||||||
|
err = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
BUFFER_TRACE(block_bitmap_bh, "get block bitmap access");
|
BUFFER_TRACE(block_bitmap_bh, "get block bitmap access");
|
||||||
err = ext4_journal_get_write_access(handle, block_bitmap_bh);
|
err = ext4_journal_get_write_access(handle, block_bitmap_bh);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -4959,7 +4959,12 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
|
||||||
if (val)
|
if (val)
|
||||||
ext4_set_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
|
ext4_set_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
|
||||||
else {
|
else {
|
||||||
jbd2_journal_flush(journal);
|
err = jbd2_journal_flush(journal);
|
||||||
|
if (err < 0) {
|
||||||
|
jbd2_journal_unlock_updates(journal);
|
||||||
|
ext4_inode_resume_unlocked_dio(inode);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
|
ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
|
||||||
}
|
}
|
||||||
ext4_set_aops(inode);
|
ext4_set_aops(inode);
|
||||||
|
|
|
@ -1816,31 +1816,39 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
|
||||||
hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
|
hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
|
||||||
hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
|
hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
|
||||||
ext4fs_dirhash(name, namelen, &hinfo);
|
ext4fs_dirhash(name, namelen, &hinfo);
|
||||||
|
memset(frames, 0, sizeof(frames));
|
||||||
frame = frames;
|
frame = frames;
|
||||||
frame->entries = entries;
|
frame->entries = entries;
|
||||||
frame->at = entries;
|
frame->at = entries;
|
||||||
frame->bh = bh;
|
frame->bh = bh;
|
||||||
bh = bh2;
|
bh = bh2;
|
||||||
|
|
||||||
ext4_handle_dirty_dx_node(handle, dir, frame->bh);
|
retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
|
||||||
ext4_handle_dirty_dirent_node(handle, dir, bh);
|
if (retval)
|
||||||
|
goto out_frames;
|
||||||
|
retval = ext4_handle_dirty_dirent_node(handle, dir, bh);
|
||||||
|
if (retval)
|
||||||
|
goto out_frames;
|
||||||
|
|
||||||
de = do_split(handle,dir, &bh, frame, &hinfo);
|
de = do_split(handle,dir, &bh, frame, &hinfo);
|
||||||
if (IS_ERR(de)) {
|
if (IS_ERR(de)) {
|
||||||
/*
|
retval = PTR_ERR(de);
|
||||||
* Even if the block split failed, we have to properly write
|
goto out_frames;
|
||||||
* out all the changes we did so far. Otherwise we can end up
|
|
||||||
* with corrupted filesystem.
|
|
||||||
*/
|
|
||||||
ext4_mark_inode_dirty(handle, dir);
|
|
||||||
dx_release(frames);
|
|
||||||
return PTR_ERR(de);
|
|
||||||
}
|
}
|
||||||
dx_release(frames);
|
dx_release(frames);
|
||||||
|
|
||||||
retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
|
retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
return retval;
|
return retval;
|
||||||
|
out_frames:
|
||||||
|
/*
|
||||||
|
* Even if the block split failed, we have to properly write
|
||||||
|
* out all the changes we did so far. Otherwise we can end up
|
||||||
|
* with corrupted filesystem.
|
||||||
|
*/
|
||||||
|
ext4_mark_inode_dirty(handle, dir);
|
||||||
|
dx_release(frames);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1081,7 +1081,7 @@ static void update_backups(struct super_block *sb, int blk_off, char *data,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (meta_bg == 0)
|
if (meta_bg == 0)
|
||||||
backup_block = group * bpg + blk_off;
|
backup_block = ((ext4_fsblk_t)group) * bpg + blk_off;
|
||||||
else
|
else
|
||||||
backup_block = (ext4_group_first_block_no(sb, group) +
|
backup_block = (ext4_group_first_block_no(sb, group) +
|
||||||
ext4_bg_has_super(sb, group));
|
ext4_bg_has_super(sb, group));
|
||||||
|
|
|
@ -3526,6 +3526,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
#ifdef CONFIG_EXT4_FS_POSIX_ACL
|
#ifdef CONFIG_EXT4_FS_POSIX_ACL
|
||||||
set_opt(sb, POSIX_ACL);
|
set_opt(sb, POSIX_ACL);
|
||||||
#endif
|
#endif
|
||||||
|
/* don't forget to enable journal_csum when metadata_csum is enabled. */
|
||||||
|
if (ext4_has_metadata_csum(sb))
|
||||||
|
set_opt(sb, JOURNAL_CHECKSUM);
|
||||||
|
|
||||||
if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
|
if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
|
||||||
set_opt(sb, JOURNAL_DATA);
|
set_opt(sb, JOURNAL_DATA);
|
||||||
else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
|
else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
|
||||||
|
@ -3943,7 +3947,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_MMP) &&
|
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_MMP) &&
|
||||||
!(sb->s_flags & MS_RDONLY))
|
!(sb->s_flags & MS_RDONLY))
|
||||||
if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
|
if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
|
||||||
goto failed_mount3;
|
goto failed_mount3a;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first inode we look at is the journal inode. Don't try
|
* The first inode we look at is the journal inode. Don't try
|
||||||
|
@ -3952,7 +3956,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
if (!test_opt(sb, NOLOAD) &&
|
if (!test_opt(sb, NOLOAD) &&
|
||||||
EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
|
EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
|
||||||
if (ext4_load_journal(sb, es, journal_devnum))
|
if (ext4_load_journal(sb, es, journal_devnum))
|
||||||
goto failed_mount3;
|
goto failed_mount3a;
|
||||||
} else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
|
} else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
|
||||||
EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
|
EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
|
||||||
ext4_msg(sb, KERN_ERR, "required journal recovery "
|
ext4_msg(sb, KERN_ERR, "required journal recovery "
|
||||||
|
@ -4240,6 +4244,7 @@ failed_mount_wq:
|
||||||
jbd2_journal_destroy(sbi->s_journal);
|
jbd2_journal_destroy(sbi->s_journal);
|
||||||
sbi->s_journal = NULL;
|
sbi->s_journal = NULL;
|
||||||
}
|
}
|
||||||
|
failed_mount3a:
|
||||||
ext4_es_unregister_shrinker(sbi);
|
ext4_es_unregister_shrinker(sbi);
|
||||||
failed_mount3:
|
failed_mount3:
|
||||||
del_timer_sync(&sbi->s_err_report);
|
del_timer_sync(&sbi->s_err_report);
|
||||||
|
@ -4841,6 +4846,14 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||||
goto restore_opts;
|
goto restore_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
|
||||||
|
test_opt(sb, JOURNAL_CHECKSUM)) {
|
||||||
|
ext4_msg(sb, KERN_ERR, "changing journal_checksum "
|
||||||
|
"during remount not supported");
|
||||||
|
err = -EINVAL;
|
||||||
|
goto restore_opts;
|
||||||
|
}
|
||||||
|
|
||||||
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
|
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
|
||||||
if (test_opt2(sb, EXPLICIT_DELALLOC)) {
|
if (test_opt2(sb, EXPLICIT_DELALLOC)) {
|
||||||
ext4_msg(sb, KERN_ERR, "can't mount with "
|
ext4_msg(sb, KERN_ERR, "can't mount with "
|
||||||
|
|
|
@ -92,6 +92,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/bio.h>
|
#include <linux/bio.h>
|
||||||
#include <linux/log2.h>
|
#include <linux/log2.h>
|
||||||
|
#include <linux/hash.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct kmem_cache *jbd2_revoke_record_cache;
|
static struct kmem_cache *jbd2_revoke_record_cache;
|
||||||
|
@ -130,16 +131,9 @@ static void flush_descriptor(journal_t *, struct buffer_head *, int, int);
|
||||||
|
|
||||||
/* Utility functions to maintain the revoke table */
|
/* Utility functions to maintain the revoke table */
|
||||||
|
|
||||||
/* Borrowed from buffer.c: this is a tried and tested block hash function */
|
|
||||||
static inline int hash(journal_t *journal, unsigned long long block)
|
static inline int hash(journal_t *journal, unsigned long long block)
|
||||||
{
|
{
|
||||||
struct jbd2_revoke_table_s *table = journal->j_revoke;
|
return hash_64(block, journal->j_revoke->hash_shift);
|
||||||
int hash_shift = table->hash_shift;
|
|
||||||
int hash = (int)block ^ (int)((block >> 31) >> 1);
|
|
||||||
|
|
||||||
return ((hash << (hash_shift - 6)) ^
|
|
||||||
(hash >> 13) ^
|
|
||||||
(hash << (hash_shift - 12))) & (table->hash_size - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
|
static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
|
||||||
|
|
Loading…
Reference in a new issue