From: Namjae Jeon <linkinjeon@kernel.org>
To: hyc.lee@gmail.com
Cc: ntfs@lists.linux.dev, linux-fsdevel@vger.kernel.org,
Namjae Jeon <linkinjeon@kernel.org>,
Matthew Wilcox <willy@infradead.org>
Subject: [PATCH] ntfs: fix kmap_local_page() usage in compress
Date: Thu, 16 Jul 2026 11:46:38 +0900 [thread overview]
Message-ID: <20260716024640.13396-4-linkinjeon@kernel.org> (raw)
In-Reply-To: <20260716024640.13396-1-linkinjeon@kernel.org>
Several compressed I/O paths discard the address returned by
kmap_local_page() and later access or unmap the page using page_address().
This is invalid for highmem pages, and local mappings must also be unmapped
using the address returned by kmap_local_page().
Map each destination page in ntfs_decompress() only while producing the
current sub-block. Use memcpy_from_page(), memcpy_to_page(), and
memzero_page() for the other page accesses. Remove unnecessary local
mappings from ntfs_write_cb(), where pages are accessed through the vmap()
mapping.
Fixes: 495e90fa3348 ("ntfs: update attrib operations")
Reported-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
---
fs/ntfs/compress.c | 38 +++++++++++++++-----------------------
1 file changed, 15 insertions(+), 23 deletions(-)
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
index d83d3e8e06ae..e866f43ca30b 100644
--- a/fs/ntfs/compress.c
+++ b/fs/ntfs/compress.c
@@ -177,6 +177,7 @@ static int ntfs_decompress(struct page *dest_pages[], int completed_pages[],
/* Variables for uncompressed data / destination. */
struct page *dp; /* Current destination page being worked on. */
+ u8 *dp_kaddr; /* Local kmap for the current destination page. */
u8 *dp_addr; /* Current pointer into dp. */
u8 *dp_sb_start; /* Start of current sub-block in dp. */
u8 *dp_sb_end; /* End of current sb in dp (dp_sb_start + NTFS_SB_SIZE). */
@@ -191,6 +192,7 @@ static int ntfs_decompress(struct page *dest_pages[], int completed_pages[],
/* Default error code. */
int err = -EOVERFLOW;
+ dp_kaddr = NULL;
ntfs_debug("Entering, cb_size = 0x%x.", cb_size);
do_next_sb:
ntfs_debug("Beginning sub-block at offset = 0x%zx in the cb.",
@@ -223,7 +225,6 @@ static int ntfs_decompress(struct page *dest_pages[], int completed_pages[],
*/
handle_bounds_compressed_page(dp, i_size,
initialized_size);
- kunmap_local(page_address(dp));
SetPageUptodate(dp);
unlock_page(dp);
if (di == xpage)
@@ -269,7 +270,8 @@ static int ntfs_decompress(struct page *dest_pages[], int completed_pages[],
}
/* We have a valid destination page. Setup the destination pointers. */
- dp_addr = (u8 *)page_address(dp) + do_sb_start;
+ dp_kaddr = kmap_local_page(dp);
+ dp_addr = dp_kaddr + do_sb_start;
/* Now, we are ready to process the current sub-block (sb). */
if (!(le16_to_cpup((__le16 *)cb) & NTFS_SB_IS_COMPRESSED)) {
@@ -290,6 +292,8 @@ static int ntfs_decompress(struct page *dest_pages[], int completed_pages[],
/* Advance destination position to next sub-block. */
*dest_ofs += NTFS_SB_SIZE;
*dest_ofs &= ~PAGE_MASK;
+ kunmap_local(dp_kaddr);
+ dp_kaddr = NULL;
if (!(*dest_ofs)) {
finalize_page:
/*
@@ -324,6 +328,8 @@ static int ntfs_decompress(struct page *dest_pages[], int completed_pages[],
}
/* We have finished the current sub-block. */
*dest_ofs &= ~PAGE_MASK;
+ kunmap_local(dp_kaddr);
+ dp_kaddr = NULL;
if (!(*dest_ofs))
goto finalize_page;
goto do_next_sb;
@@ -429,6 +435,8 @@ static int ntfs_decompress(struct page *dest_pages[], int completed_pages[],
goto do_next_tag;
return_overflow:
+ if (dp_kaddr)
+ kunmap_local(dp_kaddr);
ntfs_error(NULL, "Failed. Returning -EOVERFLOW.");
goto return_error;
}
@@ -557,7 +565,6 @@ int ntfs_read_compressed_block(struct folio *folio)
* least wasting our time.
*/
if (!PageDirty(page) && (!PageUptodate(page))) {
- kmap_local_page(page);
continue;
}
unlock_page(page);
@@ -643,8 +650,7 @@ int ntfs_read_compressed_block(struct folio *folio)
}
lock_page(lpage);
- memcpy(cb_pos, page_address(lpage) + page_ofs,
- vol->cluster_size);
+ memcpy_from_page(cb_pos, lpage, page_ofs, vol->cluster_size);
unlock_page(lpage);
put_page(lpage);
cb_pos += vol->cluster_size;
@@ -683,14 +689,7 @@ int ntfs_read_compressed_block(struct folio *folio)
for (; cur_page < cb_max_page; cur_page++) {
page = pages[cur_page];
if (page) {
- if (likely(!cur_ofs))
- clear_page(page_address(page));
- else
- memset(page_address(page) + cur_ofs, 0,
- PAGE_SIZE -
- cur_ofs);
- flush_dcache_page(page);
- kunmap_local(page_address(page));
+ memzero_page(page, cur_ofs, PAGE_SIZE - cur_ofs);
SetPageUptodate(page);
unlock_page(page);
if (cur_page == xpage)
@@ -708,8 +707,7 @@ int ntfs_read_compressed_block(struct folio *folio)
if (cb_max_ofs && cb_pos < cb_end) {
page = pages[cur_page];
if (page)
- memset(page_address(page) + cur_ofs, 0,
- cb_max_ofs - cur_ofs);
+ memzero_page(page, cur_ofs, cb_max_ofs - cur_ofs);
/*
* No need to update cb_pos at this stage:
* cb_pos += cb_max_ofs - cur_ofs;
@@ -730,7 +728,7 @@ int ntfs_read_compressed_block(struct folio *folio)
for (; cur_page < cb_max_page; cur_page++) {
page = pages[cur_page];
if (page)
- memcpy(page_address(page) + cur_ofs, cb_pos,
+ memcpy_to_page(page, cur_ofs, cb_pos,
PAGE_SIZE - cur_ofs);
cb_pos += PAGE_SIZE - cur_ofs;
cur_ofs = 0;
@@ -741,7 +739,7 @@ int ntfs_read_compressed_block(struct folio *folio)
if (cb_max_ofs && cb_pos < cb_end) {
page = pages[cur_page];
if (page)
- memcpy(page_address(page) + cur_ofs, cb_pos,
+ memcpy_to_page(page, cur_ofs, cb_pos,
cb_max_ofs - cur_ofs);
cb_pos += cb_max_ofs - cur_ofs;
cur_ofs = cb_max_ofs;
@@ -758,7 +756,6 @@ int ntfs_read_compressed_block(struct folio *folio)
*/
handle_bounds_compressed_page(page, i_size,
initialized_size);
- kunmap_local(page_address(page));
SetPageUptodate(page);
unlock_page(page);
if (cur2_page == xpage)
@@ -794,7 +791,6 @@ int ntfs_read_compressed_block(struct folio *folio)
page = pages[prev_cur_page];
if (page) {
flush_dcache_page(page);
- kunmap_local(page_address(page));
unlock_page(page);
if (prev_cur_page != xpage)
put_page(page);
@@ -818,7 +814,6 @@ int ntfs_read_compressed_block(struct folio *folio)
"Still have pages left! Terminating them with extreme prejudice. Inode 0x%llx, page index 0x%lx.",
ni->mft_no, folio->index);
flush_dcache_folio(folio);
- kunmap_local(page_address(page));
folio_unlock(folio);
if (cur_page != xpage)
folio_put(folio);
@@ -856,7 +851,6 @@ int ntfs_read_compressed_block(struct folio *folio)
page = pages[i];
if (page) {
flush_dcache_page(page);
- kunmap_local(page_address(page));
unlock_page(page);
if (i != xpage)
put_page(page);
@@ -1308,7 +1302,6 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages,
}
pages_disk[i] = pg;
lock_page(pg);
- kmap_local_page(pg);
}
outbuf = vmap(pages_disk, pages_count, VM_MAP, PAGE_KERNEL);
@@ -1443,7 +1436,6 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages,
for (i = 0; i < pages_count; i++) {
pg = pages_disk[i];
if (pg) {
- kunmap_local(page_address(pg));
unlock_page(pg);
put_page(pg);
}
--
2.25.1
next prev parent reply other threads:[~2026-07-16 2:47 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-16 2:46 [PATCH] ntfs: validate final EA attribute size Namjae Jeon
2026-07-16 2:46 ` [PATCH] ntfs: remove empty EA attribute pair Namjae Jeon
2026-07-16 22:26 ` Hyunchul Lee
2026-07-16 2:46 ` [PATCH] ntfs: rewrite EA stream before updating metadata Namjae Jeon
2026-07-16 22:27 ` Hyunchul Lee
2026-07-16 2:46 ` Namjae Jeon [this message]
2026-07-16 22:27 ` [PATCH] ntfs: fix kmap_local_page() usage in compress Hyunchul Lee
2026-07-16 2:46 ` [PATCH] ntfs: file extension before write submission Namjae Jeon
2026-07-16 22:28 ` Hyunchul Lee
2026-07-16 2:46 ` [PATCH] ntfs: use pagecache_isize_extended() on size extension Namjae Jeon
2026-07-16 22:28 ` Hyunchul Lee
2026-07-16 22:26 ` [PATCH] ntfs: validate final EA attribute size Hyunchul Lee
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260716024640.13396-4-linkinjeon@kernel.org \
--to=linkinjeon@kernel.org \
--cc=hyc.lee@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=ntfs@lists.linux.dev \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.