Commit 7bf9bfa9 authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

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: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 9a36bad6
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -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);
+2 −3
Original line number Diff line number Diff line
@@ -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);
+3 −4
Original line number Diff line number Diff line
@@ -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;
+4 −4
Original line number Diff line number Diff line
@@ -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;
		}