From 5f36c9ca33336036a087b270e68e8236c733f448 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:08 +0100 Subject: fs: Rename generic_file_fsync() to simple_fsync() The implementation is now really basic so rename generic_file_fsync() simple_fsync() and __generic_file_fsync() to simple_fsync_noflush(). Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-56-jack@suse.cz Signed-off-by: Christian Brauner --- include/linux/fs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 8b3dd145b25e..0fc0cb23000e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3295,8 +3295,8 @@ void simple_offset_destroy(struct offset_ctx *octx); extern const struct file_operations simple_offset_dir_operations; -extern int __generic_file_fsync(struct file *, loff_t, loff_t, int); -extern int generic_file_fsync(struct file *, loff_t, loff_t, int); +extern int simple_fsync_noflush(struct file *, loff_t, loff_t, int); +extern int simple_fsync(struct file *, loff_t, loff_t, int); extern int generic_check_addressable(unsigned, u64); -- cgit v1.2.3 From 972b9dd4e4180fbb2352bf2f0e015b7b63f5cca0 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:16 +0100 Subject: fs: Ignore inode metadata buffers in inode_lru_isolate() There are only a few filesystems that use generic tracking of inode metadata buffer heads. As such the logic to reclaim tracked metadata buffer heads in inode_lru_isolate() doesn't bring a benefit big enough to justify intertwining of inode reclaim and metadata buffer head tracking. Just treat tracked metadata buffer heads as any other metadata filesystem has to properly clean up on inode eviction and stop handling it in inode_lru_isolate(). As a result filesystems using generic tracking of metadata buffer heads may now see dirty metadata buffers in their .evict methods more often which can slow down inode reclaim but given these filesystems aren't used in performance demanding setups we should be fine. Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-64-jack@suse.cz Tested-by: syzbot@syzkaller.appspotmail.com Signed-off-by: Christian Brauner --- include/linux/buffer_head.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index b16b88bfbc3e..631bf971efc0 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -517,7 +517,6 @@ void buffer_init(void); bool try_to_free_buffers(struct folio *folio); int inode_has_buffers(struct inode *inode); void invalidate_inode_buffers(struct inode *inode); -int remove_inode_buffers(struct inode *inode); int sync_mapping_buffers(struct address_space *mapping); void invalidate_bh_lrus(void); void invalidate_bh_lrus_cpu(void); @@ -528,9 +527,7 @@ extern int buffer_heads_over_limit; static inline void buffer_init(void) {} static inline bool try_to_free_buffers(struct folio *folio) { return true; } -static inline int inode_has_buffers(struct inode *inode) { return 0; } static inline void invalidate_inode_buffers(struct inode *inode) {} -static inline int remove_inode_buffers(struct inode *inode) { return 1; } static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; } static inline void invalidate_bh_lrus(void) {} static inline void invalidate_bh_lrus_cpu(void) {} -- cgit v1.2.3 From 2811f2a82fafff40867b318360cc06143b088a7c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:18 +0100 Subject: hugetlbfs: Stop using i_private_data Instead of using i_private_data for resv_map pointer add the pointer into hugetlbfs private part of the inode. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-66-jack@suse.cz Signed-off-by: Christian Brauner --- include/linux/hugetlb.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 65910437be1c..fc5462fe943f 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -518,6 +518,7 @@ static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) struct hugetlbfs_inode_info { struct inode vfs_inode; + struct resv_map *resv_map; unsigned int seals; }; -- cgit v1.2.3 From cd336f2e275de14866101d3395c7d2be0a0c1b04 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:20 +0100 Subject: fs: Remove i_private_data Nobody is using it anymore. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-68-jack@suse.cz Tested-by: syzbot@syzkaller.appspotmail.com Signed-off-by: Christian Brauner --- include/linux/fs.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 0fc0cb23000e..d488459396f4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -465,7 +465,6 @@ extern const struct address_space_operations empty_aops; * @wb_err: The most recent error which has occurred. * @i_private_lock: For use by the owner of the address_space. * @i_private_list: For use by the owner of the address_space. - * @i_private_data: For use by the owner of the address_space. */ struct address_space { struct inode *host; @@ -486,7 +485,6 @@ struct address_space { spinlock_t i_private_lock; struct list_head i_private_list; struct rw_semaphore i_mmap_rwsem; - void * i_private_data; } __attribute__((aligned(sizeof(long)))) __randomize_layout; /* * On most architectures that alignment is already the case; but -- cgit v1.2.3 From 521bea7cec8a79684402d555caab408ed43171d5 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:24 +0100 Subject: fs: Move metadata bhs tracking to a separate struct Instead of tracking metadata bhs for a mapping using i_private_list and i_private_lock create a dedicated mapping_metadata_bhs struct for it. So far this struct is embedded in address_space but that will be switched for per-fs private inode parts later in the series. This also changes the locking from bdev mapping's i_private_lock to a new lock embedded in mapping_metadata_bhs to untangle the i_private_lock locking for maintaining lists of metadata bhs and the locking for looking up / reclaiming bdev's buffer heads. The locking in remove_assoc_map() gets more complex due to this but overall this looks like a reasonable tradeoff. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-72-jack@suse.cz Signed-off-by: Christian Brauner --- include/linux/fs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index d488459396f4..76360b0040e0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -445,6 +445,12 @@ struct address_space_operations { extern const struct address_space_operations empty_aops; +/* Structure for tracking metadata buffer heads associated with the mapping */ +struct mapping_metadata_bhs { + spinlock_t lock; /* Lock protecting bh list */ + struct list_head list; /* The list of bhs (b_assoc_buffers) */ +}; + /** * struct address_space - Contents of a cacheable, mappable object. * @host: Owner, either the inode or the block_device. @@ -484,6 +490,7 @@ struct address_space { errseq_t wb_err; spinlock_t i_private_lock; struct list_head i_private_list; + struct mapping_metadata_bhs i_metadata_bhs; struct rw_semaphore i_mmap_rwsem; } __attribute__((aligned(sizeof(long)))) __randomize_layout; /* -- cgit v1.2.3 From c86f5d25514c2a60fcf5ea0aa11c5d8bd1a313ef Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:25 +0100 Subject: fs: Make bhs point to mapping_metadata_bhs Make buffer heads point to mapping_metadata_bhs instead of struct address_space. This makes the code more self contained. For the (only) case of IO error handling where we really need to reach struct address_space add a pointer to the mapping from mapping_metadata_bhs. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-73-jack@suse.cz Signed-off-by: Christian Brauner --- include/linux/buffer_head.h | 4 ++-- include/linux/fs.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 631bf971efc0..20636599d858 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -73,8 +73,8 @@ struct buffer_head { bh_end_io_t *b_end_io; /* I/O completion */ void *b_private; /* reserved for b_end_io */ struct list_head b_assoc_buffers; /* associated with another mapping */ - struct address_space *b_assoc_map; /* mapping this buffer is - associated with */ + struct mapping_metadata_bhs *b_mmb; /* head of the list of metadata bhs + * this buffer is associated with */ atomic_t b_count; /* users using this buffer_head */ spinlock_t b_uptodate_lock; /* Used by the first bh in a page, to * serialise IO completion of other diff --git a/include/linux/fs.h b/include/linux/fs.h index 76360b0040e0..fa2a812bd718 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -447,6 +447,7 @@ extern const struct address_space_operations empty_aops; /* Structure for tracking metadata buffer heads associated with the mapping */ struct mapping_metadata_bhs { + struct address_space *mapping; /* Mapping bhs are associated with */ spinlock_t lock; /* Lock protecting bh list */ struct list_head list; /* The list of bhs (b_assoc_buffers) */ }; -- cgit v1.2.3 From 025c9af1a20c8353f586c9bfd30705dfe4a277de Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:26 +0100 Subject: fs: Switch inode_has_buffers() to take mapping_metadata_bhs As part of a move towards placing mapping_metadata_bhs in fs-private inode part, switch inode_has_buffers() to take mapping_metadata_bhs and rename the function to mmb_has_buffers(). Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-74-jack@suse.cz Signed-off-by: Christian Brauner --- include/linux/buffer_head.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 20636599d858..44094fd476f5 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -515,7 +515,7 @@ bool block_dirty_folio(struct address_space *mapping, struct folio *folio); void buffer_init(void); bool try_to_free_buffers(struct folio *folio); -int inode_has_buffers(struct inode *inode); +bool mmb_has_buffers(struct mapping_metadata_bhs *mmb); void invalidate_inode_buffers(struct inode *inode); int sync_mapping_buffers(struct address_space *mapping); void invalidate_bh_lrus(void); -- cgit v1.2.3 From a8c8122a3dac55d25a1912b8fec9b8cd7366c37a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:27 +0100 Subject: fs: Provide functions for handling mapping_metadata_bhs directly As part of transition toward moving mapping_metadata_bhs to fs-private part of the inode, provide functions for operations on this list directly instead of going through the inode / mapping. Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-75-jack@suse.cz Signed-off-by: Christian Brauner --- include/linux/buffer_head.h | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 44094fd476f5..e207dcca7a25 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -205,12 +205,30 @@ struct buffer_head *create_empty_buffers(struct folio *folio, void end_buffer_read_sync(struct buffer_head *bh, int uptodate); void end_buffer_write_sync(struct buffer_head *bh, int uptodate); -/* Things to do with buffers at mapping->private_list */ -void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode); -int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end, - bool datasync); -int generic_buffers_fsync(struct file *file, loff_t start, loff_t end, - bool datasync); +/* Things to do with metadata buffers list */ +void mmb_mark_buffer_dirty(struct buffer_head *bh, struct mapping_metadata_bhs *mmb); +static inline void mark_buffer_dirty_inode(struct buffer_head *bh, + struct inode *inode) +{ + mmb_mark_buffer_dirty(bh, &inode->i_data.i_metadata_bhs); +} +int mmb_fsync_noflush(struct file *file, struct mapping_metadata_bhs *mmb, + loff_t start, loff_t end, bool datasync); +static inline int generic_buffers_fsync_noflush(struct file *file, + loff_t start, loff_t end, + bool datasync) +{ + return mmb_fsync_noflush(file, &file->f_mapping->i_metadata_bhs, + start, end, datasync); +} +int mmb_fsync(struct file *file, struct mapping_metadata_bhs *mmb, + loff_t start, loff_t end, bool datasync); +static inline int generic_buffers_fsync(struct file *file, + loff_t start, loff_t end, bool datasync) +{ + return mmb_fsync(file, &file->f_mapping->i_metadata_bhs, + start, end, datasync); +} void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len); static inline void clean_bdev_bh_alias(struct buffer_head *bh) @@ -515,9 +533,18 @@ bool block_dirty_folio(struct address_space *mapping, struct folio *folio); void buffer_init(void); bool try_to_free_buffers(struct folio *folio); +void mmb_init(struct mapping_metadata_bhs *mmb, struct address_space *mapping); bool mmb_has_buffers(struct mapping_metadata_bhs *mmb); -void invalidate_inode_buffers(struct inode *inode); -int sync_mapping_buffers(struct address_space *mapping); +void mmb_invalidate(struct mapping_metadata_bhs *mmb); +int mmb_sync(struct mapping_metadata_bhs *mmb); +static inline void invalidate_inode_buffers(struct inode *inode) +{ + mmb_invalidate(&inode->i_data.i_metadata_bhs); +} +static inline int sync_mapping_buffers(struct address_space *mapping) +{ + return mmb_sync(&mapping->i_metadata_bhs); +} void invalidate_bh_lrus(void); void invalidate_bh_lrus_cpu(void); bool has_bh_in_lru(int cpu, void *dummy); @@ -527,6 +554,7 @@ extern int buffer_heads_over_limit; static inline void buffer_init(void) {} static inline bool try_to_free_buffers(struct folio *folio) { return true; } +static inline int mmb_sync(struct mapping_metadata_bhs *mmb) { return 0; } static inline void invalidate_inode_buffers(struct inode *inode) {} static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; } static inline void invalidate_bh_lrus(void) {} -- cgit v1.2.3 From cb6d109b9ccc374d09812c2387ab826499ee6562 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:35 +0100 Subject: fs: Drop mapping_metadata_bhs from address space Nobody uses mapping_metadata_bhs in struct address_space anymore. Just remove it and with it all helper functions using it. Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-83-jack@suse.cz Signed-off-by: Christian Brauner --- include/linux/buffer_head.h | 28 ---------------------------- include/linux/fs.h | 1 - 2 files changed, 29 deletions(-) (limited to 'include/linux') diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index e207dcca7a25..e4939e33b4b5 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -207,28 +207,10 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate); /* Things to do with metadata buffers list */ void mmb_mark_buffer_dirty(struct buffer_head *bh, struct mapping_metadata_bhs *mmb); -static inline void mark_buffer_dirty_inode(struct buffer_head *bh, - struct inode *inode) -{ - mmb_mark_buffer_dirty(bh, &inode->i_data.i_metadata_bhs); -} int mmb_fsync_noflush(struct file *file, struct mapping_metadata_bhs *mmb, loff_t start, loff_t end, bool datasync); -static inline int generic_buffers_fsync_noflush(struct file *file, - loff_t start, loff_t end, - bool datasync) -{ - return mmb_fsync_noflush(file, &file->f_mapping->i_metadata_bhs, - start, end, datasync); -} int mmb_fsync(struct file *file, struct mapping_metadata_bhs *mmb, loff_t start, loff_t end, bool datasync); -static inline int generic_buffers_fsync(struct file *file, - loff_t start, loff_t end, bool datasync) -{ - return mmb_fsync(file, &file->f_mapping->i_metadata_bhs, - start, end, datasync); -} void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len); static inline void clean_bdev_bh_alias(struct buffer_head *bh) @@ -537,14 +519,6 @@ void mmb_init(struct mapping_metadata_bhs *mmb, struct address_space *mapping); bool mmb_has_buffers(struct mapping_metadata_bhs *mmb); void mmb_invalidate(struct mapping_metadata_bhs *mmb); int mmb_sync(struct mapping_metadata_bhs *mmb); -static inline void invalidate_inode_buffers(struct inode *inode) -{ - mmb_invalidate(&inode->i_data.i_metadata_bhs); -} -static inline int sync_mapping_buffers(struct address_space *mapping) -{ - return mmb_sync(&mapping->i_metadata_bhs); -} void invalidate_bh_lrus(void); void invalidate_bh_lrus_cpu(void); bool has_bh_in_lru(int cpu, void *dummy); @@ -555,8 +529,6 @@ extern int buffer_heads_over_limit; static inline void buffer_init(void) {} static inline bool try_to_free_buffers(struct folio *folio) { return true; } static inline int mmb_sync(struct mapping_metadata_bhs *mmb) { return 0; } -static inline void invalidate_inode_buffers(struct inode *inode) {} -static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; } static inline void invalidate_bh_lrus(void) {} static inline void invalidate_bh_lrus_cpu(void) {} static inline bool has_bh_in_lru(int cpu, void *dummy) { return false; } diff --git a/include/linux/fs.h b/include/linux/fs.h index fa2a812bd718..ccfa696253c8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -491,7 +491,6 @@ struct address_space { errseq_t wb_err; spinlock_t i_private_lock; struct list_head i_private_list; - struct mapping_metadata_bhs i_metadata_bhs; struct rw_semaphore i_mmap_rwsem; } __attribute__((aligned(sizeof(long)))) __randomize_layout; /* -- cgit v1.2.3 From f219798ce294e346031022a85670f68eb2dec10e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 26 Mar 2026 10:54:36 +0100 Subject: fs: Drop i_private_list from address_space Nobody is using i_private_list anymore. Remove it. Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260326095354.16340-84-jack@suse.cz Tested-by: syzbot@syzkaller.appspotmail.com Signed-off-by: Christian Brauner --- include/linux/fs.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index ccfa696253c8..a3bed26d066d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -471,7 +471,6 @@ struct mapping_metadata_bhs { * @flags: Error bits and flags (AS_*). * @wb_err: The most recent error which has occurred. * @i_private_lock: For use by the owner of the address_space. - * @i_private_list: For use by the owner of the address_space. */ struct address_space { struct inode *host; @@ -490,7 +489,6 @@ struct address_space { unsigned long flags; errseq_t wb_err; spinlock_t i_private_lock; - struct list_head i_private_list; struct rw_semaphore i_mmap_rwsem; } __attribute__((aligned(sizeof(long)))) __randomize_layout; /* -- cgit v1.2.3