btrfs: prepare compression paths for large data folios
authorQu Wenruo <wqu@suse.com>
Mon, 7 Apr 2025 08:43:33 +0000 (18:13 +0930)
committerDavid Sterba <dsterba@suse.com>
Thu, 15 May 2025 12:30:45 +0000 (14:30 +0200)
All compression algorithms inside btrfs are not supporting large folios
due to the following points:

- btrfs_calc_input_length() is assuming page sized folio

- kmap_local_folio() usages are using offset_in_page()

Prepare them to support large data folios by:

- Add a folio parameter to btrfs_calc_input_length()
  And use that folio parameter to calculate the correct length.

  Since we're here, also add extra ASSERT()s to make sure the parameter
  @cur is inside the folio range.

  This affects only zlib and zstd. Lzo compresses at most one block at a
  time, thus not affected.

- Use offset_in_folio() to calculate the kmap_local_folio() offset
  This affects all 3 algorithms.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/compression.h
fs/btrfs/lzo.c
fs/btrfs/zlib.c
fs/btrfs/zstd.c

index df198623cc08435e3f954857839dcdbf553e3520..d34c4341eaf485dc949633ba99104613db7849de 100644 (file)
@@ -11,7 +11,9 @@
 #include <linux/list.h>
 #include <linux/workqueue.h>
 #include <linux/wait.h>
+#include <linux/pagemap.h>
 #include "bio.h"
+#include "messages.h"
 
 struct address_space;
 struct page;
@@ -73,11 +75,14 @@ struct compressed_bio {
 };
 
 /* @range_end must be exclusive. */
-static inline u32 btrfs_calc_input_length(u64 range_end, u64 cur)
+static inline u32 btrfs_calc_input_length(struct folio *folio, u64 range_end, u64 cur)
 {
-       u64 page_end = round_down(cur, PAGE_SIZE) + PAGE_SIZE;
+       const u64 folio_end = folio_pos(folio) + folio_size(folio);
 
-       return min(range_end, page_end) - cur;
+       /* @cur must be inside the folio. */
+       ASSERT(folio_pos(folio) <= cur);
+       ASSERT(cur < folio_end);
+       return min(range_end, folio_end) - cur;
 }
 
 int __init btrfs_init_compress(void);
index a45bc11f866531b95fc4a4384a6e646b764741dd..d403641889caf3346b241833c58f97faa34a67bf 100644 (file)
@@ -252,9 +252,8 @@ int lzo_compress_folios(struct list_head *ws, struct address_space *mapping,
                /* Compress at most one sector of data each time */
                in_len = min_t(u32, start + len - cur_in, sectorsize - sector_off);
                ASSERT(in_len);
-               data_in = kmap_local_folio(folio_in, 0);
-               ret = lzo1x_1_compress(data_in +
-                                      offset_in_page(cur_in), in_len,
+               data_in = kmap_local_folio(folio_in, offset_in_folio(folio_in, cur_in));
+               ret = lzo1x_1_compress(data_in, in_len,
                                       workspace->cbuf, &out_len,
                                       workspace->mem);
                kunmap_local(data_in);
index 11be4f2498bad6b7119976e962712c6c3cf2a51b..5292cd341f70f24e2046f3834f9c217584944e38 100644 (file)
@@ -203,7 +203,6 @@ int zlib_compress_folios(struct list_head *ws, struct address_space *mapping,
                                workspace->strm.next_in = workspace->buf;
                                workspace->strm.avail_in = copy_length;
                        } else {
-                               unsigned int pg_off;
                                unsigned int cur_len;
 
                                if (data_in) {
@@ -215,9 +214,9 @@ int zlib_compress_folios(struct list_head *ws, struct address_space *mapping,
                                                start, &in_folio);
                                if (ret < 0)
                                        goto out;
-                               pg_off = offset_in_page(start);
-                               cur_len = btrfs_calc_input_length(orig_end, start);
-                               data_in = kmap_local_folio(in_folio, pg_off);
+                               cur_len = btrfs_calc_input_length(in_folio, orig_end, start);
+                               data_in = kmap_local_folio(in_folio,
+                                                          offset_in_folio(in_folio, start));
                                start += cur_len;
                                workspace->strm.next_in = data_in;
                                workspace->strm.avail_in = cur_len;
index 3541efa765c73f8c82d700c7f7688d0acf1ee12c..75efca4da194c6a7e7ddaa5594b59d6c87410c37 100644 (file)
@@ -426,8 +426,8 @@ int zstd_compress_folios(struct list_head *ws, struct address_space *mapping,
        ret = btrfs_compress_filemap_get_folio(mapping, start, &in_folio);
        if (ret < 0)
                goto out;
-       cur_len = btrfs_calc_input_length(orig_end, start);
-       workspace->in_buf.src = kmap_local_folio(in_folio, offset_in_page(start));
+       cur_len = btrfs_calc_input_length(in_folio, orig_end, start);
+       workspace->in_buf.src = kmap_local_folio(in_folio, offset_in_folio(in_folio, start));
        workspace->in_buf.pos = 0;
        workspace->in_buf.size = cur_len;
 
@@ -511,9 +511,9 @@ int zstd_compress_folios(struct list_head *ws, struct address_space *mapping,
                        ret = btrfs_compress_filemap_get_folio(mapping, start, &in_folio);
                        if (ret < 0)
                                goto out;
-                       cur_len = btrfs_calc_input_length(orig_end, start);
+                       cur_len = btrfs_calc_input_length(in_folio, orig_end, start);
                        workspace->in_buf.src = kmap_local_folio(in_folio,
-                                                        offset_in_page(start));
+                                                        offset_in_folio(in_folio, start));
                        workspace->in_buf.pos = 0;
                        workspace->in_buf.size = cur_len;
                }