Skip to content

tail: avoid unnecessary pipe2 syscall for empty files#12465

Open
dragutreis wants to merge 2 commits into
uutils:mainfrom
dragutreis:fix/tail-is-file-exhausted
Open

tail: avoid unnecessary pipe2 syscall for empty files#12465
dragutreis wants to merge 2 commits into
uutils:mainfrom
dragutreis:fix/tail-is-file-exhausted

Conversation

@dragutreis
Copy link
Copy Markdown

Fixes #12464

bounded_tail calls print_target_section unconditionally, which creates
a broker pipe via splice_unbounded_broker even when the file is empty or
exhausted, causing an unnecessary pipe2 syscall.

Added is_file_exhausted to check before calling print_target_section:

  • Regular files: compare stream position against file length
  • Char/block devices: probe with a single-byte read; if data exists, write
    it directly to stdout since char devices don't support seeking back

Before:
strace -c -e pipe,pipe2 tail -c +1 /dev/null → 1 pipe2 call
After:
strace -c -e pipe,pipe2 tail -c +1 /dev/null → 0 pipe2 calls

@oech3
Copy link
Copy Markdown
Contributor

oech3 commented May 24, 2026

Does this require additional stat or other syscall? I'm not sure which syscall is cheap, but I thins this is not needed considering usage for 0-sized file is very rare.

@dragutreis
Copy link
Copy Markdown
Author

dragutreis commented May 24, 2026

Compared full syscall counts with strace -c:

Empty file (/dev/null):

  • Without fix: 129 syscalls (includes pipe2 + splice)
  • With fix: 124 syscalls

No new syscalls added. statx goes down by 1.

Non-empty file:

  • Without fix: 124 syscalls
  • With fix: 124 syscalls

No overhead for the common case.

@github-actions
Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/date/date-locale-hour (fails in this run but passes in the 'main' branch)
Skip an intermittent issue tests/pr/bounded-memory (fails in this run but passes in the 'main' branch)
Skip an intermittent issue tests/tail/tail-n0f (was skipped on 'main', now failing)

@oech3
Copy link
Copy Markdown
Contributor

oech3 commented May 24, 2026

it directly to stdout since char devices don't support seeking back

Are /dev/sd* and /dev/nvme* missing splice driver yet? I saw cat does not call splice yet. (Though I want to cover the case kernel started supporting someday).

@dragutreis
Copy link
Copy Markdown
Author

it directly to stdout since char devices don't support seeking back

Are /dev/sd* and /dev/nvme* missing splice driver yet? I saw cat does not call splice yet. (Though I want to cover the case kernel started supporting someday).

tested on /dev/nvme0n1, splice is called successfully, so block devices do support it

Comment thread src/uu/tail/src/tail.rs Outdated
/// For regular files, checks position against file length.
/// For char/block devices, probes by reading one byte; if data exists, writes
/// it to `out` so it isn't lost (char devices don't support seeking back).
#[allow(unused_variables)]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove this allow

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright

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.

tail: unnecessary pipe2 syscall for empty files

3 participants