f2fs: write small sized IO to hot log
authorJaegeuk Kim <jaegeuk@kernel.org>
Sat, 25 Mar 2017 00:05:13 +0000 (20:05 -0400)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 5 Apr 2017 18:05:05 +0000 (11:05 -0700)
It would better split small and large IOs separately in order to get more
consecutive big writes.

The default threshold is set to 64KB, but configurable by sysfs/min_hot_blocks.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/inline.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c

index 0904132..8f36080 100644 (file)
@@ -1432,6 +1432,8 @@ write:
                need_balance_fs = true;
        else if (has_not_enough_free_secs(sbi, 0, 0))
                goto redirty_out;
+       else
+               set_inode_flag(inode, FI_HOT_DATA);
 
        err = -EAGAIN;
        if (f2fs_has_inline_data(inode)) {
@@ -1457,6 +1459,7 @@ out:
        if (wbc->for_reclaim) {
                f2fs_submit_merged_bio_cond(sbi, inode, 0, page->index,
                                                DATA, WRITE);
+               clear_inode_flag(inode, FI_HOT_DATA);
                remove_dirty_inode(inode);
                submitted = NULL;
        }
@@ -1511,6 +1514,12 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
 
        pagevec_init(&pvec, 0);
 
+       if (get_dirty_pages(mapping->host) <=
+                               SM_I(F2FS_M_SB(mapping))->min_hot_blocks)
+               set_inode_flag(mapping->host, FI_HOT_DATA);
+       else
+               clear_inode_flag(mapping->host, FI_HOT_DATA);
+
        if (wbc->range_cyclic) {
                writeback_index = mapping->writeback_index; /* prev offset */
                index = writeback_index;
index 43b6e1e..fc90e53 100644 (file)
@@ -677,6 +677,7 @@ struct f2fs_sm_info {
        unsigned int ipu_policy;        /* in-place-update policy */
        unsigned int min_ipu_util;      /* in-place-update threshold */
        unsigned int min_fsync_blocks;  /* threshold for fsync */
+       unsigned int min_hot_blocks;    /* threshold for hot block allocation */
 
        /* for flush command control */
        struct flush_cmd_control *fcc_info;
@@ -1716,6 +1717,7 @@ enum {
        FI_DO_DEFRAG,           /* indicate defragment is running */
        FI_DIRTY_FILE,          /* indicate regular/symlink has dirty pages */
        FI_NO_PREALLOC,         /* indicate skipped preallocated blocks */
+       FI_HOT_DATA,            /* indicate file is hot */
 };
 
 static inline void __mark_inode_dirty_flag(struct inode *inode,
index 701bbd8..031c3d7 100644 (file)
@@ -137,6 +137,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
        /* write data page to try to make data consistent */
        set_page_writeback(page);
        fio.old_blkaddr = dn->data_blkaddr;
+       set_inode_flag(dn->inode, FI_HOT_DATA);
        write_data_page(dn, &fio);
        f2fs_wait_on_page_writeback(page, DATA, true);
        if (dirty) {
index 12d2aa7..b749cff 100644 (file)
@@ -1829,18 +1829,16 @@ static int __get_segment_type_6(struct page *page, enum page_type p_type)
        if (p_type == DATA) {
                struct inode *inode = page->mapping->host;
 
-               if (S_ISDIR(inode->i_mode))
-                       return CURSEG_HOT_DATA;
-               else if (is_cold_data(page) || file_is_cold(inode))
+               if (is_cold_data(page) || file_is_cold(inode))
                        return CURSEG_COLD_DATA;
-               else
-                       return CURSEG_WARM_DATA;
+               if (is_inode_flag_set(inode, FI_HOT_DATA))
+                       return CURSEG_HOT_DATA;
+               return CURSEG_WARM_DATA;
        } else {
                if (IS_DNODE(page))
                        return is_cold_node(page) ? CURSEG_WARM_NODE :
                                                CURSEG_HOT_NODE;
-               else
-                       return CURSEG_COLD_NODE;
+               return CURSEG_COLD_NODE;
        }
 }
 
@@ -2947,6 +2945,7 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
                sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC;
        sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
        sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
+       sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS;
 
        sm_info->trim_sections = DEF_BATCHED_TRIM_SECTIONS;
 
index 31846b0..57e36c1 100644 (file)
@@ -540,6 +540,7 @@ static inline int utilization(struct f2fs_sb_info *sbi)
  */
 #define DEF_MIN_IPU_UTIL       70
 #define DEF_MIN_FSYNC_BLOCKS   8
+#define DEF_MIN_HOT_BLOCKS     16
 
 enum {
        F2FS_IPU_FORCE,
index f315b54..2e2e1b4 100644 (file)
@@ -296,6 +296,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
 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_fsync_blocks, min_fsync_blocks);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_hot_blocks, min_hot_blocks);
 F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
 F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
 F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio);
@@ -321,6 +322,7 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(ipu_policy),
        ATTR_LIST(min_ipu_util),
        ATTR_LIST(min_fsync_blocks),
+       ATTR_LIST(min_hot_blocks),
        ATTR_LIST(max_victim_search),
        ATTR_LIST(dir_level),
        ATTR_LIST(ram_thresh),