diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 307893ca1bdc..9f6a028deec7 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1452,6 +1452,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 479d95b7e7b9..cda48a564ffa 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -227,6 +227,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) { @@ -234,6 +253,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, @@ -261,6 +281,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); @@ -301,7 +322,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 07a7e3ff4600..896c30e7c48d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1256,6 +1256,7 @@ int f2fs_sync_fs(struct super_block *sb, int sync) cpc.reason = __get_cp_reason(sbi); + atomic_set(&sbi->no_cp_fsync_pages, 0); down_write(&sbi->gc_lock); err = f2fs_write_checkpoint(sbi, &cpc); up_write(&sbi->gc_lock); @@ -3610,6 +3611,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;