sync Command in Linux: Complete Guide to Flushing File System Buffers and Parameters

sync command in Linux and it perimeters

I learned to respect sync the hard way — years ago, pulling a USB drive right after a file copy finished on screen, only to find the file was corrupted on the other end. The copy had “finished” from the shell’s point of view, but the actual data was still sitting in memory, not yet written to the physical device. That’s exactly the gap sync exists to close, and understanding why that gap exists in the first place is the whole point of this guide.

What sync Does

sync forces the kernel to write all buffered, unwritten filesystem data (called “dirty” pages in kernel terminology) out to the underlying storage devices.

sync

This command, run with no arguments, flushes everything system-wide — every dirty page across every mounted, writable filesystem — and doesn’t print anything on success.

Checking the version and available options:

sync --help
Usage: sync [OPTION] [FILE]...
Synchronize cached writes to persistent storage

If one or more files are specified, sync only them,
or their containing file systems.

  -d, --data             sync only file data, no unneeded metadata
  -f, --file-system      sync the file systems that contain the files
      --help        display this help and exit
      --version     output version information and exit

Why This Is Necessary: Write Caching and Dirty Pages

To understand why sync matters, you need to understand that Linux (like virtually every modern operating system) doesn’t write data to disk the instant a program calls write(). Instead, the kernel keeps a page cache in RAM. When a process writes data, that data typically lands in the page cache first, marked as “dirty” (meaning: modified in memory, not yet reflected on disk), and the write() system call returns success to the application immediately — long before the data has actually touched physical storage.

This is a deliberate and hugely important performance optimization. RAM is dramatically faster than disk, so batching writes and flushing them periodically (rather than synchronously on every single write) makes the whole system faster. The kernel handles this automatically in the background via a set of kernel threads (historically pdflush, now flusher threads per block device on modern kernels), governed by tunables like vm.dirty_ratio and vm.dirty_expire_centisecs in /proc/sys/vm/.

The tradeoff: if the system loses power, crashes, or a removable device is physically disconnected before those dirty pages are flushed, that data is lost — even though every application involved believed the write had already succeeded. sync is the manual override that says “flush everything right now, don’t wait for the kernel’s normal schedule.”

Checking Dirty Page State

You can actually see how much data is currently sitting dirty, unflushed, in /proc/meminfo:

grep -i dirty /proc/meminfo
Dirty:              1024 kB
Writeback:             0 kB

Dirty shows bytes waiting to be written; Writeback shows bytes actively being written out right now. Watching this value drop to (or near) zero after running sync is a direct, observable confirmation that the flush actually happened.

Options Explained

-f, –file-system

sync -f /mnt/usbdrive/somefile.txt

Restricts the sync to only the filesystem(s) containing the specified file(s), rather than flushing the entire system. This is meaningfully faster on a busy multi-disk system where you only care about one particular filesystem being safely flushed (like the removable drive you’re about to unplug) and don’t want to wait on unrelated I/O elsewhere.

-d, –data

sync -d somefile.txt

Syncs only the file’s data blocks, skipping metadata that isn’t strictly necessary (like access-time updates). This is a lighter-weight flush when you specifically care about the file’s actual content being safe, not every last piece of filesystem bookkeeping about it.

Related System Calls (For Understanding, Not Direct Use)

The sync command is a thin wrapper around underlying system calls that programs can also call directly:

If you’re troubleshooting why a particular application seems slow on writes, and its logs mention fsync calls, this is the same underlying mechanism — the application is deliberately forcing a flush after every transaction to guarantee durability, at the cost of write throughput. This is a very common and correct tradeoff in database engines (PostgreSQL, MySQL, SQLite all rely on fsync/fdatasync heavily for their durability guarantees).

Practical Sysadmin Use Cases

Before removing external/removable storage:

sync
sudo umount /mnt/usbdrive

This is the classic, most common real-world reason to invoke sync manually. Note that a clean umount already performs its own internal sync as part of unmounting — but running sync explicitly beforehand, especially before a umount that might be delayed by “busy” errors, is a defensive habit worth keeping, particularly on older systems or unusual filesystem types where you’re less certain about the unmount behavior.

Before a hard reboot or power cycle on an embedded/headless system:

sync && sync && sync

You’ll still see this “triple sync” idiom in a lot of older documentation and scripts, dating back to a time when a single sync call wasn’t always guaranteed to fully complete before returning, especially on systems under heavy I/O load. On modern Linux, a single sync genuinely blocks until the flush is complete, making the triple invocation more superstition than necessity today — but it remains harmless, and you’ll still see it recommended in some embedded/router firmware documentation before a manual power cycle.

In a shutdown/reboot pipeline (already handled automatically):

Modern init systems (systemd) automatically perform equivalent sync operations as part of a clean shutdown sequence, so you don’t generally need to manually call sync before a normal reboot or shutdown -h now — this matters mainly for abrupt scenarios: yanking removable media, or a script that’s about to trigger a forced/unclean power-off on hardware you don’t fully trust to shut down gracefully.

Verifying flush state in a monitoring/backup script:

#!/bin/bash
cp important_data.db /mnt/backup/
sync -f /mnt/backup/important_data.db
dirty=$(grep Dirty /proc/meminfo | awk '{print $2}')
echo "Backup copied and synced. Remaining dirty pages system-wide: ${dirty}kB"

sync and Journaling Filesystems

It’s worth being precise about what sync does and doesn’t guarantee, especially on modern journaling filesystems like ext4 or xfs. A journaling filesystem maintains its own internal log of pending metadata (and sometimes data) changes, which it uses to recover quickly and consistently after a crash, without needing a full filesystem check. sync forces the page cache’s dirty pages out to the underlying block device, but the filesystem’s own journal commit behavior is a related, complementary mechanism operating at a different layer — the journal is what guarantees the filesystem’s structure stays consistent even if a crash happens mid-write, while sync/fsync guarantee that specific data has actually reached the device at the moment you called it.

In practice, for ext4 (in its default ordered journaling mode) and xfs, calling fsync() on a file (or the broader sync system call) does correctly flush both the relevant data and enough journal information to make that write durable and crash-consistent. But it’s a useful mental distinction: sync is about “has this data left RAM and reached the device,” while the journal is about “if the device loses power mid-operation, will the filesystem’s own bookkeeping still be internally consistent afterward.” Both matter for real data durability, and modern Linux filesystems are designed so that a correctly-called fsync() gives you both guarantees together.

Historical Context: Why “Sync Three Times” Became a Meme

The sync; sync; sync idiom has a genuinely interesting history worth knowing, beyond just “it’s superstition now.” On very old Unix systems, and in some early Linux kernel versions, sync() could return before the flush was fully complete under certain conditions — it would initiate the writeback but not necessarily block until every last dirty buffer had actually reached the device, particularly under heavy I/O load. Running it multiple times, with the understanding that most of the work would already be done by later invocations, became a defensive habit to increase confidence before a manual power cycle on hardware where an incomplete flush could mean real data loss (this was especially relevant in the era before journaling filesystems existed at all, when a crash mid-write could corrupt an entire filesystem, not just the specific file being written).

On any reasonably modern Linux kernel, a single sync call genuinely blocks until the flush is complete, making the triple-invocation unnecessary from a strict technical standpoint — but you’ll still find it recommended in documentation for embedded devices, routers running minimal Linux-based firmware, and some older sysadmin folklore, and it remains completely harmless to do, which is likely why the habit has persisted this long despite not being technically required anymore.

Troubleshooting

Performance Considerations

Calling sync forces immediate I/O that the kernel would otherwise have scheduled more efficiently in the background, so frequent manual sync calls in a hot code path or busy script can genuinely hurt performance by defeating the write-caching optimization the kernel is trying to give you. Use it deliberately, at meaningful checkpoints (before removing media, before a risky operation), not as a routine habit sprinkled through scripts.

Security Implications

sync itself doesn’t have significant direct security implications — it’s a data-integrity tool, not an access-control one. Its relevance to security is mostly indirect: ensuring critical audit logs, database transaction logs, and configuration changes are actually persisted to disk (via fsync-backed application behavior, or a deliberate sync before a risky operation) is part of maintaining trustworthy forensic and audit trails, especially on systems that might be forcibly powered off or that operate in environments prone to unexpected shutdowns.

sync vs Related Commands

CommandPurpose
syncFlush all dirty pages system-wide (or scoped to specified files) to disk
fsync() (in application code)Flush a single open file’s data/metadata, called by the application itself
umountDetaches a filesystem; performs an implicit sync as part of a clean unmount
blockdev --flushbufsLower-level flush of a specific block device’s buffer cache

Compatibility Across Distributions

sync is part of GNU coreutils and ships by default on every mainstream Linux distribution — behavior and flags are consistent across Debian, Ubuntu, RHEL, Fedora, Arch, and openSUSE. It’s also present (with largely equivalent behavior, though implementation details differ) on BSD and macOS systems, since flushing cached writes to disk is a universal Unix concept, not a Linux-specific one.

Summary

sync closes the gap between “my program says the write finished” and “the data is actually safe on physical storage” — a gap that exists because of the write-caching the kernel uses to keep the whole system fast. Knowing when to reach for it (before pulling removable media, before a risky forced power-off) and understanding that well-behaved applications like databases handle their own durability via fsync() internally, rather than relying on you to call sync for them, gives you a much clearer mental model of how Linux actually manages disk I/O.

References

Exit mobile version