Commit 3cb88bc1 authored by Shin'ichiro Kawasaki's avatar Shin'ichiro Kawasaki Committed by Jaegeuk Kim
Browse files

f2fs: check zone type before sending async reset zone command



The commit 25f90805 ("f2fs: add async reset zone command support")
introduced "async reset zone commands" by calling
__submit_zone_reset_cmd() in async discard operations. However,
__submit_zone_reset_cmd() is called regardless of zone type of discard
target zone. When devices have conventional zones, zone reset commands
are sent to the conventional zones and cause I/O errors.

Avoid the I/O errors by checking that the discard target zone type is
sequential write required. If not, handle the discard operation in same
manner as non-zoned, regular block devices. For that purpose, add a new
helper function f2fs_bdev_index() which gets index of the zone reset
target device.

Fixes: 25f90805 ("f2fs: add async reset zone command support")
Signed-off-by: default avatarShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 025b3602
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -4423,6 +4423,22 @@ static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi,
}
#endif

static inline int f2fs_bdev_index(struct f2fs_sb_info *sbi,
				  struct block_device *bdev)
{
	int i;

	if (!f2fs_is_multi_device(sbi))
		return 0;

	for (i = 0; i < sbi->s_ndevs; i++)
		if (FDEV(i).bdev == bdev)
			return i;

	WARN_ON(1);
	return -1;
}

static inline bool f2fs_hw_should_discard(struct f2fs_sb_info *sbi)
{
	return f2fs_sb_has_blkzoned(sbi);
+28 −11
Original line number Diff line number Diff line
@@ -1260,9 +1260,17 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,

#ifdef CONFIG_BLK_DEV_ZONED
	if (f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(bdev)) {
		__submit_zone_reset_cmd(sbi, dc, flag, wait_list, issued);
		int devi = f2fs_bdev_index(sbi, bdev);

		if (devi < 0)
			return -EINVAL;

		if (f2fs_blkz_is_seq(sbi, devi, dc->di.start)) {
			__submit_zone_reset_cmd(sbi, dc, flag,
						wait_list, issued);
			return 0;
		}
	}
#endif

	trace_f2fs_issue_discard(bdev, dc->di.start, dc->di.len);
@@ -1787,6 +1795,14 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
	dc = __lookup_discard_cmd(sbi, blkaddr);
#ifdef CONFIG_BLK_DEV_ZONED
	if (dc && f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(dc->bdev)) {
		int devi = f2fs_bdev_index(sbi, dc->bdev);

		if (devi < 0) {
			mutex_unlock(&dcc->cmd_lock);
			return;
		}

		if (f2fs_blkz_is_seq(sbi, devi, dc->di.start)) {
			/* force submit zone reset */
			if (dc->state == D_PREP)
				__submit_zone_reset_cmd(sbi, dc, REQ_SYNC,
@@ -1797,6 +1813,7 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
			__wait_one_discard_bio(sbi, dc);
			return;
		}
	}
#endif
	if (dc) {
		if (dc->state == D_PREP) {