summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCliff Chen <cliff.chen@rock-chips.com>2019-06-24 08:51:09 +0800
committerTao Huang <huangtao@rock-chips.com>2019-06-24 14:11:46 +0800
commit12992228b67ec8fbba3281b492e1191c0c2dd1c2 (patch)
tree0c056cbbeee4250ca46261a3ba0545c2d061db75
parenta1a13306a4a8f8f78a8cf0cdd4b26322a0ce667d (diff)
f2fs: Fix recovery is too slow when power fail on much fsync
By default fsync option, if fsync is called frequently, and suddenly lost power, the POR will consume too much memory at mounting, this process may be very slow due to a large number of swapping. Change-Id: I8235098cca062d7ab58af4ebed414aed9aba6c75 Signed-off-by: Cliff Chen <cliff.chen@rock-chips.com>
-rw-r--r--fs/f2fs/f2fs.h2
-rw-r--r--fs/f2fs/file.c23
-rw-r--r--fs/f2fs/super.c3
3 files changed, 27 insertions, 1 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 2c10b09d9bcf..fb96427997f4 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1335,6 +1335,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 637a9dfbd578..78f0c3b78427 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -198,6 +198,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)
{
@@ -205,6 +224,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,
@@ -223,6 +243,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 = filemap_write_and_wait_range(inode->i_mapping, start, end);
@@ -263,7 +284,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 463b21e3cd78..84eaa5e76d69 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1140,6 +1140,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);
mutex_lock(&sbi->gc_mutex);
err = f2fs_write_checkpoint(sbi, &cpc);
mutex_unlock(&sbi->gc_mutex);
@@ -3305,6 +3306,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;