Commit 32e8fd2f 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 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
parents e2488ab6 ae9e9c6a
...@@ -3603,11 +3603,10 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ...@@ -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) ...@@ -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 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, ...@@ -887,6 +887,10 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -4240,6 +4244,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
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) ...@@ -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 @@ ...@@ -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); ...@@ -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,
......
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