f2fs: enable rb-tree extent cache
authorChao Yu <chao2.yu@samsung.com>
Thu, 5 Feb 2015 09:57:31 +0000 (17:57 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 3 Mar 2015 17:58:47 +0000 (09:58 -0800)
This patch enables rb-tree based extent cache in f2fs.

When we mount with "-o extent_cache", f2fs will try to add recently accessed
page-block mappings into rb-tree based extent cache as much as possible, instead
of original one extent info cache.

By this way, f2fs can support more effective cache between dnode page cache and
disk. It will supply high hit ratio in the cache with fewer memory when dnode
page cache are reclaimed in environment of low memory.

Storage: Sandisk sd card 64g
1.append write file (offset: 0, size: 128M);
2.override write file (offset: 2M, size: 1M);
3.override write file (offset: 4M, size: 1M);
...
4.override write file (offset: 48M, size: 1M);
...
5.override write file (offset: 112M, size: 1M);
6.sync
7.echo 3 > /proc/sys/vm/drop_caches
8.read file (size:128M, unit: 4k, count: 32768)
(time dd if=/mnt/f2fs/128m bs=4k count=32768)

Extent Hit Ratio:
before patched
Hit Ratio 121 / 1071 1071 / 1071

Performance:
before patched
real     0m37.051s 0m35.556s
user     0m0.040s 0m0.026s
sys      0m2.990s 0m2.251s

Memory Cost:
before patched
Tree Count: 0 1 (size: 24 bytes)
Node Count: 0 45 (size: 1440 bytes)

v3:
 o retest and given more details of test result.

Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/data.c
fs/f2fs/inode.c
fs/f2fs/segment.c
fs/f2fs/super.c

index f52745346205bece0b3a218ea93cda7422828201..acdc0767f77c66779852a4ed1088b98b9f5f95e1 100644 (file)
@@ -666,6 +666,9 @@ void f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
        void **slot;
        unsigned int found;
 
+       if (!test_opt(sbi, EXTENT_CACHE))
+               return;
+
        if (available_free_memory(sbi, EXTENT_CACHE))
                return;
 
@@ -714,6 +717,9 @@ void f2fs_destroy_extent_tree(struct inode *inode)
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct extent_tree *et;
 
+       if (!test_opt(sbi, EXTENT_CACHE))
+               return;
+
        down_read(&sbi->extent_tree_lock);
        et = radix_tree_lookup(&sbi->extent_tree_root, inode->i_ino);
        if (!et) {
@@ -749,6 +755,9 @@ out:
 static bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs,
                                                        struct extent_info *ei)
 {
+       if (test_opt(F2FS_I_SB(inode), EXTENT_CACHE))
+               return f2fs_lookup_extent_tree(inode, pgofs, ei);
+
        return lookup_extent_info(inode, pgofs, ei);
 }
 
@@ -765,6 +774,10 @@ void f2fs_update_extent_cache(struct dnode_of_data *dn)
        fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
                                                        dn->ofs_in_node;
 
+       if (test_opt(F2FS_I_SB(dn->inode), EXTENT_CACHE))
+               return f2fs_update_extent_tree(dn->inode, fofs,
+                                                       dn->data_blkaddr);
+
        if (update_extent_info(dn->inode, fofs, dn->data_blkaddr))
                sync_inode_page(dn);
 }
index 28dd26a502769e77ab0a5022cb6351db80bd0d6b..b5087443be411a58f9d670f3d537da18829b394a 100644 (file)
@@ -335,6 +335,7 @@ void f2fs_evict_inode(struct inode *inode)
 no_delete:
        stat_dec_inline_dir(inode);
        stat_dec_inline_inode(inode);
+       f2fs_destroy_extent_tree(inode);
        invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
        if (xnid)
                invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
index daee4ab913daf2bcd2883aeee28ff2e8975d02bd..29c04edcb84302801d3c91215f42ef9b12734ae7 100644 (file)
@@ -277,6 +277,9 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi)
 
 void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
 {
+       /* try to shrink extent cache when there is no enough memory */
+       f2fs_shrink_extent_tree(sbi, EXTENT_CACHE_SHRINK_NUMBER);
+
        /* check the # of cached NAT entries and prefree segments */
        if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK) ||
                        excess_prefree_segs(sbi) ||
index 3ce4d7c9a29d080558cc1058b1f8c5596c499611..e649f21121d2927dc0d5d36f2c2fba97b5815e34 100644 (file)
@@ -1079,6 +1079,8 @@ try_onemore:
        INIT_LIST_HEAD(&sbi->dir_inode_list);
        spin_lock_init(&sbi->dir_inode_lock);
 
+       init_extent_cache_info(sbi);
+
        init_ino_entry_info(sbi);
 
        /* setup f2fs internal modules */
@@ -1285,10 +1287,13 @@ static int __init init_f2fs_fs(void)
        err = create_checkpoint_caches();
        if (err)
                goto free_segment_manager_caches;
+       err = create_extent_cache();
+       if (err)
+               goto free_checkpoint_caches;
        f2fs_kset = kset_create_and_add("f2fs", NULL, fs_kobj);
        if (!f2fs_kset) {
                err = -ENOMEM;
-               goto free_checkpoint_caches;
+               goto free_extent_cache;
        }
        err = register_filesystem(&f2fs_fs_type);
        if (err)
@@ -1299,6 +1304,8 @@ static int __init init_f2fs_fs(void)
 
 free_kset:
        kset_unregister(f2fs_kset);
+free_extent_cache:
+       destroy_extent_cache();
 free_checkpoint_caches:
        destroy_checkpoint_caches();
 free_segment_manager_caches: