]> git.hungrycats.org Git - linux/commitdiff
btrfs: refactor read_key_bytes() to remove the dest_folio parameter
authorQu Wenruo <wqu@suse.com>
Mon, 17 Aug 2026 07:30:43 +0000 (17:00 +0930)
committerDavid Sterba <dsterba@suse.com>
Mon, 14 Sep 2026 11:23:36 +0000 (13:23 +0200)
The function read_key_bytes() have 3 call sites:

- For BTRFS_VERITY_DESC_ITEM_KEY offset 0 inside btrfs_get_verity_descriptor()
- For BTRFS_VERITY_DESC_ITEM_KEY offset 1 inside btrfs_get_verity_descriptor()
  Those are to read the description items, which are pretty small with
  fixed item size.

  Those call sites do not utilize the @dest_folio parameter.

- For btrfs_read_merkle_tree_page()
  This is to read the BTRFS_VERITY_MERKLE_ITEM_KEY, which can be pretty
  large and split into multiple items.

  This is the only call site utilizing the @dest_folio parameter.

Just for the only btrfs_read_merkle_tree_page() call site, we have a
complex scheme for @dest and @dest_folio parameters.
Since @dest can be NULL, it means if we pass @dest as NULL, then no
matter if @dest_folio is provided, the merkle data will not be loaded
into that @dest_folio.

This can lead to a bug where a highmem folio is not mapped, then we pass
folio_address(folio), which is NULL, into read_key_bytes(), causing no
data to be written into @dest_folio.

To address the complex scheme between @dest and @dest_folio, remove the
@dest_folio parameter completely, and let the only caller to map the
folio and pass the mapped kernel address into read_key_bytes() instead.

This not only reduces the parameter list, but also make it much clear on
the @dest parameter handling.
The only downside is a longer duration of locally mapped page, but this
should still be fine, as kmap_local_folio() can survive context switch.

Reported-by: Hongling Zeng <zenghongling@kylinos.cn>
Link: https://lore.kernel.org/linux-btrfs/20260817022012.19658-1-zenghongling@kylinos.cn/
Fixes: 146054090b08 ("btrfs: initial fsverity support")
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/verity.c

index 4e0ab584227419d5f1e220d74e8f5d27e6ffedd2..d432fec21c15bbf5f63cb064090e7502449dae71 100644 (file)
@@ -272,21 +272,17 @@ static int write_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset,
  * @dest:       Buffer to read into. This parameter has slightly tricky
  *              semantics.  If it is NULL, the function will not do any copying
  *              and will just return the size of all the items up to len bytes.
- *              If dest_page is passed, then the function will kmap_local the
- *              page and ignore dest, but it must still be non-NULL to avoid the
- *              counting-only behavior.
  * @len:        length in bytes to read
- * @dest_folio: copy into this folio instead of the dest buffer
  *
  * Helper function to read items from the btree.  This returns the number of
  * bytes read or < 0 for errors.  We can return short reads if the items don't
  * exist on disk or aren't big enough to fill the desired length.  Supports
- * reading into a provided buffer (dest) or into the page cache
+ * reading into a provided buffer (dest).
  *
  * Returns number of bytes read or a negative error code on failure.
  */
 static int read_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset,
-                         char *dest, u64 len, struct folio *dest_folio)
+                         char *dest, u64 len)
 {
        BTRFS_PATH_AUTO_FREE(path);
        struct btrfs_root *root = inode->root;
@@ -306,7 +302,11 @@ static int read_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset,
        if (!path)
                return -ENOMEM;
 
-       if (dest_folio)
+       /*
+        * Merkle items can be large and split across multiple items, so enable
+        * readahead for such cases.
+        */
+       if (key_type == BTRFS_VERITY_MERKLE_ITEM_KEY)
                path->reada = READA_FORWARD;
 
        key.objectid = btrfs_ino(inode);
@@ -350,7 +350,7 @@ static int read_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset,
                                break;
                }
 
-               /* des= NULL to just sum all the item lengths */
+               /* dest == NULL to just sum all the item lengths */
                if (!dest)
                        copy_end = item_end;
                else
@@ -363,16 +363,10 @@ static int read_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset,
                copy_offset = offset - key.offset;
 
                if (dest) {
-                       if (dest_folio)
-                               kaddr = kmap_local_folio(dest_folio, 0);
-
                        data = btrfs_item_ptr(leaf, path->slots[0], void);
                        read_extent_buffer(leaf, kaddr + dest_offset,
                                           (unsigned long)data + copy_offset,
                                           copy_bytes);
-
-                       if (dest_folio)
-                               kunmap_local(kaddr);
                }
 
                offset += copy_bytes;
@@ -663,7 +657,7 @@ int btrfs_get_verity_descriptor(struct inode *inode, void *buf, size_t buf_size)
 
        memset(&item, 0, sizeof(item));
        ret = read_key_bytes(BTRFS_I(inode), BTRFS_VERITY_DESC_ITEM_KEY, 0,
-                            (char *)&item, sizeof(item), NULL);
+                            (char *)&item, sizeof(item));
        if (ret < 0)
                return ret;
 
@@ -680,7 +674,7 @@ int btrfs_get_verity_descriptor(struct inode *inode, void *buf, size_t buf_size)
                return -ERANGE;
 
        ret = read_key_bytes(BTRFS_I(inode), BTRFS_VERITY_DESC_ITEM_KEY, 1,
-                            buf, buf_size, NULL);
+                            buf, buf_size);
        if (ret < 0)
                return ret;
        if (ret != true_size)
@@ -706,6 +700,7 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode,
        struct folio *folio;
        u64 off = (u64)index << PAGE_SHIFT;
        loff_t merkle_pos = merkle_file_pos(inode);
+       void *kaddr;
        int ret;
 
        if (merkle_pos < 0)
@@ -749,6 +744,7 @@ again:
        }
 
 read_folio:
+       kaddr = kmap_local_folio(folio, 0);
        /*
         * Merkle item keys are indexed from byte 0 in the merkle tree.
         * They have the form:
@@ -756,7 +752,8 @@ read_folio:
         * [ inode objectid, BTRFS_MERKLE_ITEM_KEY, offset in bytes ]
         */
        ret = read_key_bytes(BTRFS_I(inode), BTRFS_VERITY_MERKLE_ITEM_KEY, off,
-                            folio_address(folio), PAGE_SIZE, folio);
+                            kaddr, PAGE_SIZE);
+       kunmap_local(kaddr);
        if (ret < 0) {
                folio_unlock(folio);
                folio_put(folio);