When sudden f2fs shutdown happens on zoned block devices, write
pointers can be inconsistent with valid blocks counts in meta data.
The failure scenario is as follows:

- Just before a sudden shutdown, a new segment in a new zone is selected
  for a current segment. Write commands were executed to the segment.
  and the zone has a write pointer not at zone start.
- Before the write commands complete, shutdown happens. Meta data is
  not updated and still keeps zero valid blocks count for the zone.
- After next mount of the file system, the zone is selected for the next
  write target because it has zero valid blocks count. However, it has
  the write pointer not at zone start. Then "Unaligned write command"
  error happens.

To avoid this potential error path, reset write pointers if the zone
does not have a current segment, the write pointer is not at the zone
start and the zone has no valid blocks.

Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawas...@wdc.com>
---
 fsck/fsck.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/fsck/fsck.c b/fsck/fsck.c
index 21a06ac..cc9bbc0 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -2595,6 +2595,7 @@ static int fsck_chk_write_pointer(int i, struct blk_zone 
*blkz, void *opaque)
        int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;
        unsigned int segs_per_zone = sbi->segs_per_sec * sbi->secs_per_zone;
        void *zero_blk;
+       block_t zone_valid_blocks = 0;
 
        if (blk_zone_conv(blkz))
                return 0;
@@ -2615,8 +2616,35 @@ static int fsck_chk_write_pointer(int i, struct blk_zone 
*blkz, void *opaque)
                        break;
        }
 
-       if (cs_index >= NR_CURSEG_TYPE)
+       if (cs_index >= NR_CURSEG_TYPE) {
+               for (b = zone_block; b < zone_block + c.zone_blocks &&
+                            IS_VALID_BLK_ADDR(sbi, b); b += c.blks_per_seg) {
+                       se = get_seg_entry(sbi, GET_SEGNO(sbi, b));
+                       zone_valid_blocks += se->valid_blocks;
+               }
+               if (wp_block == zone_block || zone_valid_blocks)
+                       return 0;
+
+               /*
+                * The write pointer is not at zone start but there is no valid
+                * block in the zone. Segments in the zone can be selected for
+                * next write. Need to reset the write pointer to avoid
+                * unaligned write command error.
+                */
+               if (c.fix_on) {
+                       FIX_MSG("Reset write pointer at segment 0x%x",
+                               zone_segno);
+                       ret = f2fs_reset_zone(dev, blkz);
+                       if (ret)
+                               return ret;
+                       fsck->chk.wp_fixed_zones++;
+               } else {
+                       MSG(0, "Inconsistent write pointer at segment 0x%x\n",
+                           zone_segno);
+                       fsck->chk.wp_inconsistent_zones++;
+               }
                return 0;
+       }
 
        /* check write pointer consistency with the curseg in the zone */
        cs_block = START_BLOCK(sbi, cs->segno) + cs->next_blkoff;
-- 
2.21.0



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to