Merge tag 'vfs-6.7.fsid' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[linux-block.git] / fs / ext4 / super.c
index 42a44990d99c7e96a104dbebfe7cee578129add8..c5fcf377ab1faad832c9165fd2ed299d9c3e94f6 100644 (file)
@@ -244,18 +244,25 @@ static struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb,
 struct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block,
                                   blk_opf_t op_flags)
 {
-       return __ext4_sb_bread_gfp(sb, block, op_flags, __GFP_MOVABLE);
+       gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_inode->i_mapping,
+                       ~__GFP_FS) | __GFP_MOVABLE;
+
+       return __ext4_sb_bread_gfp(sb, block, op_flags, gfp);
 }
 
 struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb,
                                            sector_t block)
 {
-       return __ext4_sb_bread_gfp(sb, block, 0, 0);
+       gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_inode->i_mapping,
+                       ~__GFP_FS);
+
+       return __ext4_sb_bread_gfp(sb, block, 0, gfp);
 }
 
 void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block)
 {
-       struct buffer_head *bh = sb_getblk_gfp(sb, block, 0);
+       struct buffer_head *bh = bdev_getblk(sb->s_bdev, block,
+                       sb->s_blocksize, GFP_NOWAIT | __GFP_NOWARN);
 
        if (likely(bh)) {
                if (trylock_buffer(bh))
@@ -768,7 +775,8 @@ static void update_super_work(struct work_struct *work)
         */
        if (!sb_rdonly(sbi->s_sb) && journal) {
                struct buffer_head *sbh = sbi->s_sbh;
-               bool call_notify_err;
+               bool call_notify_err = false;
+
                handle = jbd2_journal_start(journal, 1);
                if (IS_ERR(handle))
                        goto write_directly;
@@ -1646,6 +1654,7 @@ static const struct super_operations ext4_sops = {
 };
 
 static const struct export_operations ext4_export_ops = {
+       .encode_fh = generic_encode_ino32_fh,
        .fh_to_dentry = ext4_fh_to_dentry,
        .fh_to_parent = ext4_fh_to_parent,
        .get_parent = ext4_get_parent,
@@ -6444,6 +6453,7 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb)
        struct ext4_mount_options old_opts;
        ext4_group_t g;
        int err = 0;
+       int alloc_ctx;
 #ifdef CONFIG_QUOTA
        int enable_quota = 0;
        int i, j;
@@ -6484,7 +6494,16 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb)
 
        }
 
+       /*
+        * Changing the DIOREAD_NOLOCK or DELALLOC mount options 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.
+        */
+       alloc_ctx = ext4_writepages_down_write(sb);
        ext4_apply_options(fc, sb);
+       ext4_writepages_up_write(sb, alloc_ctx);
 
        if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
            test_opt(sb, JOURNAL_CHECKSUM)) {
@@ -6702,6 +6721,8 @@ restore_opts:
        if (sb_rdonly(sb) && !(old_sb_flags & SB_RDONLY) &&
            sb_any_quota_suspended(sb))
                dquot_resume(sb, -1);
+
+       alloc_ctx = ext4_writepages_down_write(sb);
        sb->s_flags = old_sb_flags;
        sbi->s_mount_opt = old_opts.s_mount_opt;
        sbi->s_mount_opt2 = old_opts.s_mount_opt2;
@@ -6710,6 +6731,8 @@ restore_opts:
        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;
+       ext4_writepages_up_write(sb, alloc_ctx);
+
        if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks)
                ext4_release_system_zone(sb);
 #ifdef CONFIG_QUOTA