linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [bug report] memory leak of xa_node in collapse_file() when rollbacks
@ 2025-12-18 11:45 Jinjiang Tu
  2025-12-18 11:51 ` David Hildenbrand (Red Hat)
  0 siblings, 1 reply; 10+ messages in thread
From: Jinjiang Tu @ 2025-12-18 11:45 UTC (permalink / raw)
  To: Andrew Morton, Matthew Wilcox, ziy, david, lorenzo.stoakes,
	baolin.wang, Liam.Howlett, npache, ryan.roberts, dev.jain,
	baohua, lance.yang, linux-mm, linux-fsdevel
  Cc: Kefeng Wang, tujinjiang

I encountered a memory leak issue caused by xas_create_range().

collapse_file() calls xas_create_range() to pre-create all slots needed.
If collapse_file() finally fails, these pre-created slots are empty nodes
and aren't destroyed.

I can reproduce it with following steps.
1) create file /tmp/test_madvise_collapse and ftruncate to 4MB size, and then mmap the file
2) memset for the first 2MB
3) madvise(MADV_COLLAPSE) for the second 2MB
4) unlink the file

in 3), collapse_file() calls xas_create_range() to expand xarray depth, and fails to collapse
due to the whole 2M region is empty, the code is as following:

collapse_file()
	for (index = start; index < end;) {
		xas_set(&xas, index);
		folio = xas_load(&xas);

		VM_BUG_ON(index != xas.xa_index);
		if (is_shmem) {
			if (!folio) {
				/*
				 * Stop if extent has been truncated or
				 * hole-punched, and is now completely
				 * empty.
				 */
				if (index == start) {
					if (!xas_next_entry(&xas, end - 1)) {
						result = SCAN_TRUNCATED;
						goto xa_locked;
					}
				}
				...
			}


collapse_file() rollback path doesn't destroy the pre-created empty nodes.

When the file is deleted, shmem_evict_inode()->shmem_truncate_range() traverses
all entries and calls xas_store(xas, NULL) to delete, if the leaf xa_node that
stores deleted entry becomes emtry, xas_store() will automatically delete the empty
node and delete it's  parent is empty too, until parent node isn't empty. shmem_evict_inode()
won't traverse the empty nodes created by xas_create_range() due to these nodes doesn't store
any entries. As a result, these empty nodes are leaked.

At first, I tried to destory the empty nodes when collapse_file() goes to rollback path. However,
collapse_file() only holds xarray lock and may release the lock, so we couldn't prevent concurrent
call of collapse_file(), so the deleted empty nodes may be needed by other collapse_file() calls.

IIUC, xas_create_range() is used to guarantee the xas_store(&xas, new_folio); succeeds. Could we
remove xas_create_range() call and just rollback when we fail to xas_store?




^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-12-31  6:29 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-18 11:45 [bug report] memory leak of xa_node in collapse_file() when rollbacks Jinjiang Tu
2025-12-18 11:51 ` David Hildenbrand (Red Hat)
2025-12-18 12:18   ` Jinjiang Tu
2025-12-18 12:49     ` David Hildenbrand (Red Hat)
2025-12-18 13:11       ` Jinjiang Tu
2025-12-25  4:15         ` Shardul Bankar
2025-12-27  1:24           ` Jinjiang Tu
2025-12-30 21:03             ` David Hildenbrand (Red Hat)
2025-12-31  6:29               ` Jinjiang Tu
2025-12-18 12:35   ` Jinjiang Tu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox