Commit 2a158d54 authored by Zhang Yi's avatar Zhang Yi
Browse files

ext4: fall back to buffer_head path for defrag

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I9DN5Z


CVE: NA

--------------------------------

Online defrag doesn't support iomap path yet, we have to fall back to
buffer_head path for the inode which has been using iomap. Changing
active inode is dangerous, before we start, we must hold the inode lock
and the mapping->invalidate_lock, and writeback all dirty folios and
drop the inode's pagecache.

Signed-off-by: default avatarZhang Yi <yi.zhang@huawei.com>
parent ed8d1152
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -539,6 +539,34 @@ mext_check_arguments(struct inode *orig_inode,
	return 0;
}

/*
 * Disable buffered iomap path for the inode that requiring move extents,
 * fallback to buffer_head path.
 */
static int ext4_disable_buffered_iomap_aops(struct inode *inode)
{
	int err;

	/*
	 * The buffered_head aops don't know how to handle folios
	 * dirtied by iomap, so before falling back, flush all dirty
	 * folios the inode has.
	 */
	filemap_invalidate_lock(inode->i_mapping);
	err = filemap_write_and_wait(inode->i_mapping);
	if (err < 0) {
		filemap_invalidate_unlock(inode->i_mapping);
		return err;
	}
	truncate_inode_pages(inode->i_mapping, 0);

	ext4_clear_inode_state(inode, EXT4_STATE_BUFFERED_IOMAP);
	ext4_set_aops(inode);
	filemap_invalidate_unlock(inode->i_mapping);

	return 0;
}

/**
 * ext4_move_extents - Exchange the specified range of a file
 *
@@ -610,6 +638,12 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
	inode_dio_wait(orig_inode);
	inode_dio_wait(donor_inode);

	/* Fallback to buffer_head aops for inodes with buffered iomap aops */
	if (ext4_test_inode_state(orig_inode, EXT4_STATE_BUFFERED_IOMAP))
		ext4_disable_buffered_iomap_aops(orig_inode);
	if (ext4_test_inode_state(donor_inode, EXT4_STATE_BUFFERED_IOMAP))
		ext4_disable_buffered_iomap_aops(donor_inode);

	/* Protect extent tree against block allocations via delalloc */
	ext4_double_down_write_data_sem(orig_inode, donor_inode);
	/* Check the filesystem environment whether move_extent can be done */