Skip to content

Commit 81ac4ae

Browse files
committed
btrfs: extract the compressed folio padding into a helper
Currently after btrfs_compress_folios(), we zero the tail folio at compress_file_range() after the btrfs_compress_folios() call. However there are several problems with the incoming block size > page size support: - We may need extra padding folios for the compressed data Or we will submit a write smaller than the block size. - The current folio tail zeroing is not covering extra padding folios Solve this problem by introducing a dedicated helper, pad_compressed_folios(), which will: - Do extra basic sanity checks Focusing on the @out_folios and @total_out values. - Zero the tailing folio Now we don't need to tail zeroing inside compress_file_range() anymore. - Add extra padding zero folios So that for bs > ps cases, the compressed data will always be bs aligned. This also implies we won't allocate dedicated large folios for compressed data. Finally since we're here, update the stale comments about btrfs_compress_folios(). Signed-off-by: Qu Wenruo <[email protected]> --- RFC v2->RFC v3: - Fix a failure related to inline compressed data (btrfs/246 failure) The check on whether the resulted compressed data should not happen until we're sure no inlined extent is going to be created. RFC v1->RFC v2: - Fix a check causes more strict condition for subpage cases Instead comparing the resulted compressed folios number, compare the resulted blocks number instead. For 64K page sized system with 4K block size, it will result any compressed data larger than 64K to be rejected. Even if the compression caused a pretty good result, e.g. 128K ->68K. - Remove an unused local variable Reason for RFC: Although this seems to be a preparation patch for bs > ps support, this one will determine the path we go for compressed folios. There are 2 methods I can come up with: - Allocate dedicated large folios following min_order for compressed folios This is the more common method, used by filemap and will be the method for page cache. The problem is, we will no longer share the compr_pool across all btrfs filesystems, and the dedicated per-fs pool will have a much harder time to fill its pool when memory is fragmented or under-pressure. The benefit is obvious, we will have the insurance that every folio will contain at least one block for bs > ps cases. - Allocate page sized folios but add extra padding folios for compressed folios The method I take in this patchset. The benefit is we can still use the shared compr folios pool, meaning a better latency filling the pool. The problem is we must manually pad the compressed folios. Thankfully the compressed folios are not filemap ones, we don't need to bother about the folio flags at all. Another problem is, we will have different handling for filemap and compressed folios. Filemap folios will have the min_order insurance, but not for compressed folios. I believe the inconsistency is still manageable, at least for now. Thus I leave this one as RFC, any feedback will be appreciated.
1 parent eeae4b3 commit 81ac4ae

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed

fs/btrfs/compression.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,43 @@ int btrfs_compress_filemap_get_folio(struct address_space *mapping, u64 start,
10241024
return 0;
10251025
}
10261026

1027+
/*
1028+
* Fill the range between (total_out, round_up(total_out, blocksize)) with zero.
1029+
*
1030+
* If bs > ps, also allocate extra folios to ensure the compressed folios are aligned
1031+
* to block size.
1032+
*/
1033+
static int pad_compressed_folios(struct btrfs_fs_info *fs_info, struct folio **folios,
1034+
unsigned long orig_len, unsigned long *out_folios,
1035+
unsigned long *total_out)
1036+
{
1037+
const unsigned long aligned_len = round_up(*total_out, fs_info->sectorsize);
1038+
const unsigned long aligned_nr_folios = aligned_len >> PAGE_SHIFT;
1039+
1040+
ASSERT(aligned_nr_folios <= BTRFS_MAX_COMPRESSED_PAGES);
1041+
ASSERT(*out_folios == DIV_ROUND_UP_POW2(*total_out, PAGE_SIZE),
1042+
"out_folios=%lu total_out=%lu", *out_folios, *total_out);
1043+
1044+
/* Zero the tailing part of the compressed folio. */
1045+
if (!IS_ALIGNED(*total_out, PAGE_SIZE))
1046+
folio_zero_range(folios[*total_out >> PAGE_SHIFT], offset_in_page(*total_out),
1047+
PAGE_SIZE - offset_in_page(*total_out));
1048+
1049+
/* Padding the compressed folios to blocksize. */
1050+
for (unsigned long cur = *out_folios; cur < aligned_nr_folios; cur++) {
1051+
struct folio *folio;
1052+
1053+
ASSERT(folios[cur] == NULL);
1054+
folio = btrfs_alloc_compr_folio();
1055+
if (!folio)
1056+
return -ENOMEM;
1057+
folios[cur] = folio;
1058+
folio_zero_range(folio, 0, PAGE_SIZE);
1059+
(*out_folios)++;
1060+
}
1061+
return 0;
1062+
}
1063+
10271064
/*
10281065
* Given an address space and start and length, compress the bytes into @pages
10291066
* that are allocated on demand.
@@ -1033,7 +1070,7 @@ int btrfs_compress_filemap_get_folio(struct address_space *mapping, u64 start,
10331070
* - compression algo are 0-3
10341071
* - the level are bits 4-7
10351072
*
1036-
* @out_pages is an in/out parameter, holds maximum number of pages to allocate
1073+
* @out_folios is an in/out parameter, holds maximum number of pages to allocate
10371074
* and returns number of actually allocated pages
10381075
*
10391076
* @total_in is used to return the number of bytes actually read. It
@@ -1060,6 +1097,9 @@ int btrfs_compress_folios(unsigned int type, int level, struct btrfs_inode *inod
10601097
/* The total read-in bytes should be no larger than the input. */
10611098
ASSERT(*total_in <= orig_len);
10621099
put_workspace(fs_info, type, workspace);
1100+
if (ret < 0)
1101+
return ret;
1102+
ret = pad_compressed_folios(fs_info, folios, orig_len, out_folios, total_out);
10631103
return ret;
10641104
}
10651105

fs/btrfs/inode.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,6 @@ static void compress_file_range(struct btrfs_work *work)
864864
unsigned long nr_folios;
865865
unsigned long total_compressed = 0;
866866
unsigned long total_in = 0;
867-
unsigned int poff;
868867
int i;
869868
int compress_type = fs_info->compress_type;
870869
int compress_level = fs_info->compress_level;
@@ -964,14 +963,6 @@ static void compress_file_range(struct btrfs_work *work)
964963
if (ret)
965964
goto mark_incompressible;
966965

967-
/*
968-
* Zero the tail end of the last page, as we might be sending it down
969-
* to disk.
970-
*/
971-
poff = offset_in_page(total_compressed);
972-
if (poff)
973-
folio_zero_range(folios[nr_folios - 1], poff, PAGE_SIZE - poff);
974-
975966
/*
976967
* Try to create an inline extent.
977968
*

0 commit comments

Comments
 (0)