f2fs: introduce mempool for {,de}compress intermediate page allocation
authorChao Yu <yuchao0@huawei.com>
Wed, 8 Apr 2020 11:56:05 +0000 (19:56 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 12 May 2020 03:35:51 +0000 (20:35 -0700)
If compression feature is on, in scenario of no enough free memory,
page refault ratio is higher than before, the root cause is:
- {,de}compression flow needs to allocate intermediate pages to store
compressed data in cluster, so during their allocation, vm may reclaim
mmaped pages.
- if above reclaimed pages belong to compressed cluster, during its
refault, it may cause more intermediate pages allocation, result in
reclaiming more mmaped pages.

So this patch introduces a mempool for intermediate page allocation,
in order to avoid high refault ratio, by default, number of
preallocated page in pool is 512, user can change the number by
assigning 'num_compress_pages' parameter during module initialization.

Ma Feng found warnings in the original patch and fixed like below.

Fix the following sparse warning:
fs/f2fs/compress.c:501:5: warning: symbol 'num_compress_pages' was not declared.
 Should it be static?
fs/f2fs/compress.c:530:6: warning: symbol 'f2fs_compress_free_page' was not
declared. Should it be static?

Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Ma Feng <mafeng.ma@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/compress.c
fs/f2fs/f2fs.h
fs/f2fs/super.c

index d6283e3..230ea7c 100644 (file)
@@ -65,15 +65,6 @@ static void f2fs_set_compressed_page(struct page *page,
        page->mapping = inode->i_mapping;
 }
 
-static void f2fs_put_compressed_page(struct page *page)
-{
-       set_page_private(page, (unsigned long)NULL);
-       ClearPagePrivate(page);
-       page->mapping = NULL;
-       unlock_page(page);
-       put_page(page);
-}
-
 static void f2fs_drop_rpages(struct compress_ctx *cc, int len, bool unlock)
 {
        int i;
@@ -476,17 +467,47 @@ bool f2fs_is_compress_backend_ready(struct inode *inode)
        return f2fs_cops[F2FS_I(inode)->i_compress_algorithm];
 }
 
-static struct page *f2fs_grab_page(void)
+static mempool_t *compress_page_pool = NULL;
+static int num_compress_pages = 512;
+module_param(num_compress_pages, uint, 0444);
+MODULE_PARM_DESC(num_compress_pages,
+               "Number of intermediate compress pages to preallocate");
+
+int f2fs_init_compress_mempool(void)
+{
+       compress_page_pool = mempool_create_page_pool(num_compress_pages, 0);
+       if (!compress_page_pool)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void f2fs_destroy_compress_mempool(void)
+{
+       mempool_destroy(compress_page_pool);
+}
+
+static struct page *f2fs_compress_alloc_page(void)
 {
        struct page *page;
 
-       page = alloc_page(GFP_NOFS);
-       if (!page)
-               return NULL;
+       page = mempool_alloc(compress_page_pool, GFP_NOFS);
        lock_page(page);
+
        return page;
 }
 
+static void f2fs_compress_free_page(struct page *page)
+{
+       if (!page)
+               return;
+       set_page_private(page, (unsigned long)NULL);
+       ClearPagePrivate(page);
+       page->mapping = NULL;
+       unlock_page(page);
+       mempool_free(page, compress_page_pool);
+}
+
 static int f2fs_compress_pages(struct compress_ctx *cc)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode);
@@ -516,7 +537,7 @@ static int f2fs_compress_pages(struct compress_ctx *cc)
        }
 
        for (i = 0; i < cc->nr_cpages; i++) {
-               cc->cpages[i] = f2fs_grab_page();
+               cc->cpages[i] = f2fs_compress_alloc_page();
                if (!cc->cpages[i]) {
                        ret = -ENOMEM;
                        goto out_free_cpages;
@@ -561,7 +582,7 @@ static int f2fs_compress_pages(struct compress_ctx *cc)
        vunmap(cc->rbuf);
 
        for (i = nr_cpages; i < cc->nr_cpages; i++) {
-               f2fs_put_compressed_page(cc->cpages[i]);
+               f2fs_compress_free_page(cc->cpages[i]);
                cc->cpages[i] = NULL;
        }
 
@@ -581,7 +602,7 @@ out_vunmap_rbuf:
 out_free_cpages:
        for (i = 0; i < cc->nr_cpages; i++) {
                if (cc->cpages[i])
-                       f2fs_put_compressed_page(cc->cpages[i]);
+                       f2fs_compress_free_page(cc->cpages[i]);
        }
        kfree(cc->cpages);
        cc->cpages = NULL;
@@ -1183,7 +1204,7 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
        if (unlikely(bio->bi_status))
                mapping_set_error(cic->inode->i_mapping, -EIO);
 
-       f2fs_put_compressed_page(page);
+       f2fs_compress_free_page(page);
 
        dec_page_count(sbi, F2FS_WB_DATA);
 
@@ -1344,7 +1365,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
        for (i = 0; i < dic->nr_cpages; i++) {
                struct page *page;
 
-               page = f2fs_grab_page();
+               page = f2fs_compress_alloc_page();
                if (!page)
                        goto out_free;
 
@@ -1364,7 +1385,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
                        continue;
                }
 
-               dic->tpages[i] = f2fs_grab_page();
+               dic->tpages[i] = f2fs_compress_alloc_page();
                if (!dic->tpages[i])
                        goto out_free;
        }
@@ -1386,8 +1407,7 @@ void f2fs_free_dic(struct decompress_io_ctx *dic)
                                continue;
                        if (!dic->tpages[i])
                                continue;
-                       unlock_page(dic->tpages[i]);
-                       put_page(dic->tpages[i]);
+                       f2fs_compress_free_page(dic->tpages[i]);
                }
                kfree(dic->tpages);
        }
@@ -1396,7 +1416,7 @@ void f2fs_free_dic(struct decompress_io_ctx *dic)
                for (i = 0; i < dic->nr_cpages; i++) {
                        if (!dic->cpages[i])
                                continue;
-                       f2fs_put_compressed_page(dic->cpages[i]);
+                       f2fs_compress_free_page(dic->cpages[i]);
                }
                kfree(dic->cpages);
        }
index cc7a7a0..d098b94 100644 (file)
@@ -3829,6 +3829,8 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
 int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock);
 void f2fs_compress_write_end_io(struct bio *bio, struct page *page);
 bool f2fs_is_compress_backend_ready(struct inode *inode);
+int f2fs_init_compress_mempool(void);
+void f2fs_destroy_compress_mempool(void);
 void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity);
 bool f2fs_cluster_is_empty(struct compress_ctx *cc);
 bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index);
@@ -3862,6 +3864,8 @@ static inline struct page *f2fs_compress_control_page(struct page *page)
        WARN_ON_ONCE(1);
        return ERR_PTR(-EINVAL);
 }
+static inline int f2fs_init_compress_mempool(void) { return 0; }
+static inline void f2fs_destroy_compress_mempool(void) { }
 #endif
 
 static inline void set_compress_context(struct inode *inode)
index d0a705e..1b170fc 100644 (file)
@@ -3879,7 +3879,12 @@ static int __init init_f2fs_fs(void)
        err = f2fs_init_bioset();
        if (err)
                goto free_bio_enrty_cache;
+       err = f2fs_init_compress_mempool();
+       if (err)
+               goto free_bioset;
        return 0;
+free_bioset:
+       f2fs_destroy_bioset();
 free_bio_enrty_cache:
        f2fs_destroy_bio_entry_cache();
 free_post_read:
@@ -3907,6 +3912,7 @@ fail:
 
 static void __exit exit_f2fs_fs(void)
 {
+       f2fs_destroy_compress_mempool();
        f2fs_destroy_bioset();
        f2fs_destroy_bio_entry_cache();
        f2fs_destroy_post_read_processing();