btrfs: use page alloc/free wrappers for compression pages
authorDavid Sterba <dsterba@suse.com>
Wed, 15 Nov 2023 16:59:39 +0000 (17:59 +0100)
committerDavid Sterba <dsterba@suse.com>
Fri, 15 Dec 2023 19:27:01 +0000 (20:27 +0100)
This is a preparation for managing compression pages in a cache-like
manner, instead of asking the allocator each time. The common allocation
and free wrappers are introduced and are functionally equivalent to the
current code.

The freeing helpers need to be carefully placed where the last reference
is dropped.  This is either after directly allocating (error handling)
or when there are no other users of the pages (after copying the contents).

It's safe to not use the helper and use put_page() that will handle the
reference count. Not using the helper means there's lower number of
pages that could be reused without passing them back to allocator.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/inode.c
fs/btrfs/lzo.c
fs/btrfs/zlib.c
fs/btrfs/zstd.c

index 19b22b4653c83b4fb3694f54e6d26a9d621d3e95..1cd15d6a9c49c7cab79444bdfe939c15e2994c11 100644 (file)
@@ -163,12 +163,26 @@ static int compression_decompress(int type, struct list_head *ws,
 static void btrfs_free_compressed_pages(struct compressed_bio *cb)
 {
        for (unsigned int i = 0; i < cb->nr_pages; i++)
-               put_page(cb->compressed_pages[i]);
+               btrfs_free_compr_page(cb->compressed_pages[i]);
        kfree(cb->compressed_pages);
 }
 
 static int btrfs_decompress_bio(struct compressed_bio *cb);
 
+/*
+ * Common wrappers for page allocation from compression wrappers
+ */
+struct page *btrfs_alloc_compr_page(void)
+{
+       return alloc_page(GFP_NOFS);
+}
+
+void btrfs_free_compr_page(struct page *page)
+{
+       ASSERT(page_ref_count(page) == 1);
+       put_page(page);
+}
+
 static void end_compressed_bio_read(struct btrfs_bio *bbio)
 {
        struct compressed_bio *cb = to_compressed_bio(bbio);
index 03bb9d143fa75d115308dffb0ee2d38e90c78c03..93cc92974deee4cebb4fd25d38118f2c046e1840 100644 (file)
@@ -32,6 +32,8 @@ static_assert((BTRFS_MAX_COMPRESSED % PAGE_SIZE) == 0);
 
 #define        BTRFS_ZLIB_DEFAULT_LEVEL                3
 
+struct page;
+
 struct compressed_bio {
        /* Number of compressed pages in the array */
        unsigned int nr_pages;
@@ -96,6 +98,9 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio);
 
 unsigned int btrfs_compress_str2level(unsigned int type, const char *str);
 
+struct page *btrfs_alloc_compr_page(void);
+void btrfs_free_compr_page(struct page *page);
+
 enum btrfs_compression_type {
        BTRFS_COMPRESS_NONE  = 0,
        BTRFS_COMPRESS_ZLIB  = 1,
index fb3c3f43c3fa401da09ad815ae815e47e92087e3..3305472453f9473ccce729cf95a0c6f206ec9a14 100644 (file)
@@ -1037,7 +1037,7 @@ free_pages:
        if (pages) {
                for (i = 0; i < nr_pages; i++) {
                        WARN_ON(pages[i]->mapping);
-                       put_page(pages[i]);
+                       btrfs_free_compr_page(pages[i]);
                }
                kfree(pages);
        }
@@ -1052,7 +1052,7 @@ static void free_async_extent_pages(struct async_extent *async_extent)
 
        for (i = 0; i < async_extent->nr_pages; i++) {
                WARN_ON(async_extent->pages[i]->mapping);
-               put_page(async_extent->pages[i]);
+               btrfs_free_compr_page(async_extent->pages[i]);
        }
        kfree(async_extent->pages);
        async_extent->nr_pages = 0;
index d3fcfc628a4fe58ff275a4460cd86bf4c7e4981b..1131d5a29d612ee50e14c488b1812a0657c259f1 100644 (file)
@@ -152,7 +152,7 @@ static int copy_compressed_data_to_page(char *compressed_data,
        cur_page = out_pages[*cur_out / PAGE_SIZE];
        /* Allocate a new page */
        if (!cur_page) {
-               cur_page = alloc_page(GFP_NOFS);
+               cur_page = btrfs_alloc_compr_page();
                if (!cur_page)
                        return -ENOMEM;
                out_pages[*cur_out / PAGE_SIZE] = cur_page;
@@ -178,7 +178,7 @@ static int copy_compressed_data_to_page(char *compressed_data,
                cur_page = out_pages[*cur_out / PAGE_SIZE];
                /* Allocate a new page */
                if (!cur_page) {
-                       cur_page = alloc_page(GFP_NOFS);
+                       cur_page = btrfs_alloc_compr_page();
                        if (!cur_page)
                                return -ENOMEM;
                        out_pages[*cur_out / PAGE_SIZE] = cur_page;
index 6c231a116a29cbebbbc5691a2035a24f611746d9..36cf1f0e338e2f59d736aaeb1001e00e8eaddaa3 100644 (file)
@@ -121,7 +121,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
        workspace->strm.total_in = 0;
        workspace->strm.total_out = 0;
 
-       out_page = alloc_page(GFP_NOFS);
+       out_page = btrfs_alloc_compr_page();
        if (out_page == NULL) {
                ret = -ENOMEM;
                goto out;
@@ -200,7 +200,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
                                ret = -E2BIG;
                                goto out;
                        }
-                       out_page = alloc_page(GFP_NOFS);
+                       out_page = btrfs_alloc_compr_page();
                        if (out_page == NULL) {
                                ret = -ENOMEM;
                                goto out;
@@ -236,7 +236,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
                                ret = -E2BIG;
                                goto out;
                        }
-                       out_page = alloc_page(GFP_NOFS);
+                       out_page = btrfs_alloc_compr_page();
                        if (out_page == NULL) {
                                ret = -ENOMEM;
                                goto out;
index 5511766485cdd6a9d6cae03b5696ef7e29e710a5..0d66db8bc1d4774835348a1aa71b827371aebb65 100644 (file)
@@ -410,9 +410,8 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
        workspace->in_buf.pos = 0;
        workspace->in_buf.size = min_t(size_t, len, PAGE_SIZE);
 
-
        /* Allocate and map in the output buffer */
-       out_page = alloc_page(GFP_NOFS);
+       out_page = btrfs_alloc_compr_page();
        if (out_page == NULL) {
                ret = -ENOMEM;
                goto out;
@@ -457,7 +456,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
                                ret = -E2BIG;
                                goto out;
                        }
-                       out_page = alloc_page(GFP_NOFS);
+                       out_page = btrfs_alloc_compr_page();
                        if (out_page == NULL) {
                                ret = -ENOMEM;
                                goto out;
@@ -514,7 +513,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
                        ret = -E2BIG;
                        goto out;
                }
-               out_page = alloc_page(GFP_NOFS);
+               out_page = btrfs_alloc_compr_page();
                if (out_page == NULL) {
                        ret = -ENOMEM;
                        goto out;