Unverified Commit 43f46df2 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!8925 ext4: avoid deadlock in fs reclaim with page writeback

parents 5e37324a a2daf91f
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/falloc.h>
#include <linux/percpu-rwsem.h>
#include <linux/fiemap.h>
#include <linux/sched/mm.h>
#ifdef __KERNEL__
#include <linux/compat.h>
#endif
@@ -1701,6 +1702,30 @@ static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
	return container_of(inode, struct ext4_inode_info, vfs_inode);
}

static inline int ext4_writepages_down_read(struct super_block *sb)
{
	percpu_down_read(&EXT4_SB(sb)->s_writepages_rwsem);
	return memalloc_nofs_save();
}

static inline void ext4_writepages_up_read(struct super_block *sb, int ctx)
{
	memalloc_nofs_restore(ctx);
	percpu_up_read(&EXT4_SB(sb)->s_writepages_rwsem);
}

static inline int ext4_writepages_down_write(struct super_block *sb)
{
	percpu_down_write(&EXT4_SB(sb)->s_writepages_rwsem);
	return memalloc_nofs_save();
}

static inline void ext4_writepages_up_write(struct super_block *sb, int ctx)
{
	memalloc_nofs_restore(ctx);
	percpu_up_write(&EXT4_SB(sb)->s_writepages_rwsem);
}

static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
{
	return ino == EXT4_ROOT_INO ||
+10 −8
Original line number Diff line number Diff line
@@ -2692,13 +2692,14 @@ static int ext4_writepages(struct address_space *mapping,
	struct blk_plug plug;
	bool give_up_on_write = false;
	unsigned long retry_warn_ddl = 0;
	int alloc_ctx;

#define RETRY_WARN_TIMEOUT (30 * HZ)

	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
		return -EIO;

	percpu_down_read(&sbi->s_writepages_rwsem);
	alloc_ctx = ext4_writepages_down_read(inode->i_sb);
	trace_ext4_writepages(inode, wbc);

	/*
@@ -2919,7 +2920,7 @@ static int ext4_writepages(struct address_space *mapping,
out_writepages:
	trace_ext4_writepages_result(inode, wbc, ret,
				     nr_to_write - wbc->nr_to_write);
	percpu_up_read(&sbi->s_writepages_rwsem);
	ext4_writepages_up_read(inode->i_sb, alloc_ctx);
	return ret;
}

@@ -2930,17 +2931,18 @@ static int ext4_dax_writepages(struct address_space *mapping,
	long nr_to_write = wbc->nr_to_write;
	struct inode *inode = mapping->host;
	struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
	int alloc_ctx;

	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
		return -EIO;

	percpu_down_read(&sbi->s_writepages_rwsem);
	alloc_ctx = ext4_writepages_down_read(inode->i_sb);
	trace_ext4_writepages(inode, wbc);

	ret = dax_writeback_mapping_range(mapping, sbi->s_daxdev, wbc);
	trace_ext4_writepages_result(inode, wbc, ret,
				     nr_to_write - wbc->nr_to_write);
	percpu_up_read(&sbi->s_writepages_rwsem);
	ext4_writepages_up_read(inode->i_sb, alloc_ctx);
	return ret;
}

@@ -6095,7 +6097,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
	journal_t *journal;
	handle_t *handle;
	int err;
	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
	int alloc_ctx;

	/*
	 * We have to be very careful here: changing a data block's
@@ -6133,7 +6135,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
		}
	}

	percpu_down_write(&sbi->s_writepages_rwsem);
	alloc_ctx = ext4_writepages_down_write(inode->i_sb);
	jbd2_journal_lock_updates(journal);

	/*
@@ -6150,7 +6152,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
		err = jbd2_journal_flush(journal);
		if (err < 0) {
			jbd2_journal_unlock_updates(journal);
			percpu_up_write(&sbi->s_writepages_rwsem);
			ext4_writepages_up_write(inode->i_sb, alloc_ctx);
			return err;
		}
		ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
@@ -6158,7 +6160,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
	ext4_set_aops(inode);

	jbd2_journal_unlock_updates(journal);
	percpu_up_write(&sbi->s_writepages_rwsem);
	ext4_writepages_up_write(inode->i_sb, alloc_ctx);

	if (val)
		up_write(&EXT4_I(inode)->i_mmap_sem);
+6 −5
Original line number Diff line number Diff line
@@ -409,7 +409,6 @@ static int free_ext_block(handle_t *handle, struct inode *inode)

int ext4_ext_migrate(struct inode *inode)
{
	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
	handle_t *handle;
	int retval = 0, i;
	__le32 *i_data;
@@ -419,6 +418,7 @@ int ext4_ext_migrate(struct inode *inode)
	unsigned long max_entries;
	__u32 goal, tmp_csum_seed;
	uid_t owner[2];
	int alloc_ctx;

	/*
	 * If the filesystem does not support extents, or the inode
@@ -435,7 +435,7 @@ int ext4_ext_migrate(struct inode *inode)
		 */
		return retval;

	percpu_down_write(&sbi->s_writepages_rwsem);
	alloc_ctx = ext4_writepages_down_write(inode->i_sb);

	/*
	 * Worst case we can touch the allocation bitmaps and a block
@@ -587,7 +587,7 @@ int ext4_ext_migrate(struct inode *inode)
	unlock_new_inode(tmp_inode);
	iput(tmp_inode);
out_unlock:
	percpu_up_write(&sbi->s_writepages_rwsem);
	ext4_writepages_up_write(inode->i_sb, alloc_ctx);
	return retval;
}

@@ -606,6 +606,7 @@ int ext4_ind_migrate(struct inode *inode)
	ext4_fsblk_t			blk;
	handle_t			*handle;
	int				ret, ret2 = 0;
	int				alloc_ctx;

	if (!ext4_has_feature_extents(inode->i_sb) ||
	    (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
@@ -622,7 +623,7 @@ int ext4_ind_migrate(struct inode *inode)
	if (test_opt(inode->i_sb, DELALLOC))
		ext4_alloc_da_blocks(inode);

	percpu_down_write(&sbi->s_writepages_rwsem);
	alloc_ctx = ext4_writepages_down_write(inode->i_sb);

	handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
	if (IS_ERR(handle)) {
@@ -666,6 +667,6 @@ int ext4_ind_migrate(struct inode *inode)
	ext4_journal_stop(handle);
	up_write(&EXT4_I(inode)->i_data_sem);
out_unlock:
	percpu_up_write(&sbi->s_writepages_rwsem);
	ext4_writepages_up_write(inode->i_sb, alloc_ctx);
	return ret;
}
+7 −5
Original line number Diff line number Diff line
@@ -5986,6 +5986,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
	ext4_group_t g;
	unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
	int err = 0;
	int alloc_ctx;
#ifdef CONFIG_QUOTA
	int enable_quota = 0;
	int i, j;
@@ -6039,13 +6040,13 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
	 * here s_writepages_rwsem to avoid race between writepages ops and
	 * remount.
	 */
	percpu_down_write(&sbi->s_writepages_rwsem);
	alloc_ctx = ext4_writepages_down_write(sb);
	if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {
		err = -EINVAL;
		percpu_up_write(&sbi->s_writepages_rwsem);
		ext4_writepages_up_write(sb, alloc_ctx);
		goto restore_opts;
	}
	percpu_up_write(&sbi->s_writepages_rwsem);
	ext4_writepages_up_write(sb, alloc_ctx);

	if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
	    test_opt(sb, JOURNAL_CHECKSUM)) {
@@ -6272,7 +6273,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
	if ((sb->s_flags & SB_RDONLY) && !(old_sb_flags & SB_RDONLY) &&
	    sb_any_quota_suspended(sb))
		dquot_resume(sb, -1);
	percpu_down_write(&sbi->s_writepages_rwsem);

	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;
@@ -6281,7 +6283,7 @@ 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);
	ext4_writepages_up_write(sb, alloc_ctx);

	if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks)
		ext4_release_system_zone(sb);