[Concept,05/19] linux: Add pagemap.h header with folio and page cache stubs

Message ID 20260117011448.3007171-6-sjg@u-boot.org
State New
Headers
Series ext4l: Reduce ext4_uboot.h size by moving code to include/linux |

Commit Message

Simon Glass Jan. 17, 2026, 1:14 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

U-Boot does not have a real page cache or VM system. The ext4l
filesystem uses many folio and filemap operations which are currently
defined inline in ext4_uboot.h.

Create a new linux/pagemap.h header file with stub implementations
to better match the Linux kernel structure. This significantly reduces
duplication and makes ext4_uboot.h smaller.

Types and operations moved:
- struct folio
- FGP_* flags for __filemap_get_folio()
- PAGECACHE_TAG_* constants
- folio operation stubs (folio_mark_dirty, folio_test_*, etc.)
- filemap operation stubs (filemap_invalidate_*, filemap_write_*, etc.)
- truncate stubs (truncate_pagecache, truncate_inode_pages, etc.)
- readahead stubs (readahead_pos, readahead_length, etc.)
- kmap/kunmap stubs
- struct readahead_control

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 fs/ext4l/ext4_uboot.h   | 192 +++-----------------------------------
 include/linux/pagemap.h | 201 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 216 insertions(+), 177 deletions(-)
 create mode 100644 include/linux/pagemap.h
  

Patch

diff --git a/fs/ext4l/ext4_uboot.h b/fs/ext4l/ext4_uboot.h
index 6a06805329f..40c68085c7a 100644
--- a/fs/ext4l/ext4_uboot.h
+++ b/fs/ext4l/ext4_uboot.h
@@ -394,8 +394,7 @@  struct sb_writers {
 	int frozen;
 };
 
-/* mapping_large_folio_support stub */
-#define mapping_large_folio_support(m)	(0)
+/* mapping_large_folio_support is in linux/pagemap.h */
 
 /* sector_t is now in linux/types.h */
 
@@ -870,28 +869,7 @@  static inline unsigned long memweight(const void *ptr, size_t bytes)
 /* Security checks - no security in U-Boot */
 #define IS_NOSEC(inode)			(1)
 
-/* Filemap operations */
-#define filemap_invalidate_lock(m)	do { } while (0)
-#define filemap_invalidate_unlock(m)	do { } while (0)
-#define filemap_invalidate_lock_shared(m) do { } while (0)
-#define filemap_invalidate_unlock_shared(m) do { } while (0)
-#define filemap_write_and_wait_range(m, s, e) ({ (void)(m); (void)(s); (void)(e); 0; })
-#define filemap_fdatawrite_range(m, s, e) ({ (void)(m); (void)(s); (void)(e); 0; })
-#define truncate_pagecache(i, s)	do { } while (0)
-#define pagecache_isize_extended(i, f, t) do { } while (0)
-#define invalidate_mapping_pages(m, s, e) do { (void)(m); (void)(s); (void)(e); } while (0)
-
-/* Filemap fault handlers - stubs */
-static inline vm_fault_t filemap_fault(struct vm_fault *vmf)
-{
-	return 0;
-}
-
-static inline vm_fault_t filemap_map_pages(struct vm_fault *vmf,
-					   pgoff_t start, pgoff_t end)
-{
-	return 0;
-}
+/* Filemap operations and fault handlers are in linux/pagemap.h */
 
 /* DAX device mapping check - always false in U-Boot */
 #define daxdev_mapping_supported(f, i, d) ({ (void)(f); (void)(i); (void)(d); 1; })
@@ -935,8 +913,7 @@  static inline int in_range(unsigned long val, unsigned long start,
 /* umin - unsigned min (Linux 6.x) */
 #define umin(x, y)	((x) < (y) ? (x) : (y))
 
-/* truncate_inode_pages - stub */
-#define truncate_inode_pages(m, s)	do { } while (0)
+/* truncate_inode_pages is in linux/pagemap.h */
 
 /* ext4_sb_bread_nofail is stubbed in interface.c */
 
@@ -966,48 +943,12 @@  static inline int in_range(unsigned long val, unsigned long start,
 
 /* SEQ_START_TOKEN is in linux/seq_file.h */
 
-/* folio - memory page container stub */
-struct folio {
-	struct page *page;
-	unsigned long index;
-	struct address_space *mapping;
-	unsigned long flags;
-	void *data;
-	struct buffer_head *private;
-	int _refcount;
-};
-
-/* struct folio_batch is in linux/pagevec.h */
-
-/* folio operations - stubs */
-#define folio_mark_dirty(f)			do { (void)(f); } while (0)
-/*
- * offset_in_folio - calculate offset of pointer within folio's data
- * In Linux this uses page alignment, but in U-Boot we use the folio's
- * actual data pointer since our buffers are malloc'd.
- */
-#define offset_in_folio(f, p)			((f) ? (unsigned int)((uintptr_t)(p) - (uintptr_t)(f)->data) : 0U)
-#define folio_buffers(f)			({ (void)(f); (struct buffer_head *)NULL; })
-#define virt_to_folio(p)			({ (void)(p); (struct folio *)NULL; })
-#define folio_set_bh(bh, f, off)		do { if ((bh) && (f)) { (bh)->b_folio = (f); (bh)->b_data = (char *)(f)->data + (off); } } while (0)
-#define memcpy_from_folio(dst, f, off, len)	do { (void)(dst); (void)(f); (void)(off); (void)(len); } while (0)
-#define folio_test_uptodate(f)			({ (void)(f); 1; })
-#define folio_pos(f)				({ (void)(f); 0LL; })
-#define folio_size(f)				({ (void)(f); PAGE_SIZE; })
-#define folio_unlock(f)				do { (void)(f); } while (0)
-/* folio_put and folio_get are implemented in support.c */
-#define folio_lock(f)				do { (void)(f); } while (0)
-/* folio_batch_init is in linux/pagevec.h */
-#define filemap_get_folios(m, i, e, fb)		({ (void)(m); (void)(i); (void)(e); (void)(fb); 0U; })
+/* folio and pagemap - use linux/pagemap.h */
+#include <linux/pagemap.h>
 
 /* xa_mark_t - xarray mark type */
 typedef unsigned int xa_mark_t;
 
-/* Page cache tags */
-#define PAGECACHE_TAG_DIRTY	0
-#define PAGECACHE_TAG_TOWRITE	1
-#define PAGECACHE_TAG_WRITEBACK	2
-
 static inline xa_mark_t wbc_to_tag(struct writeback_control *wbc)
 {
 	if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
@@ -1025,54 +966,9 @@  struct blk_plug {
 /* Writeback reasons */
 #define WB_REASON_FS_FREE_SPACE	0
 
-/* readahead_control stub */
-struct readahead_control {
-	struct address_space *mapping;
-	struct file *file;
-	unsigned long _index;
-	unsigned int _batch_count;
-};
-
-#define readahead_pos(rac)		({ (void)(rac); 0LL; })
-#define readahead_length(rac)		({ (void)(rac); 0UL; })
-
 /* address_space_operations is in linux/fs.h */
 /* buffer_migrate_folio, buffer_migrate_folio_norefs, noop_dirty_folio are in linux/buffer_head.h */
-
-/* Stub implementations for address_space_operations callbacks */
-static inline bool block_is_partially_uptodate(struct folio *folio,
-					       size_t from, size_t count)
-{
-	return false;
-}
-
-static inline int generic_error_remove_folio(struct address_space *mapping,
-					     struct folio *folio)
-{
-	return 0;
-}
-
-/* FGP flags for folio_grab_cache */
-#define FGP_ACCESSED	0x00000001
-#define FGP_LOCK	0x00000002
-#define FGP_CREAT	0x00000004
-#define FGP_WRITE	0x00000008
-#define FGP_NOFS	0x00000010
-#define FGP_NOWAIT	0x00000020
-#define FGP_FOR_MMAP	0x00000040
-#define FGP_STABLE	0x00000080
-#define FGP_WRITEBEGIN	(FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE)
-
-/* kmap/kunmap stubs for inline.c */
-#define kmap_local_folio(folio, off)	((folio) ? (char *)(folio)->data + (off) : NULL)
-#define kunmap_local(addr)		do { (void)(addr); } while (0)
-
-/* Folio zeroing stubs for inline.c */
-#define folio_zero_tail(f, off, kaddr)	({ (void)(f); (void)(off); (void)(kaddr); (void *)NULL; })
-#define folio_zero_segment(f, s, e)	do { (void)(f); (void)(s); (void)(e); } while (0)
-
-/* mapping_gfp_mask stub */
-#define mapping_gfp_mask(m)		({ (void)(m); GFP_KERNEL; })
+/* readahead_control, FGP_*, kmap/kunmap, folio stubs are in linux/pagemap.h */
 
 /* Folio operations - implemented in support.c */
 struct folio *__filemap_get_folio(struct address_space *mapping,
@@ -1154,43 +1050,8 @@  static inline char *d_path(const struct path *path, char *buf, int buflen)
 #define inode_is_open_for_write(i)		(0)
 #define inode_is_dirtytime_only(i)		(0)
 
-/* Writeback stubs for super.c */
-#define writeback_iter(mapping, wbc, folio, error) \
-	({ (void)(mapping); (void)(wbc); (void)(error); (struct folio *)NULL; })
-#define folio_redirty_for_writepage(wbc, folio) \
-	({ (void)(wbc); (void)(folio); false; })
-
-/* Folio operations - additional stubs */
-#define folio_zero_segments(f, s1, e1, s2, e2)	do { } while (0)
-#define folio_zero_new_buffers(f, f2, t)	do { } while (0)
-#define folio_wait_stable(f)			do { } while (0)
-#define folio_zero_range(f, s, l)		do { } while (0)
-#define folio_mark_uptodate(f)			do { } while (0)
-#define folio_next_index(f)			((f)->index + 1)
-#define folio_next_pos(f)			((loff_t)folio_next_index(f) << PAGE_SHIFT)
-#define folio_mapped(f)				(0)
-
-/*
- * fgf_set_order - Set the order (size) for folio allocation
- * U-Boot doesn't support large folios, so this is a no-op stub.
- */
-#define fgf_set_order(size)			(0)
-#define folio_clear_dirty_for_io(f)		({ (void)(f); 1; })
-#define folio_clear_uptodate(f)			do { } while (0)
+/* Folio operations and writeback stubs are in linux/pagemap.h */
 #define folio_batch_release(fb)			do { } while (0)
-#define folio_nr_pages(f)			(1UL)
-#define folio_contains(f, idx)			({ (void)(f); (void)(idx); 1; })
-#define folio_clear_checked(f)			do { } while (0)
-#define folio_test_dirty(f)			(0)
-#define folio_test_writeback(f)			(0)
-#define folio_wait_writeback(f)			do { } while (0)
-#define folio_clear_dirty(f)			do { } while (0)
-#define folio_test_checked(f)			(0)
-#define folio_maybe_dma_pinned(f)		(0)
-#define folio_set_checked(f)			do { } while (0)
-#define folio_test_locked(f)			(0)
-#define folio_mkclean(f)			(0)
-#define page_folio(page)			((struct folio *)(page))
 
 /* Quota stubs - additional */
 #define dquot_claim_block(i, n)			({ (void)(i); (void)(n); 0; })
@@ -1202,20 +1063,8 @@  static inline char *d_path(const struct path *path, char *buf, int buflen)
 
 /* percpu_counter_sub is in linux/percpu_counter.h */
 
-/* Filemap operations - additional */
-#define filemap_get_folio(m, i)			((struct folio *)NULL)
-#define filemap_get_folios_tag(m, s, e, t, fb)	({ (void)(m); (void)(s); (void)(e); (void)(t); (void)(fb); 0U; })
-#define filemap_flush(m)			({ (void)(m); 0; })
-#define filemap_write_and_wait(m)		({ (void)(m); 0; })
-#define filemap_dirty_folio(m, f)		({ (void)(m); (void)(f); false; })
-#define filemap_lock_folio(m, i)		((struct folio *)NULL)
-/* filemap_invalidate_lock_shared defined earlier */
-#define mapping_tagged(m, t)			(0)
-#define tag_pages_for_writeback(m, s, e)	do { } while (0)
+/* Filemap operations are in linux/pagemap.h */
 #define try_to_writeback_inodes_sb(sb, r)	do { } while (0)
-#define mapping_gfp_constraint(m, g)		(g)
-#define mapping_set_folio_order_range(m, l, h)	do { } while (0)
-#define filemap_splice_read(i, p, pi, l, f)	({ (void)(i); (void)(p); (void)(pi); (void)(l); (void)(f); 0L; })
 
 /* Buffer operations - additional */
 #define getblk_unmovable(bdev, block, size)	sb_getblk(bdev->bd_super, block)
@@ -1340,9 +1189,7 @@  extern struct inode *iget_locked(struct super_block *sb, unsigned long ino);
 /* Block device alignment */
 #define bdev_dma_alignment(bd)		(0)
 
-/* Truncation */
-#define truncate_inode_pages_final(m)	do { } while (0)
-#define truncate_pagecache_range(i, s, e) do { } while (0)
+/* Truncation stubs are in linux/pagemap.h */
 
 /*
  * Additional stubs for dir.c
@@ -1353,9 +1200,7 @@  extern struct inode *iget_locked(struct super_block *sb, unsigned long ino);
 
 /* fscrypt directory operations are in ext4_fscrypt.h */
 
-/* Readahead operations */
-#define ra_has_index(ra, idx)			({ (void)(ra); (void)(idx); 0; })
-#define page_cache_sync_readahead(m, ra, f, i, n) do { } while (0)
+/* Readahead operations are in linux/pagemap.h */
 
 /* Inode version operations */
 #define inode_eq_iversion(i, v)			({ (void)(i); (void)(v); 1; })
@@ -2072,9 +1917,7 @@  static inline unsigned long ext4_find_next_bit_le(const void *addr,
 /* CPU cycle counter stub */
 #define get_cycles()			(0ULL)
 
-/* folio_address - get virtual address of folio data */
-#undef folio_address
-#define folio_address(folio)		((folio)->data)
+/* folio_address is in linux/pagemap.h */
 
 /* sb_end_intwrite defined earlier */
 
@@ -2243,9 +2086,7 @@  typedef void *mempool_t;
 #define fsverity_verify_folio(f)	({ (void)(f); 1; })
 #define IS_VERITY(inode)		(0)
 
-/* readahead operations */
-#define readahead_count(rac)		({ (void)(rac); 0UL; })
-#define readahead_folio(rac)		({ (void)(rac); (struct folio *)NULL; })
+/* readahead operations are in linux/pagemap.h */
 
 /* prefetch operations */
 #define prefetchw(addr)			do { (void)(addr); } while (0)
@@ -2300,10 +2141,9 @@  struct wait_bit_entry {
 #define write_dirty_buffer(bh, flags)	sync_dirty_buffer(bh)
 #define spin_needbreak(l)		({ (void)(l); 0; })
 
-/* JBD2 commit.c stubs */
+/* JBD2 commit.c stubs (folio_trylock is in linux/pagemap.h) */
 #define clear_bit_unlock(nr, addr)	clear_bit(nr, addr)
 #define smp_mb__after_atomic()		do { } while (0)
-#define folio_trylock(f)		({ (void)(f); 1; })
 #define ktime_get_coarse_real_ts64(ts)	do { (ts)->tv_sec = 0; (ts)->tv_nsec = 0; } while (0)
 #define filemap_fdatawait_range_keep_errors(m, s, e) \
 	({ (void)(m); (void)(s); (void)(e); 0; })
@@ -2379,7 +2219,7 @@  int bh_read(struct buffer_head *bh, int flags);
 #ifndef SECTOR_SHIFT
 #define SECTOR_SHIFT	9
 #endif
-#define mapping_max_folio_order(m)	({ (void)(m); 0; })
+/* mapping_max_folio_order is in linux/pagemap.h */
 
 /* Memory allocation for journal.c */
 #define __get_free_pages(gfp, order)	((unsigned long)memalign(PAGE_SIZE, PAGE_SIZE << (order)))
@@ -2410,9 +2250,7 @@  static inline struct new_utsname *init_utsname(void)
 #define down_write_nested(sem, subclass) \
 	do { (void)(sem); (void)(subclass); } while (0)
 
-/* filemap_release_folio - try to release a folio */
-#define filemap_release_folio(folio, gfp) \
-	({ (void)(folio); (void)(gfp); 1; })
+/* filemap_release_folio is in linux/pagemap.h */
 
 /* IS_SWAPFILE - check if inode is a swap file */
 #define IS_SWAPFILE(inode)	({ (void)(inode); 0; })
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
new file mode 100644
index 00000000000..19a64993955
--- /dev/null
+++ b/include/linux/pagemap.h
@@ -0,0 +1,201 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Page cache and folio management stubs for U-Boot
+ *
+ * U-Boot doesn't have a real page cache, so these are stubs.
+ */
+#ifndef _LINUX_PAGEMAP_H
+#define _LINUX_PAGEMAP_H
+
+#include <linux/types.h>
+#include <linux/mm_types.h>
+
+/* Forward declarations */
+struct address_space;
+struct buffer_head;
+
+/**
+ * struct folio - memory page container stub
+ * @page: associated page
+ * @index: page index in the mapping
+ * @mapping: address space this folio belongs to
+ * @flags: folio flags
+ * @data: pointer to the actual data
+ * @private: private data for filesystem
+ * @_refcount: reference count
+ *
+ * U-Boot stub - simplified folio structure.
+ */
+struct folio {
+	struct page *page;
+	unsigned long index;
+	struct address_space *mapping;
+	unsigned long flags;
+	void *data;
+	struct buffer_head *private;
+	int _refcount;
+};
+
+/* FGP flags for __filemap_get_folio() */
+#define FGP_ACCESSED	0x00000001
+#define FGP_LOCK	0x00000002
+#define FGP_CREAT	0x00000004
+#define FGP_WRITE	0x00000008
+#define FGP_NOFS	0x00000010
+#define FGP_NOWAIT	0x00000020
+#define FGP_FOR_MMAP	0x00000040
+#define FGP_STABLE	0x00000080
+#define FGP_WRITEBEGIN	(FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE)
+
+/* Page cache tags */
+#define PAGECACHE_TAG_DIRTY	0
+#define PAGECACHE_TAG_TOWRITE	1
+#define PAGECACHE_TAG_WRITEBACK	2
+
+/* Folio operations - stubs */
+#define folio_mark_dirty(f)		do { (void)(f); } while (0)
+#define folio_test_uptodate(f)		({ (void)(f); 1; })
+#define folio_pos(f)			({ (void)(f); 0LL; })
+#define folio_size(f)			({ (void)(f); PAGE_SIZE; })
+#define folio_unlock(f)			do { (void)(f); } while (0)
+#define folio_lock(f)			do { (void)(f); } while (0)
+#define folio_buffers(f)		({ (void)(f); (struct buffer_head *)NULL; })
+#define virt_to_folio(p)		({ (void)(p); (struct folio *)NULL; })
+#define folio_zero_tail(f, off, kaddr)	({ (void)(f); (void)(off); (void)(kaddr); (void *)NULL; })
+#define folio_zero_segment(f, s, e)	do { (void)(f); (void)(s); (void)(e); } while (0)
+#define folio_zero_segments(f, s1, e1, s2, e2)	do { } while (0)
+#define folio_zero_new_buffers(f, f2, t)	do { } while (0)
+#define folio_wait_stable(f)		do { } while (0)
+#define folio_zero_range(f, s, l)	do { } while (0)
+#define folio_mark_uptodate(f)		do { } while (0)
+#define folio_next_index(f)		((f)->index + 1)
+#define folio_next_pos(f)		((loff_t)folio_next_index(f) << PAGE_SHIFT)
+#define folio_mapped(f)			(0)
+#define fgf_set_order(size)		(0)
+#define folio_clear_dirty_for_io(f)	({ (void)(f); 1; })
+#define folio_clear_uptodate(f)		do { } while (0)
+#define folio_nr_pages(f)		(1UL)
+#define folio_contains(f, idx)		({ (void)(f); (void)(idx); 1; })
+#define folio_clear_checked(f)		do { } while (0)
+#define folio_test_dirty(f)		(0)
+#define folio_test_writeback(f)		(0)
+#define folio_wait_writeback(f)		do { } while (0)
+#define folio_clear_dirty(f)		do { } while (0)
+#define folio_test_checked(f)		(0)
+#define folio_maybe_dma_pinned(f)	(0)
+#define folio_set_checked(f)		do { } while (0)
+#define folio_test_locked(f)		(0)
+#define folio_mkclean(f)		(0)
+#define page_folio(page)		((struct folio *)(page))
+#define folio_address(folio)		((folio)->data)
+#define folio_trylock(f)		({ (void)(f); 1; })
+
+/* Folio writeback operations */
+#define folio_end_writeback(f)		do { (void)(f); } while (0)
+#define folio_start_writeback(f)	do { (void)(f); } while (0)
+#define folio_start_writeback_keepwrite(f) do { (void)(f); } while (0)
+#define folio_end_read(f, success)	do { (void)(f); (void)(success); } while (0)
+#define folio_set_mappedtodisk(f)	do { (void)(f); } while (0)
+#define folio_redirty_for_writepage(wbc, folio) \
+	({ (void)(wbc); (void)(folio); false; })
+
+/*
+ * offset_in_folio - calculate offset of pointer within folio's data
+ *
+ * In Linux this uses page alignment, but in U-Boot we use the folio's
+ * actual data pointer since our buffers are malloc'd.
+ */
+#define offset_in_folio(f, p)		((f) ? (unsigned int)((uintptr_t)(p) - (uintptr_t)(f)->data) : 0U)
+
+/* folio_set_bh - associate buffer_head with folio */
+#define folio_set_bh(bh, f, off)	do { if ((bh) && (f)) { (bh)->b_folio = (f); (bh)->b_data = (char *)(f)->data + (off); } } while (0)
+
+#define memcpy_from_folio(dst, f, off, len)	do { (void)(dst); (void)(f); (void)(off); (void)(len); } while (0)
+
+/* kmap/kunmap for folio access */
+#define kmap_local_folio(folio, off)	((folio) ? (char *)(folio)->data + (off) : NULL)
+#define kunmap_local(addr)		do { (void)(addr); } while (0)
+
+/* mapping_gfp_mask - get GFP mask for address_space */
+#define mapping_gfp_mask(m)		({ (void)(m); GFP_KERNEL; })
+
+/* mapping_large_folio_support stub */
+#define mapping_large_folio_support(m)	(0)
+
+/* Filemap operations - stubs */
+#define filemap_get_folios(m, i, e, fb)	({ (void)(m); (void)(i); (void)(e); (void)(fb); 0U; })
+#define filemap_get_folio(m, i)		((struct folio *)NULL)
+#define filemap_get_folios_tag(m, s, e, t, fb) \
+	({ (void)(m); (void)(s); (void)(e); (void)(t); (void)(fb); 0U; })
+#define filemap_lock_folio(m, i)	((struct folio *)NULL)
+#define filemap_dirty_folio(m, f)	({ (void)(m); (void)(f); false; })
+#define filemap_invalidate_lock(m)	do { } while (0)
+#define filemap_invalidate_unlock(m)	do { } while (0)
+#define filemap_invalidate_lock_shared(m) do { } while (0)
+#define filemap_invalidate_unlock_shared(m) do { } while (0)
+#define filemap_write_and_wait_range(m, s, e) ({ (void)(m); (void)(s); (void)(e); 0; })
+#define filemap_fdatawrite_range(m, s, e) ({ (void)(m); (void)(s); (void)(e); 0; })
+#define filemap_flush(m)		({ (void)(m); 0; })
+#define filemap_write_and_wait(m)	({ (void)(m); 0; })
+#define filemap_release_folio(folio, gfp) ({ (void)(folio); (void)(gfp); 1; })
+#define mapping_tagged(m, t)		(0)
+#define tag_pages_for_writeback(m, s, e) do { } while (0)
+#define mapping_gfp_constraint(m, g)	(g)
+#define mapping_set_folio_order_range(m, l, h) do { } while (0)
+#define filemap_splice_read(i, p, pi, l, f) ({ (void)(i); (void)(p); (void)(pi); (void)(l); (void)(f); 0L; })
+#define mapping_max_folio_order(m)	({ (void)(m); 0; })
+
+/* Truncation stubs */
+#define truncate_pagecache(i, s)	do { } while (0)
+#define truncate_inode_pages(m, s)	do { } while (0)
+#define truncate_inode_pages_final(m)	do { } while (0)
+#define truncate_pagecache_range(i, s, e) do { } while (0)
+#define truncate_inode_pages_range(m, s, e) do { (void)(m); (void)(s); (void)(e); } while (0)
+#define pagecache_isize_extended(i, f, t) do { } while (0)
+#define invalidate_mapping_pages(m, s, e) do { (void)(m); (void)(s); (void)(e); } while (0)
+
+/* Filemap fault handlers */
+static inline vm_fault_t filemap_fault(struct vm_fault *vmf)
+{
+	return 0;
+}
+
+static inline vm_fault_t filemap_map_pages(struct vm_fault *vmf,
+					   pgoff_t start, pgoff_t end)
+{
+	return 0;
+}
+
+/* readahead_control stub */
+struct readahead_control {
+	struct address_space *mapping;
+	struct file *file;
+	unsigned long _index;
+	unsigned int _batch_count;
+};
+
+#define readahead_pos(rac)		({ (void)(rac); 0LL; })
+#define readahead_length(rac)		({ (void)(rac); 0UL; })
+#define readahead_count(rac)		({ (void)(rac); 0UL; })
+#define readahead_folio(rac)		({ (void)(rac); (struct folio *)NULL; })
+#define page_cache_sync_readahead(m, ra, f, i, n) do { } while (0)
+#define ra_has_index(ra, idx)		({ (void)(ra); (void)(idx); 0; })
+
+/* Stub implementations for address_space_operations callbacks */
+static inline bool block_is_partially_uptodate(struct folio *folio,
+					       size_t from, size_t count)
+{
+	return false;
+}
+
+static inline int generic_error_remove_folio(struct address_space *mapping,
+					     struct folio *folio)
+{
+	return 0;
+}
+
+/* writeback_iter stub */
+#define writeback_iter(mapping, wbc, folio, error) \
+	({ (void)(mapping); (void)(wbc); (void)(error); (struct folio *)NULL; })
+
+#endif /* _LINUX_PAGEMAP_H */