f2fs: shrink unreferenced extent_caches first
authorJaegeuk Kim <jaegeuk@kernel.org>
Mon, 29 Jun 2015 23:34:39 +0000 (16:34 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 4 Aug 2015 21:09:57 +0000 (14:09 -0700)
If an extent_tree entry has a zero reference count, we can drop it from the
cache in higher priority rather than currently referencing entries.

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

index 3e4402f661d7f471c97eadd70a16a189f2cb426c..c9d0f8b06d15438b721309b7f705877a7e6b21c9 100644 (file)
@@ -662,21 +662,54 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
        struct radix_tree_root *root = &sbi->extent_tree_root;
        unsigned int found;
        unsigned int node_cnt = 0, tree_cnt = 0;
+       int remained;
 
        if (!test_opt(sbi, EXTENT_CACHE))
                return 0;
 
+       if (!down_write_trylock(&sbi->extent_tree_lock))
+               goto out;
+
+       /* 1. remove unreferenced extent tree */
+       while ((found = radix_tree_gang_lookup(root,
+                               (void **)treevec, ino, EXT_TREE_VEC_SIZE))) {
+               unsigned i;
+
+               ino = treevec[found - 1]->ino + 1;
+               for (i = 0; i < found; i++) {
+                       struct extent_tree *et = treevec[i];
+
+                       if (!atomic_read(&et->refcount)) {
+                               write_lock(&et->lock);
+                               node_cnt += __free_extent_tree(sbi, et, true);
+                               write_unlock(&et->lock);
+
+                               radix_tree_delete(root, et->ino);
+                               kmem_cache_free(extent_tree_slab, et);
+                               sbi->total_ext_tree--;
+                               tree_cnt++;
+
+                               if (node_cnt + tree_cnt >= nr_shrink)
+                                       goto unlock_out;
+                       }
+               }
+       }
+       up_write(&sbi->extent_tree_lock);
+
+       /* 2. remove LRU extent entries */
+       if (!down_write_trylock(&sbi->extent_tree_lock))
+               goto out;
+
+       remained = nr_shrink - (node_cnt + tree_cnt);
+
        spin_lock(&sbi->extent_lock);
        list_for_each_entry_safe(en, tmp, &sbi->extent_list, list) {
-               if (!nr_shrink--)
+               if (!remained--)
                        break;
                list_del_init(&en->list);
        }
        spin_unlock(&sbi->extent_lock);
 
-       if (!down_write_trylock(&sbi->extent_tree_lock))
-               goto out;
-
        while ((found = radix_tree_gang_lookup(root,
                                (void **)treevec, ino, EXT_TREE_VEC_SIZE))) {
                unsigned i;
@@ -688,14 +721,12 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
                        write_lock(&et->lock);
                        node_cnt += __free_extent_tree(sbi, et, false);
                        write_unlock(&et->lock);
-                       if (!atomic_read(&et->refcount) && !et->count) {
-                               radix_tree_delete(root, et->ino);
-                               kmem_cache_free(extent_tree_slab, et);
-                               sbi->total_ext_tree--;
-                               tree_cnt++;
-                       }
+
+                       if (node_cnt + tree_cnt >= nr_shrink)
+                               break;
                }
        }
+unlock_out:
        up_write(&sbi->extent_tree_lock);
 out:
        trace_f2fs_shrink_extent_tree(sbi, node_cnt, tree_cnt);