aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Yu2020-11-24 20:57:36 -0600
committerJaegeuk Kim2020-12-21 15:33:14 -0600
commit34315f887206f21d03674d7e8dcbf50053154689 (patch)
treedd7428deee666c9d18f9731a7b1d5c3025d5fcf2
parent301e31717eb7c2f1df1d99af0b36d22c11e09326 (diff)
downloadkernel-34315f887206f21d03674d7e8dcbf50053154689.tar.gz
kernel-34315f887206f21d03674d7e8dcbf50053154689.tar.xz
kernel-34315f887206f21d03674d7e8dcbf50053154689.zip
f2fs: fix to avoid REQ_TIME and CP_TIME collision
Lei Li reported a issue: if foreground operations are frequent, background checkpoint may be always skipped due to below check, result in losing more data after sudden power-cut. f2fs_balance_fs_bg() ... if (!is_idle(sbi, REQ_TIME) && (!excess_dirty_nats(sbi) && !excess_dirty_nodes(sbi))) return; E.g: cp_interval = 5 second idle_interval = 2 second foreground operation interval = 1 second (append 1 byte per second into file) In such case, no matter when it calls f2fs_balance_fs_bg(), is_idle(, REQ_TIME) returns false, result in skipping background checkpoint. This patch changes as below to make trigger condition being more reasonable: - trigger sync_fs() if dirty_{nats,nodes} and prefree segs exceeds threshold; - skip triggering sync_fs() if there is any background inflight IO or there is foreground operation recently and meanwhile cp_rwsem is being held by someone; Reported-by: Lei Li <noctis.akm@gmail.com> Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/f2fs.h19
-rw-r--r--fs/f2fs/segment.c47
2 files changed, 40 insertions, 26 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 273f068e8899..0d25f5ca5618 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2400,24 +2400,31 @@ static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep,
2400 return entry; 2400 return entry;
2401} 2401}
2402 2402
2403static inline bool is_idle(struct f2fs_sb_info *sbi, int type) 2403static inline bool is_inflight_io(struct f2fs_sb_info *sbi, int type)
2404{ 2404{
2405 if (sbi->gc_mode == GC_URGENT_HIGH)
2406 return true;
2407
2408 if (get_pages(sbi, F2FS_RD_DATA) || get_pages(sbi, F2FS_RD_NODE) || 2405 if (get_pages(sbi, F2FS_RD_DATA) || get_pages(sbi, F2FS_RD_NODE) ||
2409 get_pages(sbi, F2FS_RD_META) || get_pages(sbi, F2FS_WB_DATA) || 2406 get_pages(sbi, F2FS_RD_META) || get_pages(sbi, F2FS_WB_DATA) ||
2410 get_pages(sbi, F2FS_WB_CP_DATA) || 2407 get_pages(sbi, F2FS_WB_CP_DATA) ||
2411 get_pages(sbi, F2FS_DIO_READ) || 2408 get_pages(sbi, F2FS_DIO_READ) ||
2412 get_pages(sbi, F2FS_DIO_WRITE)) 2409 get_pages(sbi, F2FS_DIO_WRITE))
2413 return false; 2410 return true;
2414 2411
2415 if (type != DISCARD_TIME && SM_I(sbi) && SM_I(sbi)->dcc_info && 2412 if (type != DISCARD_TIME && SM_I(sbi) && SM_I(sbi)->dcc_info &&
2416 atomic_read(&SM_I(sbi)->dcc_info->queued_discard)) 2413 atomic_read(&SM_I(sbi)->dcc_info->queued_discard))
2417 return false; 2414 return true;
2418 2415
2419 if (SM_I(sbi) && SM_I(sbi)->fcc_info && 2416 if (SM_I(sbi) && SM_I(sbi)->fcc_info &&
2420 atomic_read(&SM_I(sbi)->fcc_info->queued_flush)) 2417 atomic_read(&SM_I(sbi)->fcc_info->queued_flush))
2418 return true;
2419 return false;
2420}
2421
2422static inline bool is_idle(struct f2fs_sb_info *sbi, int type)
2423{
2424 if (sbi->gc_mode == GC_URGENT_HIGH)
2425 return true;
2426
2427 if (is_inflight_io(sbi, type))
2421 return false; 2428 return false;
2422 2429
2423 if (sbi->gc_mode == GC_URGENT_LOW && 2430 if (sbi->gc_mode == GC_URGENT_LOW &&
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 1596502f7375..d9e2e656764d 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -529,31 +529,38 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
529 else 529 else
530 f2fs_build_free_nids(sbi, false, false); 530 f2fs_build_free_nids(sbi, false, false);
531 531
532 if (!is_idle(sbi, REQ_TIME) && 532 if (excess_dirty_nats(sbi) || excess_dirty_nodes(sbi) ||
533 (!excess_dirty_nats(sbi) && !excess_dirty_nodes(sbi))) 533 excess_prefree_segs(sbi))
534 goto do_sync;
535
536 /* there is background inflight IO or foreground operation recently */
537 if (is_inflight_io(sbi, REQ_TIME) ||
538 (!f2fs_time_over(sbi, REQ_TIME) && rwsem_is_locked(&sbi->cp_rwsem)))
534 return; 539 return;
535 540
541 /* exceed periodical checkpoint timeout threshold */
542 if (f2fs_time_over(sbi, CP_TIME))
543 goto do_sync;
544
536 /* checkpoint is the only way to shrink partial cached entries */ 545 /* checkpoint is the only way to shrink partial cached entries */
537 if (!f2fs_available_free_memory(sbi, NAT_ENTRIES) || 546 if (f2fs_available_free_memory(sbi, NAT_ENTRIES) ||
538 !f2fs_available_free_memory(sbi, INO_ENTRIES) || 547 f2fs_available_free_memory(sbi, INO_ENTRIES))
539 excess_prefree_segs(sbi) || 548 return;
540 excess_dirty_nats(sbi) ||
541 excess_dirty_nodes(sbi) ||
542 f2fs_time_over(sbi, CP_TIME)) {
543 if (test_opt(sbi, DATA_FLUSH) && from_bg) {
544 struct blk_plug plug;
545
546 mutex_lock(&sbi->flush_lock);
547
548 blk_start_plug(&plug);
549 f2fs_sync_dirty_inodes(sbi, FILE_INODE);
550 blk_finish_plug(&plug);
551 549
552 mutex_unlock(&sbi->flush_lock); 550do_sync:
553 } 551 if (test_opt(sbi, DATA_FLUSH) && from_bg) {
554 f2fs_sync_fs(sbi->sb, true); 552 struct blk_plug plug;
555 stat_inc_bg_cp_count(sbi->stat_info); 553
554 mutex_lock(&sbi->flush_lock);
555
556 blk_start_plug(&plug);
557 f2fs_sync_dirty_inodes(sbi, FILE_INODE);
558 blk_finish_plug(&plug);
559
560 mutex_unlock(&sbi->flush_lock);
556 } 561 }
562 f2fs_sync_fs(sbi->sb, true);
563 stat_inc_bg_cp_count(sbi->stat_info);
557} 564}
558 565
559static int __submit_flush_wait(struct f2fs_sb_info *sbi, 566static int __submit_flush_wait(struct f2fs_sb_info *sbi,