Skip to content

Commit 68f6bd1

Browse files
Matthew Wilcox (Oracle)aalexandrovich
authored andcommitted
ntfs: Do not overwrite uptodate pages
When reading a compressed file, we may read several pages in addition to the one requested. The current code will overwrite pages in the page cache with the data from disc which can definitely result in changes that have been made being lost. For example if we have four consecutie pages ABCD in the file compressed into a single extent, on first access, we'll bring in ABCD. Then we write to page B. Memory pressure results in the eviction of ACD. When we attempt to write to page C, we will overwrite the data in page B with the data currently on disk. I haven't investigated the decompression code to check whether it's OK to overwrite a clean page or whether it might be possible to see corrupt data. Out of an abundance of caution, decline to overwrite uptodate pages, not just dirty pages. Fixes: 4342306 (fs/ntfs3: Add file operations and implementation) Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: stable@vger.kernel.org Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
1 parent 953b79a commit 68f6bd1

1 file changed

Lines changed: 29 additions & 6 deletions

File tree

fs/ntfs3/frecord.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,6 +2020,29 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
20202020
return err;
20212021
}
20222022

2023+
static struct page *ntfs_lock_new_page(struct address_space *mapping,
2024+
pgoff_t index, gfp_t gfp)
2025+
{
2026+
struct folio *folio = __filemap_get_folio(mapping, index,
2027+
FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp);
2028+
struct page *page;
2029+
2030+
if (IS_ERR(folio))
2031+
return ERR_CAST(folio);
2032+
2033+
if (!folio_test_uptodate(folio))
2034+
return folio_file_page(folio, index);
2035+
2036+
/* Use a temporary page to avoid data corruption */
2037+
folio_unlock(folio);
2038+
folio_put(folio);
2039+
page = alloc_page(gfp);
2040+
if (!page)
2041+
return ERR_PTR(-ENOMEM);
2042+
__SetPageLocked(page);
2043+
return page;
2044+
}
2045+
20232046
/*
20242047
* ni_readpage_cmpr
20252048
*
@@ -2074,9 +2097,9 @@ int ni_readpage_cmpr(struct ntfs_inode *ni, struct folio *folio)
20742097
if (i == idx)
20752098
continue;
20762099

2077-
pg = find_or_create_page(mapping, index, gfp_mask);
2078-
if (!pg) {
2079-
err = -ENOMEM;
2100+
pg = ntfs_lock_new_page(mapping, index, gfp_mask);
2101+
if (IS_ERR(pg)) {
2102+
err = PTR_ERR(pg);
20802103
goto out1;
20812104
}
20822105
pages[i] = pg;
@@ -2175,13 +2198,13 @@ int ni_decompress_file(struct ntfs_inode *ni)
21752198
for (i = 0; i < pages_per_frame; i++, index++) {
21762199
struct page *pg;
21772200

2178-
pg = find_or_create_page(mapping, index, gfp_mask);
2179-
if (!pg) {
2201+
pg = ntfs_lock_new_page(mapping, index, gfp_mask);
2202+
if (IS_ERR(pg)) {
21802203
while (i--) {
21812204
unlock_page(pages[i]);
21822205
put_page(pages[i]);
21832206
}
2184-
err = -ENOMEM;
2207+
err = PTR_ERR(pg);
21852208
goto out;
21862209
}
21872210
pages[i] = pg;

0 commit comments

Comments
 (0)