summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Wilcox (Oracle) <willy@infradead.org>2026-06-23 20:28:48 +0100
committerChristian Brauner <brauner@kernel.org>2026-06-29 10:27:29 +0200
commitee3f011250104129893d8e9599147e457d4d7280 (patch)
tree5a4b86cfc8597a2d847d668067ef4e2b59d3876d
parent0baad6f9b9970c6e3f1d33dbfd17d1a77702771d (diff)
downloadlinux-stable-ee3f011250104129893d8e9599147e457d4d7280.tar.gz
linux-stable-ee3f011250104129893d8e9599147e457d4d7280.zip
fs: Free any excess xarray nodes in clear_inode()
For many years we've had a hard to hit leak of xarray nodes. Hugh documented it well in commit 786b31121a2c. Recently people and syzbot have found ways to force it to happen with madvise. Rather than fix the leaks where they happen, just call xa_destroy() which has the side-effect of cycling the i_pages lock. Cc: Rik van Riel <riel@surriel.com> Cc: Zi Yan <ziy@nvidia.com> Cc: Jinjiang Tu <tujinjiang@huawei.com> Cc: Dave Jones <davej@codemonkey.org.uk> Link: https://lore.kernel.org/all/20260121062243.1893129-1-tujinjiang@huawei.com/ Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Link: https://patch.msgid.link/20260623192850.1595958-1-willy@infradead.org Reviewed-by: Rik van Riel <riel@surriel.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
-rw-r--r--fs/inode.c23
1 files changed, 10 insertions, 13 deletions
diff --git a/fs/inode.c b/fs/inode.c
index 31c5b9ee3a81..a31aa7cb47f6 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -763,21 +763,18 @@ void clear_inode(struct inode *inode)
fsverity_cleanup_inode(inode);
/*
- * We have to cycle the i_pages lock here because reclaim can be in the
- * process of removing the last page (in __filemap_remove_folio())
- * and we must not free the mapping under it.
+ * We have to cycle the i_pages lock here because reclaim
+ * can be in the process of removing the last page (in
+ * __filemap_remove_folio()) and we must not free the mapping
+ * under it. We also remove nodes which are empty; these
+ * can occur in two different ways. The first is that radix
+ * tree expansion can fail partway and the second is that THP
+ * collapse_file() can allocate some temporary nodes and not
+ * clean them up.
*/
- xa_lock_irq(&inode->i_data.i_pages);
+ xa_destroy(&inode->i_data.i_pages);
+
BUG_ON(inode->i_data.nrpages);
- /*
- * Almost always, mapping_empty(&inode->i_data) here; but there are
- * two known and long-standing ways in which nodes may get left behind
- * (when deep radix-tree node allocation failed partway; or when THP
- * collapse_file() failed). Until those two known cases are cleaned up,
- * or a cleanup function is called here, do not BUG_ON(!mapping_empty),
- * nor even WARN_ON(!mapping_empty).
- */
- xa_unlock_irq(&inode->i_data.i_pages);
BUG_ON(!(inode_state_read_once(inode) & I_FREEING));
BUG_ON(inode_state_read_once(inode) & I_CLEAR);
BUG_ON(!list_empty(&inode->i_wb_list));