sync FILE hangs because of a USB disk I/O errors, applies global sync for no apparent reasons.
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 30/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- linux, rust
- Domain
- cli, operating-systems
Research direction
Start in src/uu/sync/src/sync.rs and trace the no-flags dispatch, then inspect the platform sync helpers and tests/by-util/test_sync.rs. Run the sync test command named in the issue; done means file operands use the documented per-file behavior without changing bare sync, and the regression test passes.
Written by the indexing model from the issue text.
Description
I have a ksmbd server serving three USB devices on the network,
then, I tried installing stuff with apt install,
then, initramfs got stuck,
I did some investigation about what was causing it, because no way initramfs should hang just because of my USB devices,
turns out some transcribing incoherence is present, at least according to Big Pickle, I am not an expert about linux, but the bug was real,
Big pickle identified a path that differs in the old GNU rustutils vs rust coreutils.
I noticed a maybe duplicate according to the agent but there isnt much details/info :
https://github.com/uutils/coreutils/issues/12776
Ubuntu bug report: sync FILE performs a global sync() and ignores the file argument
Package: rust-coreutils 0.8.0-0ubuntu3
Binary shipped as: /usr/bin/sync -> uutils coreutils 0.8.0
Distribution: Ubuntu 26.04.1 LTS, kernel 7.0.0-31-generic (x86_64)
Summary
On Ubuntu 26.04, sync is the Rust uutils implementation (package
rust-coreutils), meant as a drop-in for GNU coreutils sync. It is not.
sync FILE with no flags performs a global sync(2) — flushing every
mounted filesystem and waiting on every block device — instead of the
documented fsync(2) on the given file. The file operand is opened, then
discarded. This violates the documented GNU contract:
If one or more files are specified, sync only them, or their containing file
systems. --sync(1)
Behavior matrix
| invocation | GNU (reference) | rust-coreutils (shipped) | match? |
|---|---|---|---|
sync |
sync() |
sync() |
ok |
sync FILE |
fsync(FILE) |
sync() |
BUG |
sync -f FILE |
syncfs(FILE) |
syncfs(FILE) |
ok |
sync -d FILE |
fdatasync(FILE) |
fdatasync(FILE) |
ok |
Only the no-flags + file operand combination is wrong — also the most
common way scripts call sync. strace proof on the same file:
$ strace -e trace=sync,fsync sync /boot/initrd.img-$(uname -r)
gnusync -> fsync(3) (GNU 9.7, correct)
sync -> sync() (rust-coreutils 0.8.0, the bug)
The bug, end to end (1 → 2 → 3 → 4)
1 — the call (/usr/bin/dracut:3606):
if ! sync "$outfile" 2> /dev/null; then
2 — the bug (src/uu/sync/src/sync.rs, 0.8.0 / upstream main):
} else {
sync()?; // ✗ global sync — file operand ignored
}
3 — the fix (sync.rs corrected):
} else if !files.is_empty() {
fsync(&files)?; // ✓ per-file fsync
} else {
sync()?; // bare `sync` only
}
4 — the reference (src/sync.c, GNU coreutils master):
else if (! arg_data)
mode = MODE_FILE; // ← sync FILE lands here
...
case MODE_FILE:
sync_status = fsync (fd); // → one file flushed
1 → 2 = the trap. 3 ≡ 4 = the fix.
Root cause
The unix platform module implements do_sync, do_syncfs, do_fdatasync but
no do_fsync — a per-file fsync(2) path does not exist on Linux. The
default branch is the pre-file-operand full-sync stub:
if matches.get_flag(options::FILE_SYSTEM) {
syncfs(&files)?;
} else if matches.get_flag(options::DATA) {
fdatasync(&files)?;
} else {
sync()?; // ← fires even when `files` is non-empty
}
Introduced in commit 11ecf80 (2020-11-29, PR #1639) when -d/-f were
added; still present in main as of 2026-09-15 (~6 years old). Nothing in the
history documents this as intentional.
Real-world impact
dracut's sync "$outfile" becomes a global sync(), which synchronously waits
on every attached device. On the affected machine a USB-attached NTFS disk
was in an error state; the global sync blocked in the kernel's
ntfs_sync_fs -> blkdev_issue_flush -> submit_bio_wait path and dpkg --configure -a / initramfs regeneration hung indefinitely.
Separate I/O issue noted, not investigated here (the trigger that made the
hang possible):
kernel: sd 1:0:0:0: [sdb] tag#0 CDB: Synchronize Cache(10) 35 00...
kernel: I/O error, dev sdb, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 2
kernel: hung tasks (udisksd, udev) blocked for >120s in submit_bio_wait
A correct sync FILE (fsync) would only have flushed the initramfs file on the
root ext4 filesystem and never touched the USB disk.
Workaround / local fix (applied on this box)
Two options, both restoring sync FILE -> fsync(file):
-
Symlink to the shipped GNU binary (no build required):
ln -s /usr/bin/gnusync /usr/local/bin/syncDoes not survive removal of
coreutils. -
Self-built patched uutils 0.8.0 (preferred; current state here):
/usr/local/bin/syncis uutils coreutils 0.8.0 rebuilt with the fix
below, verified by strace (sync FILE->fsync(3) = 0). The previous
symlink is backed up at/usr/local/bin/sync.gnusymlink.bak; revert with
rm /usr/local/bin/sync && mv /usr/local/bin/sync.gnusymlink.bak /usr/local/bin/sync.
Suggested fix
// platform (unix)
pub fn do_fsync(files: &[String]) -> UResult<()> {
do_sync_with(files, rustix::fs::fsync)
}
// uumain dispatch
} else if !files.is_empty() {
fsync(&files)?; // GNU MODE_FILE behavior
} else {
sync()?; // only for bare `sync`
}
Fix status: commits, patch, and regression test (checked 2026-09-15)
Prepared against uutils/coreutils main (base commit 4f11d2b17), as a
standalone patch (a PR is planned separately):
- Fix commit:
b9dfbeaee— "sync: fsync() file operands when no -d/-f flags
(GNU MODE_FILE compat)", on branchfix-sync-fsync-file-operands. - Patch:
git format-patchoutput in~/Desktop/pr-sync-fsync/0001-….patch
(applies withgit am). - 0.8.0 backport (this box's shipped version, nix-based code):
~/Desktop/pr-sync-fsync/backport-0.8.0-sync.patch; prebuilt x86_64 binary
in the same folder.
The change follows the existing fdatasync/syncfs structure, three parts:
- dispatch:
else if !files.is_empty() { fsync(&files)?; }— the decision - glue:
fn fsync(files) { platform::do_fsync(files) }— pass-through - worker:
pub fn do_fsync(files) { do_sync_with(files, rustix::fs::fsync) }
— the per-filefsync(2)loop
Regression test added to tests/by-util/test_sync.rs:
#[cfg(any(target_os = "linux", target_os = "android"))]
#[test]
fn test_sync_file_operands_fsync_each_file() {
new_ucmd!().arg("/proc/self/mem").fails().stderr_contains("error syncing");
}
- Discriminates the bug: on unpatched code
sync /proc/self/memexits 0 via
the globalsync()(test fails "Command was expected to fail"); with the fix
it hitsfsync(2), getsEINVAL, exits 1 -> test passes. - Run with:
cargo test --features sync --test tests test_sync_ - Result: full sync suite 15/15 on patched
mainand on the 0.8.0 backport.
Upstream status (checked 2026-09-15, uutils/coreutils main)
- Bug still present in
main; no issue reports this specific case. - Fix exists only as the standalone patch above (
b9dfbeaee), not yet merged. - Adjacent: PR #11393 (merged 2026-04-03) fixed
sync -fwith no operands
(different corner of the same dispatch); issue #12776 (open) coverssync FILEswallowing per-filefsyncerrors on/proc/self/mem,/dev/full—
both consequences of the missing per-file fsync path.
Reproduction (root)
strace -e trace=sync,syncfs,fsync,fdatasync sync /boot/initrd.img-$(uname -r)
# Expected (GNU): fsync(3) Actual (rust-coreutils 0.8.0): sync()
- Dominant language
- Rust
- Stars
- 24.1k
- Forks
- 2k
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 365
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from uutils/coreutils
-
U - ls
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
U - ls
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
U - tr
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
U - date
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
U - date
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
All issues in uutils/coreutils
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
kwakseongjae/auto-hwp#319 ·
-
area:cli bug filter-quality good first issue priority:medium
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
bevyengine/bevy#25861 ·
-
comp-datalake
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
ClickHouse/ClickHouse#121222 ·
-
enhancement remote
Difficulty 2/5 1-3 hours Newbie friendliness 68/100