f2fs: give an option to enable in-place-updates during fsync to users

If user wrote F2FS_IPU_FSYNC:4 in /sys/fs/f2fs/ipu_policy, f2fs_sync_file
only starts to try in-place-updates.
And, if the number of dirty pages is over /sys/fs/f2fs/min_fsync_blocks, it
keeps out-of-order manner. Otherwise, it triggers in-place-updates.

This may be used by storage showing very high random write performance.

For example, it can be used when,

Seq. writes (Data) + wait + Seq. writes (Node)

is pretty much slower than,

Rand. writes (Data)

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Jaegeuk Kim 2014-09-10 16:53:02 -07:00
parent a7ffdbe22c
commit c1ce1b02bb
7 changed files with 33 additions and 10 deletions

View File

@ -44,6 +44,13 @@ Description:
Controls the FS utilization condition for the in-place-update Controls the FS utilization condition for the in-place-update
policies. policies.
What: /sys/fs/f2fs/<disk>/min_fsync_blocks
Date: September 2014
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description:
Controls the dirty page count condition for the in-place-update
policies.
What: /sys/fs/f2fs/<disk>/max_small_discards What: /sys/fs/f2fs/<disk>/max_small_discards
Date: November 2013 Date: November 2013
Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com> Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>

View File

@ -194,13 +194,20 @@ Files in /sys/fs/f2fs/<devname>
updates in f2fs. There are five policies: updates in f2fs. There are five policies:
0: F2FS_IPU_FORCE, 1: F2FS_IPU_SSR, 0: F2FS_IPU_FORCE, 1: F2FS_IPU_SSR,
2: F2FS_IPU_UTIL, 3: F2FS_IPU_SSR_UTIL, 2: F2FS_IPU_UTIL, 3: F2FS_IPU_SSR_UTIL,
4: F2FS_IPU_DISABLE. 4: F2FS_IPU_FSYNC, 5: F2FS_IPU_DISABLE.
min_ipu_util This parameter controls the threshold to trigger min_ipu_util This parameter controls the threshold to trigger
in-place-updates. The number indicates percentage in-place-updates. The number indicates percentage
of the filesystem utilization, and used by of the filesystem utilization, and used by
F2FS_IPU_UTIL and F2FS_IPU_SSR_UTIL policies. F2FS_IPU_UTIL and F2FS_IPU_SSR_UTIL policies.
min_fsync_blocks This parameter controls the threshold to trigger
in-place-updates when F2FS_IPU_FSYNC mode is set.
The number indicates the number of dirty pages
when fsync needs to flush on its call path. If
the number is less than this value, it triggers
in-place-updates.
max_victim_search This parameter controls the number of trials to max_victim_search This parameter controls the number of trials to
find a victim segment when conducting SSR and find a victim segment when conducting SSR and
cleaning operations. The default value is 4096 cleaning operations. The default value is 4096

View File

@ -386,6 +386,7 @@ struct f2fs_sm_info {
unsigned int ipu_policy; /* in-place-update policy */ unsigned int ipu_policy; /* in-place-update policy */
unsigned int min_ipu_util; /* in-place-update threshold */ unsigned int min_ipu_util; /* in-place-update threshold */
unsigned int min_fsync_blocks; /* threshold for fsync */
/* for flush command control */ /* for flush command control */
struct flush_cmd_control *cmd_control_info; struct flush_cmd_control *cmd_control_info;

View File

@ -154,12 +154,11 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
trace_f2fs_sync_file_enter(inode); trace_f2fs_sync_file_enter(inode);
/* if fdatasync is triggered, let's do in-place-update */ /* if fdatasync is triggered, let's do in-place-update */
if (datasync) if (get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
set_inode_flag(fi, FI_NEED_IPU); set_inode_flag(fi, FI_NEED_IPU);
ret = filemap_write_and_wait_range(inode->i_mapping, start, end); ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
if (datasync)
clear_inode_flag(fi, FI_NEED_IPU); clear_inode_flag(fi, FI_NEED_IPU);
if (ret) { if (ret) {
trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
return ret; return ret;

View File

@ -1928,8 +1928,9 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
sm_info->rec_prefree_segments = sm_info->main_segments * sm_info->rec_prefree_segments = sm_info->main_segments *
DEF_RECLAIM_PREFREE_SEGMENTS / 100; DEF_RECLAIM_PREFREE_SEGMENTS / 100;
sm_info->ipu_policy = F2FS_IPU_DISABLE; sm_info->ipu_policy = F2FS_IPU_FSYNC;
sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
INIT_LIST_HEAD(&sm_info->discard_list); INIT_LIST_HEAD(&sm_info->discard_list);
sm_info->nr_discards = 0; sm_info->nr_discards = 0;

View File

@ -472,15 +472,20 @@ static inline int utilization(struct f2fs_sb_info *sbi)
* F2FS_IPU_UTIL - if FS utilization is over threashold, * F2FS_IPU_UTIL - if FS utilization is over threashold,
* F2FS_IPU_SSR_UTIL - if SSR mode is activated and FS utilization is over * F2FS_IPU_SSR_UTIL - if SSR mode is activated and FS utilization is over
* threashold, * threashold,
* F2FS_IPU_FSYNC - activated in fsync path only for high performance flash
* storages. IPU will be triggered only if the # of dirty
* pages over min_fsync_blocks.
* F2FS_IPUT_DISABLE - disable IPU. (=default option) * F2FS_IPUT_DISABLE - disable IPU. (=default option)
*/ */
#define DEF_MIN_IPU_UTIL 70 #define DEF_MIN_IPU_UTIL 70
#define DEF_MIN_FSYNC_BLOCKS 8
enum { enum {
F2FS_IPU_FORCE, F2FS_IPU_FORCE,
F2FS_IPU_SSR, F2FS_IPU_SSR,
F2FS_IPU_UTIL, F2FS_IPU_UTIL,
F2FS_IPU_SSR_UTIL, F2FS_IPU_SSR_UTIL,
F2FS_IPU_FSYNC,
F2FS_IPU_DISABLE, F2FS_IPU_DISABLE,
}; };
@ -492,10 +497,6 @@ static inline bool need_inplace_update(struct inode *inode)
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
return false; return false;
/* this is only set during fdatasync */
if (is_inode_flag_set(F2FS_I(inode), FI_NEED_IPU))
return true;
switch (SM_I(sbi)->ipu_policy) { switch (SM_I(sbi)->ipu_policy) {
case F2FS_IPU_FORCE: case F2FS_IPU_FORCE:
return true; return true;
@ -511,6 +512,11 @@ static inline bool need_inplace_update(struct inode *inode)
if (need_SSR(sbi) && utilization(sbi) > SM_I(sbi)->min_ipu_util) if (need_SSR(sbi) && utilization(sbi) > SM_I(sbi)->min_ipu_util)
return true; return true;
break; break;
case F2FS_IPU_FSYNC:
/* this is only set during fdatasync */
if (is_inode_flag_set(F2FS_I(inode), FI_NEED_IPU))
return true;
break;
case F2FS_IPU_DISABLE: case F2FS_IPU_DISABLE:
break; break;
} }

View File

@ -190,6 +190,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
@ -204,6 +205,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(max_small_discards), ATTR_LIST(max_small_discards),
ATTR_LIST(ipu_policy), ATTR_LIST(ipu_policy),
ATTR_LIST(min_ipu_util), ATTR_LIST(min_ipu_util),
ATTR_LIST(min_fsync_blocks),
ATTR_LIST(max_victim_search), ATTR_LIST(max_victim_search),
ATTR_LIST(dir_level), ATTR_LIST(dir_level),
ATTR_LIST(ram_thresh), ATTR_LIST(ram_thresh),