f2fs: check zone type before sending async reset zone command
authorShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Fri, 4 Aug 2023 09:15:56 +0000 (18:15 +0900)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 14 Aug 2023 20:41:09 +0000 (13:41 -0700)
The commit 25f9080576b9 ("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: 25f9080576b9 ("f2fs: add async reset zone command support")
Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/f2fs.h
fs/f2fs/segment.c

index d372bed..a528309 100644 (file)
@@ -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);
index b254aaa..24596d0 100644 (file)
@@ -1260,8 +1260,16 @@ 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);
-               return 0;
+               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
 
@@ -1787,15 +1795,24 @@ 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)) {
-               /* force submit zone reset */
-               if (dc->state == D_PREP)
-                       __submit_zone_reset_cmd(sbi, dc, REQ_SYNC,
-                                               &dcc->wait_list, NULL);
-               dc->ref++;
-               mutex_unlock(&dcc->cmd_lock);
-               /* wait zone reset */
-               __wait_one_discard_bio(sbi, dc);
-               return;
+               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,
+                                                       &dcc->wait_list, NULL);
+                       dc->ref++;
+                       mutex_unlock(&dcc->cmd_lock);
+                       /* wait zone reset */
+                       __wait_one_discard_bio(sbi, dc);
+                       return;
+               }
        }
 #endif
        if (dc) {