Commit 08bab74a authored by Vincent Whitchurch's avatar Vincent Whitchurch Committed by Andrew Morton

squashfs: fix cache race with migration

Migration replaces the page in the mapping before copying the contents and
the flags over from the old page, so check that the page in the page cache
is really up to date before using it.  Without this, stressing squashfs
reads with parallel compaction sometimes results in squashfs reporting
data corruption.

Link: https://lkml.kernel.org/r/20230629-squashfs-cache-migration-v1-1-d50ebe55099d@axis.com
Fixes: e994f5b6 ("squashfs: cache partial compressed blocks")
Signed-off-by: default avatarVincent Whitchurch <vincent.whitchurch@axis.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Phillip Lougher <phillip@squashfs.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 191fcdb6
...@@ -166,6 +166,26 @@ static int squashfs_bio_read_cached(struct bio *fullbio, ...@@ -166,6 +166,26 @@ static int squashfs_bio_read_cached(struct bio *fullbio,
return 0; return 0;
} }
static struct page *squashfs_get_cache_page(struct address_space *mapping,
pgoff_t index)
{
struct page *page;
if (!mapping)
return NULL;
page = find_get_page(mapping, index);
if (!page)
return NULL;
if (!PageUptodate(page)) {
put_page(page);
return NULL;
}
return page;
}
static int squashfs_bio_read(struct super_block *sb, u64 index, int length, static int squashfs_bio_read(struct super_block *sb, u64 index, int length,
struct bio **biop, int *block_offset) struct bio **biop, int *block_offset)
{ {
...@@ -190,11 +210,10 @@ static int squashfs_bio_read(struct super_block *sb, u64 index, int length, ...@@ -190,11 +210,10 @@ static int squashfs_bio_read(struct super_block *sb, u64 index, int length,
for (i = 0; i < page_count; ++i) { for (i = 0; i < page_count; ++i) {
unsigned int len = unsigned int len =
min_t(unsigned int, PAGE_SIZE - offset, total_len); min_t(unsigned int, PAGE_SIZE - offset, total_len);
struct page *page = NULL; pgoff_t index = (read_start >> PAGE_SHIFT) + i;
struct page *page;
if (cache_mapping) page = squashfs_get_cache_page(cache_mapping, index);
page = find_get_page(cache_mapping,
(read_start >> PAGE_SHIFT) + i);
if (!page) if (!page)
page = alloc_page(GFP_NOIO); page = alloc_page(GFP_NOIO);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment