]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
btrfs: prepare lzo to support bs > ps cases
authorQu Wenruo <wqu@suse.com>
Mon, 8 Sep 2025 08:51:47 +0000 (18:21 +0930)
committerDavid Sterba <dsterba@suse.com>
Tue, 23 Sep 2025 06:49:25 +0000 (08:49 +0200)
This involves converting the following functions to use correct folio
sizes/shifts:

- copy_compress_data_to_page()
- lzo_compress_folios()
- lzo_decompress_bio()

Just like zstd, lzo has some extra incorrect usage of kmap_local_folio()
that the offset is always 0.

This will not handle HIGHMEM large folios correctly, but those cases are
already rejected explicitly so it should not cause problems when bs > ps
support is enabled.

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/lzo.c

index c5a25fd872bdfcefc7b51b0255fdd77afe6a1aca..b93bdac91b30e725856a1f618fafe633707dc68b 100644 (file)
@@ -140,12 +140,13 @@ static int copy_compressed_data_to_page(struct btrfs_fs_info *fs_info,
                                        u32 *cur_out)
 {
        const u32 sectorsize = fs_info->sectorsize;
+       const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order;
        u32 sector_bytes_left;
        u32 orig_out;
        struct folio *cur_folio;
        char *kaddr;
 
-       if ((*cur_out / PAGE_SIZE) >= max_nr_folio)
+       if ((*cur_out >> min_folio_shift) >= max_nr_folio)
                return -E2BIG;
 
        /*
@@ -154,18 +155,17 @@ static int copy_compressed_data_to_page(struct btrfs_fs_info *fs_info,
         */
        ASSERT((*cur_out / sectorsize) == (*cur_out + LZO_LEN - 1) / sectorsize);
 
-       cur_folio = out_folios[*cur_out / PAGE_SIZE];
+       cur_folio = out_folios[*cur_out >> min_folio_shift];
        /* Allocate a new page */
        if (!cur_folio) {
                cur_folio = btrfs_alloc_compr_folio(fs_info);
                if (!cur_folio)
                        return -ENOMEM;
-               out_folios[*cur_out / PAGE_SIZE] = cur_folio;
+               out_folios[*cur_out >> min_folio_shift] = cur_folio;
        }
 
-       kaddr = kmap_local_folio(cur_folio, 0);
-       write_compress_length(kaddr + offset_in_page(*cur_out),
-                             compressed_size);
+       kaddr = kmap_local_folio(cur_folio, offset_in_folio(cur_folio, *cur_out));
+       write_compress_length(kaddr, compressed_size);
        *cur_out += LZO_LEN;
 
        orig_out = *cur_out;
@@ -177,20 +177,20 @@ static int copy_compressed_data_to_page(struct btrfs_fs_info *fs_info,
 
                kunmap_local(kaddr);
 
-               if ((*cur_out / PAGE_SIZE) >= max_nr_folio)
+               if ((*cur_out >> min_folio_shift) >= max_nr_folio)
                        return -E2BIG;
 
-               cur_folio = out_folios[*cur_out / PAGE_SIZE];
+               cur_folio = out_folios[*cur_out >> min_folio_shift];
                /* Allocate a new page */
                if (!cur_folio) {
                        cur_folio = btrfs_alloc_compr_folio(fs_info);
                        if (!cur_folio)
                                return -ENOMEM;
-                       out_folios[*cur_out / PAGE_SIZE] = cur_folio;
+                       out_folios[*cur_out >> min_folio_shift] = cur_folio;
                }
                kaddr = kmap_local_folio(cur_folio, 0);
 
-               memcpy(kaddr + offset_in_page(*cur_out),
+               memcpy(kaddr + offset_in_folio(cur_folio, *cur_out),
                       compressed_data + *cur_out - orig_out, copy_len);
 
                *cur_out += copy_len;
@@ -221,6 +221,7 @@ int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
        struct workspace *workspace = list_entry(ws, struct workspace, list);
        const u32 sectorsize = fs_info->sectorsize;
+       const u32 min_folio_size = btrfs_min_folio_size(fs_info);
        struct address_space *mapping = inode->vfs_inode.i_mapping;
        struct folio *folio_in = NULL;
        char *sizes_ptr;
@@ -287,8 +288,8 @@ int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
                        goto out;
                }
 
-               /* Check if we have reached page boundary */
-               if (PAGE_ALIGNED(cur_in)) {
+               /* Check if we have reached folio boundary. */
+               if (IS_ALIGNED(cur_in, min_folio_size)) {
                        folio_put(folio_in);
                        folio_in = NULL;
                }
@@ -305,7 +306,7 @@ int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
 out:
        if (folio_in)
                folio_put(folio_in);
-       *out_folios = DIV_ROUND_UP(cur_out, PAGE_SIZE);
+       *out_folios = DIV_ROUND_UP(cur_out, min_folio_size);
        return ret;
 }
 
@@ -317,15 +318,16 @@ out:
 static void copy_compressed_segment(struct compressed_bio *cb,
                                    char *dest, u32 len, u32 *cur_in)
 {
+       struct btrfs_fs_info *fs_info = cb_to_fs_info(cb);
+       const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order;
        u32 orig_in = *cur_in;
 
        while (*cur_in < orig_in + len) {
-               struct folio *cur_folio;
-               u32 copy_len = min_t(u32, PAGE_SIZE - offset_in_page(*cur_in),
-                                         orig_in + len - *cur_in);
+               struct folio *cur_folio = cb->compressed_folios[*cur_in >> min_folio_shift];
+               u32 copy_len = min_t(u32, orig_in + len - *cur_in,
+                                    folio_size(cur_folio) - offset_in_folio(cur_folio, *cur_in));
 
                ASSERT(copy_len);
-               cur_folio = cb->compressed_folios[*cur_in / PAGE_SIZE];
 
                memcpy_from_folio(dest + *cur_in - orig_in, cur_folio,
                                  offset_in_folio(cur_folio, *cur_in), copy_len);
@@ -339,6 +341,7 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
        struct workspace *workspace = list_entry(ws, struct workspace, list);
        const struct btrfs_fs_info *fs_info = cb->bbio.inode->root->fs_info;
        const u32 sectorsize = fs_info->sectorsize;
+       const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order;
        char *kaddr;
        int ret;
        /* Compressed data length, can be unaligned */
@@ -385,10 +388,10 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
                 */
                ASSERT(cur_in / sectorsize ==
                       (cur_in + LZO_LEN - 1) / sectorsize);
-               cur_folio = cb->compressed_folios[cur_in / PAGE_SIZE];
+               cur_folio = cb->compressed_folios[cur_in >> min_folio_shift];
                ASSERT(cur_folio);
                kaddr = kmap_local_folio(cur_folio, 0);
-               seg_len = read_compress_length(kaddr + offset_in_page(cur_in));
+               seg_len = read_compress_length(kaddr + offset_in_folio(cur_folio, cur_in));
                kunmap_local(kaddr);
                cur_in += LZO_LEN;