btrfs: send: prepare put_file_data() for large data folios
authorQu Wenruo <wqu@suse.com>
Mon, 17 Mar 2025 07:10:47 +0000 (17:40 +1030)
committerDavid Sterba <dsterba@suse.com>
Thu, 15 May 2025 12:30:42 +0000 (14:30 +0200)
Currently put_file_data() can only accept a page sized folio.  However
the function itself is not that complex, it's just copying data from
filemap folio into the send buffer.

Make it support large data folios:

- Change the loop to use file offset instead of page index

- Calculate @pg_offset and @cur_len after getting the folio

- Remove the "WARN_ON(folio_order(folio));" line

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

index 43c29295f477e9cc4159f891178c35108e75a163..116d67ab93dcdb4f8dc18936907ce92661dcfb3d 100644 (file)
@@ -5263,10 +5263,9 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
 {
        struct btrfs_root *root = sctx->send_root;
        struct btrfs_fs_info *fs_info = root->fs_info;
-       struct folio *folio;
-       pgoff_t index = offset >> PAGE_SHIFT;
-       pgoff_t last_index;
-       unsigned pg_offset = offset_in_page(offset);
+       u64 cur = offset;
+       const u64 end = offset + len;
+       const pgoff_t last_index = ((end - 1) >> PAGE_SHIFT);
        struct address_space *mapping = sctx->cur_inode->i_mapping;
        int ret;
 
@@ -5274,11 +5273,11 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
        if (ret)
                return ret;
 
-       last_index = (offset + len - 1) >> PAGE_SHIFT;
-
-       while (index <= last_index) {
-               unsigned cur_len = min_t(unsigned, len,
-                                        PAGE_SIZE - pg_offset);
+       while (cur < end) {
+               pgoff_t index = (cur >> PAGE_SHIFT);
+               unsigned int cur_len;
+               unsigned int pg_offset;
+               struct folio *folio;
 
                folio = filemap_lock_folio(mapping, index);
                if (IS_ERR(folio)) {
@@ -5292,8 +5291,8 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
                                break;
                        }
                }
-
-               WARN_ON(folio_order(folio));
+               pg_offset = offset_in_folio(folio, cur);
+               cur_len = min_t(unsigned int, end - cur, folio_size(folio) - pg_offset);
 
                if (folio_test_readahead(folio))
                        page_cache_async_readahead(mapping, &sctx->ra, NULL, folio,
@@ -5323,9 +5322,7 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
                                  pg_offset, cur_len);
                folio_unlock(folio);
                folio_put(folio);
-               index++;
-               pg_offset = 0;
-               len -= cur_len;
+               cur += cur_len;
                sctx->send_size += cur_len;
        }