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 090413236b2780bed3fdf087483c27b10cb0815e..8f36080b47c4b8108d65d1171181bda9bdff908b 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 43b6e1eeceb6bd89a7236e6a46512f6b79da9eb2..fc90e5317159c11d1cd1ab92011e1aba2abc0ab4 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 701bbd8d10ba918d19d91e0b8064db93a4a28a51..031c3d78cbc61da8535261c6e9fe90e54ebf5eb6 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 12d2aa7032bba292fa339645bddbaec3bd1b9f08..b749cff59420041190b0df7472df58580dd0ac38 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 31846b0fcb957908f45e7cfbc3e6aa7e15a0373d..57e36c1ce7bdda172421db2dde8734960f84c680 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 f315b54cd840ccf37afc438485a19dd94a4f2cdd..2e2e1b438ce11c77b7e38cd150e3e7f2af62b2e7 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),