f2fs: fix to stop filesystem update once CP failed
authorChao Yu <chao@kernel.org>
Wed, 4 Aug 2021 00:38:38 +0000 (08:38 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 4 Aug 2021 01:08:29 +0000 (18:08 -0700)
During f2fs_write_checkpoint(), once we failed in
f2fs_flush_nat_entries() or do_checkpoint(), metadata of filesystem
such as prefree bitmap, nat/sit version bitmap won't be recovered,
it may cause f2fs image to be inconsistent, let's just set CP error
flag to avoid further updates until we figure out a scheme to rollback
all metadatas in such condition.

Reported-by: Yangtao Li <frank.li@vivo.com>
Signed-off-by: Yangtao Li <frank.li@vivo.com>
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/checkpoint.c
fs/f2fs/f2fs.h
fs/f2fs/segment.c

index 6c20810..7f6745f 100644 (file)
@@ -1639,8 +1639,11 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        /* write cached NAT/SIT entries to NAT/SIT area */
        err = f2fs_flush_nat_entries(sbi, cpc);
-       if (err)
+       if (err) {
+               f2fs_err(sbi, "f2fs_flush_nat_entries failed err:%d, stop checkpoint", err);
+               f2fs_bug_on(sbi, !f2fs_cp_error(sbi));
                goto stop;
+       }
 
        f2fs_flush_sit_entries(sbi, cpc);
 
@@ -1648,10 +1651,13 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        f2fs_save_inmem_curseg(sbi);
 
        err = do_checkpoint(sbi, cpc);
-       if (err)
+       if (err) {
+               f2fs_err(sbi, "do_checkpoint failed err:%d, stop checkpoint", err);
+               f2fs_bug_on(sbi, !f2fs_cp_error(sbi));
                f2fs_release_discard_addrs(sbi);
-       else
+       } else {
                f2fs_clear_prefree_segments(sbi, cpc);
+       }
 
        f2fs_restore_inmem_curseg(sbi);
 stop:
index 1b4c482..d24fd50 100644 (file)
@@ -547,7 +547,7 @@ enum {
                                         */
 };
 
-#define DEFAULT_RETRY_IO_COUNT 8       /* maximum retry read IO count */
+#define DEFAULT_RETRY_IO_COUNT 8       /* maximum retry read IO or flush count */
 
 /* congestion wait timeout value, default: 20ms */
 #define        DEFAULT_IO_TIMEOUT      (msecs_to_jiffies(20))
index 80f2615..ca9876a 100644 (file)
@@ -776,11 +776,22 @@ int f2fs_flush_device_cache(struct f2fs_sb_info *sbi)
                return 0;
 
        for (i = 1; i < sbi->s_ndevs; i++) {
+               int count = DEFAULT_RETRY_IO_COUNT;
+
                if (!f2fs_test_bit(i, (char *)&sbi->dirty_device))
                        continue;
-               ret = __submit_flush_wait(sbi, FDEV(i).bdev);
-               if (ret)
+
+               do {
+                       ret = __submit_flush_wait(sbi, FDEV(i).bdev);
+                       if (ret)
+                               congestion_wait(BLK_RW_ASYNC,
+                                               DEFAULT_IO_TIMEOUT);
+               } while (ret && --count);
+
+               if (ret) {
+                       f2fs_stop_checkpoint(sbi, false);
                        break;
+               }
 
                spin_lock(&sbi->dev_lock);
                f2fs_clear_bit(i, (char *)&sbi->dirty_device);