summaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorBoris Burkov <boris@bur.io>2024-12-13 21:33:22 +0100
committerDavid Sterba <dsterba@suse.com>2024-12-23 22:00:07 +0100
commit0fba7be1ca6df2881e68386e5575fe096f33c4ca (patch)
treef63d2445e8d35420b056a8b4e4116b2098adcf8f /fs/btrfs
parentbtrfs: check folio mapping after unlock in relocate_one_folio() (diff)
downloadlinux-0fba7be1ca6df2881e68386e5575fe096f33c4ca.tar.xz
linux-0fba7be1ca6df2881e68386e5575fe096f33c4ca.zip
btrfs: check folio mapping after unlock in put_file_data()
When we call btrfs_read_folio() we get an unlocked folio, so it is possible for a different thread to concurrently modify folio->mapping. We must check that this hasn't happened once we do have the lock. CC: stable@vger.kernel.org # 6.12+ Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Boris Burkov <boris@bur.io> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/send.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 7254279c3cc9..498c84323253 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -5280,6 +5280,7 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
unsigned cur_len = min_t(unsigned, len,
PAGE_SIZE - pg_offset);
+again:
folio = filemap_lock_folio(mapping, index);
if (IS_ERR(folio)) {
page_cache_sync_readahead(mapping,
@@ -5312,6 +5313,11 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
ret = -EIO;
break;
}
+ if (folio->mapping != mapping) {
+ folio_unlock(folio);
+ folio_put(folio);
+ goto again;
+ }
}
memcpy_from_folio(sctx->send_buf + sctx->send_size, folio,