Skip to content

Commit 6309b8c

Browse files
konisakpm00
authored andcommitted
nilfs2: fix buffer head leaks in calls to truncate_inode_pages()
When block_invalidatepage was converted to block_invalidate_folio, the fallback to block_invalidatepage in folio_invalidate() if the address_space_operations method invalidatepage (currently invalidate_folio) was not set, was removed. Unfortunately, some pseudo-inodes in nilfs2 use empty_aops set by inode_init_always_gfp() as is, or explicitly set it to address_space_operations. Therefore, with this change, block_invalidatepage() is no longer called from folio_invalidate(), and as a result, the buffer_head structures attached to these pages/folios are no longer freed via try_to_free_buffers(). Thus, these buffer heads are now leaked by truncate_inode_pages(), which cleans up the page cache from inode evict(), etc. Three types of caches use empty_aops: gc inode caches and the DAT shadow inode used by GC, and b-tree node caches. Of these, b-tree node caches explicitly call invalidate_mapping_pages() during cleanup, which involves calling try_to_free_buffers(), so the leak was not visible during normal operation but worsened when GC was performed. Fix this issue by using address_space_operations with invalidate_folio set to block_invalidate_folio instead of empty_aops, which will ensure the same behavior as before. Link: https://lkml.kernel.org/r/20241212164556.21338-1-konishi.ryusuke@gmail.com Fixes: 7ba13ab ("fs: Turn block_invalidatepage into block_invalidate_folio") Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> Cc: <stable@vger.kernel.org> [5.18+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent a2e740e commit 6309b8c

File tree

4 files changed

+8
-1
lines changed

4 files changed

+8
-1
lines changed

fs/nilfs2/btnode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ void nilfs_init_btnc_inode(struct inode *btnc_inode)
3535
ii->i_flags = 0;
3636
memset(&ii->i_bmap_data, 0, sizeof(struct nilfs_bmap));
3737
mapping_set_gfp_mask(btnc_inode->i_mapping, GFP_NOFS);
38+
btnc_inode->i_mapping->a_ops = &nilfs_buffer_cache_aops;
3839
}
3940

4041
void nilfs_btnode_cache_clear(struct address_space *btnc)

fs/nilfs2/gcinode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ int nilfs_init_gcinode(struct inode *inode)
163163

164164
inode->i_mode = S_IFREG;
165165
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
166-
inode->i_mapping->a_ops = &empty_aops;
166+
inode->i_mapping->a_ops = &nilfs_buffer_cache_aops;
167167

168168
ii->i_flags = 0;
169169
nilfs_bmap_init_gc(ii->i_bmap);

fs/nilfs2/inode.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ const struct address_space_operations nilfs_aops = {
276276
.is_partially_uptodate = block_is_partially_uptodate,
277277
};
278278

279+
const struct address_space_operations nilfs_buffer_cache_aops = {
280+
.invalidate_folio = block_invalidate_folio,
281+
};
282+
279283
static int nilfs_insert_inode_locked(struct inode *inode,
280284
struct nilfs_root *root,
281285
unsigned long ino)
@@ -681,6 +685,7 @@ struct inode *nilfs_iget_for_shadow(struct inode *inode)
681685
NILFS_I(s_inode)->i_flags = 0;
682686
memset(NILFS_I(s_inode)->i_bmap, 0, sizeof(struct nilfs_bmap));
683687
mapping_set_gfp_mask(s_inode->i_mapping, GFP_NOFS);
688+
s_inode->i_mapping->a_ops = &nilfs_buffer_cache_aops;
684689

685690
err = nilfs_attach_btree_node_cache(s_inode);
686691
if (unlikely(err)) {

fs/nilfs2/nilfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ extern const struct file_operations nilfs_dir_operations;
401401
extern const struct inode_operations nilfs_file_inode_operations;
402402
extern const struct file_operations nilfs_file_operations;
403403
extern const struct address_space_operations nilfs_aops;
404+
extern const struct address_space_operations nilfs_buffer_cache_aops;
404405
extern const struct inode_operations nilfs_dir_inode_operations;
405406
extern const struct inode_operations nilfs_special_inode_operations;
406407
extern const struct inode_operations nilfs_symlink_inode_operations;

0 commit comments

Comments
 (0)