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:
parent
a7ffdbe22c
commit
c1ce1b02bb
7 changed files with 33 additions and 10 deletions
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Reference in a new issue