btrfs: prepare compression paths for large data folios

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>
This commit is contained in:
Qu Wenruo 2025-04-07 18:13:33 +09:30 committed by David Sterba
parent 9a36bad6c3
commit 7bf9bfa946
4 changed files with 17 additions and 14 deletions

View 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);

View 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);

View 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;

View 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;
}