diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 65f21b9aab79..7c33238694a2 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1551,6 +1551,8 @@ struct f2fs_sb_info { /* migration granularity of garbage collection, unit: segment */ unsigned int migration_granularity; + atomic_t no_cp_fsync_pages; + /* * for stat information. * one is for the LFS mode, and the other is for the SSR mode. diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 453bd12574c7..e464fba8d461 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -250,6 +250,25 @@ static void try_to_fix_pino(struct inode *inode) up_write(&fi->i_sem); } +static bool f2fs_update_fsync_count(struct f2fs_sb_info *sbi, + unsigned int npages) +{ + struct sysinfo val; + unsigned long avail_ram; + + si_meminfo(&val); + + /* only uses low memory */ + avail_ram = val.totalram - val.totalhigh; + avail_ram = (avail_ram * DEF_RAM_THRESHOLD) / 100; + + if ((atomic_read(&sbi->no_cp_fsync_pages) + npages) > avail_ram) + return false; + + atomic_add(npages, &sbi->no_cp_fsync_pages); + return true; +} + static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, int datasync, bool atomic) { @@ -257,6 +276,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, struct f2fs_sb_info *sbi = F2FS_I_SB(inode); nid_t ino = inode->i_ino; int ret = 0; + unsigned int npages = 0; enum cp_reason_type cp_reason = 0; struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, @@ -275,6 +295,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, goto go_write; /* if fdatasync is triggered, let's do in-place-update */ + npages = get_dirty_pages(inode); if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks) set_inode_flag(inode, FI_NEED_IPU); ret = file_write_and_wait_range(file, start, end); @@ -315,7 +336,7 @@ go_write: cp_reason = need_do_checkpoint(inode); up_read(&F2FS_I(inode)->i_sem); - if (cp_reason) { + if (cp_reason || !f2fs_update_fsync_count(sbi, npages)) { /* all the dirty node pages should be flushed for POR */ ret = f2fs_sync_fs(inode->i_sb, 1); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index aab614b2b84b..b55d8ae19b23 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1454,8 +1454,10 @@ int f2fs_sync_fs(struct super_block *sb, int sync) if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) return -EAGAIN; - if (sync) + if (sync) { err = f2fs_issue_checkpoint(sbi); + atomic_set(&sbi->no_cp_fsync_pages, 0); + } return err; } @@ -3874,6 +3876,8 @@ try_onemore: f2fs_build_gc_manager(sbi); + atomic_set(&sbi->no_cp_fsync_pages, 0); + err = f2fs_build_stats(sbi); if (err) goto free_nm;