diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4c88e75180a23b1e0161c65ae7e2fa88dc414c50..6df919b154b44ec11b0d54dc9f80bac7726fd65a 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1530,7 +1530,8 @@ struct ext4_sb_info { /* * Barrier between writepages ops and changing any inode's JOURNAL_DATA - * or EXTENTS flag. + * or EXTENTS flag or between writepages ops and changing DIOREAD_NOLOCK + * mount option on remount. */ struct percpu_rw_semaphore s_writepages_rwsem; struct dax_device *s_daxdev; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 8029a6f6471ca6f3692c067413da7e946a6d8533..df07222f1cc58f94d2ced51370269aa29767a1ad 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5605,10 +5605,20 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) vfs_flags = SB_LAZYTIME | SB_I_VERSION; sb->s_flags = (sb->s_flags & ~vfs_flags) | (*flags & vfs_flags); + /* + * Changing the DIOREAD_NOLOCK mount option may cause two calls to + * ext4_should_dioread_nolock() to return inconsistent values, + * triggering WARN_ON in ext4_add_complete_io(). we grab here + * s_writepages_rwsem to avoid race between writepages ops and + * remount. + */ + percpu_down_write(&sbi->s_writepages_rwsem); if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) { err = -EINVAL; + percpu_up_write(&sbi->s_writepages_rwsem); goto restore_opts; } + percpu_up_write(&sbi->s_writepages_rwsem); if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^ test_opt(sb, JOURNAL_CHECKSUM)) { @@ -5833,6 +5843,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) return 0; restore_opts: + percpu_down_write(&sbi->s_writepages_rwsem); sb->s_flags = old_sb_flags; sbi->s_mount_opt = old_opts.s_mount_opt; sbi->s_mount_opt2 = old_opts.s_mount_opt2; @@ -5841,6 +5852,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) sbi->s_commit_interval = old_opts.s_commit_interval; sbi->s_min_batch_time = old_opts.s_min_batch_time; sbi->s_max_batch_time = old_opts.s_max_batch_time; + percpu_up_write(&sbi->s_writepages_rwsem); + if (!test_opt(sb, BLOCK_VALIDITY) && sbi->system_blks) ext4_release_system_zone(sb); #ifdef CONFIG_QUOTA