Skip to content

fix(rm): keep directory FD use O(1) on deep trees#13420

Open
l46983284-cpu wants to merge 4 commits into
uutils:mainfrom
l46983284-cpu:fix/rm-deep-tree-emfile
Open

fix(rm): keep directory FD use O(1) on deep trees#13420
l46983284-cpu wants to merge 4 commits into
uutils:mainfrom
l46983284-cpu:fix/rm-deep-tree-emfile

Conversation

@l46983284-cpu

Copy link
Copy Markdown

Summary

rm -r on a very deep directory tree fails with Too many open files (EMFILE) while GNU rm succeeds. Recursive safe traversal kept one DirFd open per nesting level, so FD use grew with depth.

This change walks the tree with an explicit stack, closes the parent directory descriptor before descending, and reopens it from the saved path when returning to unlink the child. openat / unlinkat safety is preserved; open-file use stays O(1) with depth.

Test plan

  • cargo build -p uu_rm --release
  • Manual: depth-200 tree under prlimit --nofile=32 removes successfully
  • Manual: multi-entry tree (files + dirs) removes cleanly
  • CI: tests/by-util/test_rm.rs including new test_rm_recursive_deep_tree_low_nofile (NOFILE=32, depth 80)

Fixes #7995

Recursive rm held one DirFd per nesting level, so deep trees failed with
EMFILE under normal NOFILE limits while GNU rm succeeded.

Walk directories with an explicit stack, close the parent DirFd before
descending, and reopen it from the saved path when returning to unlink.
Preserves openat/unlinkat safety and adds a low-NOFILE regression test.

Fixes uutils#7995

Signed-off-by: Alex Chen <l46983284@gmail.com>
Signed-off-by: Alex Chen <l46983284@gmail.com>
@codspeed-hq

codspeed-hq Bot commented Jul 16, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 6.11%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 3 regressed benchmarks
✅ 336 untouched benchmarks
⏩ 46 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation rm_recursive_tree 12 ms 13 ms -7.69%
Simulation complex_relative_date 137.2 µs 147.9 µs -7.21%
Simulation du_max_depth_balanced_tree[(6, 4, 10)] 25.2 ms 26.1 ms -3.36%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing l46983284-cpu:fix/rm-deep-tree-emfile (bcda98a) with main (9846eb8)

Open in CodSpeed

Footnotes

  1. 46 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Flip child_error branch for clippy::if_not_else and reword the
doc comment so cspell does not flag EMFILE.

Signed-off-by: Alex Chen <l46983284@gmail.com>
Use cargo fmt import order (CI) and else-if chain for clippy
if_not_else / collapsible_else_if cleanliness.

Signed-off-by: Alex Chen <l46983284@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rm: cannot remove '/tmp/tmp.i4z7SivxAR/incoming/pkg-deep-tree/[very deep tree]': Too many open files

1 participant