[PATCH] ntfs3: update iomap folio state when marking folios uptodate

From: aljojobypls

Date: Thu Oct 01 2026 - 03:32:14 EST


ntfs3 hands page invalidation and dirty tracking to iomap. With a
block size smaller than the folio, iomap keeps a per-block uptodate
bitmap in iomap_folio_state, and ifs_free() warns when that bitmap
does not match PG_uptodate.

The read past i_valid, compressed reads past i_size, compressed
writes, resident-to-nonresident conversion, and ni_read_frame() still
set the folio flag directly. truncate_setsize() from ntfs_setattr()
then drops the folio and hits the warning.

Mark those folios through iomap_folio_mark_uptodate() so the bitmap
and PG_uptodate move together.

Reported-by: syzbot+0e70362e1726b5a7502e@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=0e70362e1726b5a7502e
Fixes: 099ef9ab9203 ("fs/ntfs3: implement iomap-based file operations")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Aljo Joby <aljojobypls@xxxxxxxxx>
---
fs/ntfs3/attrib.c | 5 +++--
fs/ntfs3/file.c | 6 +++---
fs/ntfs3/frecord.c | 5 +++--
fs/ntfs3/inode.c | 2 +-
4 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c
index b1c315206..73f059765 100644
--- a/fs/ntfs3/attrib.c
+++ b/fs/ntfs3/attrib.c
@@ -7,8 +7,9 @@
*/

#include <linux/fs.h>
-#include <linux/slab.h>
+#include <linux/iomap.h>
#include <linux/kernel.h>
+#include <linux/slab.h>

#include "debug.h"
#include "ntfs.h"
@@ -327,7 +328,7 @@ int attr_make_nonresident(struct ntfs_inode *ni,
struct ATTRIB *attr,
goto out2;
}
folio_fill_tail(folio, 0, data, rsize);
- folio_mark_uptodate(folio);
+ iomap_folio_mark_uptodate(folio);
folio_mark_dirty(folio);
folio_unlock(folio);
folio_put(folio);
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 2abf334bf..520b72456 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -1071,7 +1071,7 @@ static ssize_t ntfs_compress_write(struct kiocb
*iocb, struct iov_iter *from)
folio = page_folio(pages[ip]);
folio_zero_segment(folio, off, PAGE_SIZE);
flush_dcache_folio(folio);
- folio_mark_uptodate(folio);
+ iomap_folio_mark_uptodate(folio);
}

ni_lock(ni);
@@ -1080,7 +1080,7 @@ static ssize_t ntfs_compress_write(struct kiocb
*iocb, struct iov_iter *from)

for (ip = 0; ip < pages_per_frame; ip++) {
folio = page_folio(pages[ip]);
- folio_mark_uptodate(folio);
+ iomap_folio_mark_uptodate(folio);
folio_unlock(folio);
folio_put(folio);
}
@@ -1166,7 +1166,7 @@ static ssize_t ntfs_compress_write(struct kiocb
*iocb, struct iov_iter *from)
for (ip = 0; ip < pages_per_frame; ip++) {
folio = page_folio(pages[ip]);
folio_clear_dirty(folio);
- folio_mark_uptodate(folio);
+ iomap_folio_mark_uptodate(folio);
folio_unlock(folio);
folio_put(folio);
}
diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c
index bead01a95..3bf794dc9 100644
--- a/fs/ntfs3/frecord.c
+++ b/fs/ntfs3/frecord.c
@@ -7,6 +7,7 @@

#include <linux/fiemap.h>
#include <linux/fs.h>
+#include <linux/iomap.h>
#include <linux/minmax.h>
#include <linux/vmalloc.h>

@@ -1943,7 +1944,7 @@ int ni_read_folio_cmpr(struct ntfs_inode *ni,
struct folio *folio)

if (vbo >= i_size_read(&ni->vfs_inode)) {
folio_zero_range(folio, 0, folio_size(folio));
- folio_mark_uptodate(folio);
+ iomap_folio_mark_uptodate(folio);
err = 0;
goto out;
}
@@ -2521,7 +2522,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64
frame_vbo, struct page **pages,
out:
for (i = 0; i < pages_per_frame; i++) {
pg = pages[i];
- SetPageUptodate(pg);
+ iomap_folio_mark_uptodate(page_folio(pg));
}

return err;
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 4ac26c80b..8e4a5dd6e 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -842,7 +842,7 @@ static int ntfs_read_folio(struct file *file,
struct folio *folio)

if (ni->i_valid <= vbo) {
folio_zero_range(folio, 0, folio_size(folio));
- folio_mark_uptodate(folio);
+ iomap_folio_mark_uptodate(folio);
folio_unlock(folio);
return 0;
}
--
2.53.0