]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
btrfs: check folio mapping after unlock in put_file_data()
authorBoris Burkov <boris@bur.io>
Fri, 13 Dec 2024 20:33:22 +0000 (12:33 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 2 Jan 2025 09:34:25 +0000 (10:34 +0100)
commit 0fba7be1ca6df2881e68386e5575fe096f33c4ca upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/btrfs/send.c

index 0cb11dcd10cd4be48fe236a6477660700eda5abd..b1015f383f75ef1a8c56d231c224d416e97780b3 100644 (file)
@@ -5291,6 +5291,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,
@@ -5323,6 +5324,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,