fflush() works on FILE*, it just flushes the internal buffers in the FILE* of your application out to the OS.

fsync works on a lower level, it tells the OS to flush its buffers to the physical media.

OSs heavily cache data you write to a file. If the OS enforced every write to hit the drive, things would be very slow. fsync (among other things) allows you to control when the data should hit the drive.

Furthermore, fsync/commit works on a file descriptor. It has no knowledge of a FILE* and can't flush its buffers. FILE* lives in your application, file descriptors live in the OS kernel, typically.

Answer from nos on Stack Overflow
Top answer
1 of 6
119

fflush() works on FILE*, it just flushes the internal buffers in the FILE* of your application out to the OS.

fsync works on a lower level, it tells the OS to flush its buffers to the physical media.

OSs heavily cache data you write to a file. If the OS enforced every write to hit the drive, things would be very slow. fsync (among other things) allows you to control when the data should hit the drive.

Furthermore, fsync/commit works on a file descriptor. It has no knowledge of a FILE* and can't flush its buffers. FILE* lives in your application, file descriptors live in the OS kernel, typically.

2 of 6
13

The standard C function fflush() and the POSIX system call fsync() are conceptually somewhat similar. fflush() operates on C file streams (FILE objects), and is therefore portable. fsync() operate on POSIX file descriptors. Both cause buffered data to be sent to a destination.

On a POSIX system, each C file stream has an associated file descriptor, and all the operations on a C file stream will be implemented by delegating, when necessary, to POSIX system calls that operate on the file descriptor.

One might think that a call to fflush on a POSIX system would cause a write of any data in the buffer of the file stream, followed by a call of fsync() for the file descriptor of that file stream. So on a POSIX system there would be no need to follow a call to fflush with a call to fsync(fileno(fp)). But is that the case: is there a call to fsync from fflush?

No, calling fflush on a POSIX system does not imply that fsync will be called.

The C standard for fflush says (emphasis added) it

causes any unwritten data for [the] stream to be delivered to the host environment to be written to the file

Saying that the data is to be written, rather than that is is written implies that further buffering by the host environment is permitted. That buffering by the "host environment" could include, for a POSIX environment, the internal buffering that fsync flushes. So a close reading of the C standard suggests that the standard does not require the POSIX implementation to call fsync.

The POSIX standard description of fflush does not declare, as an extension of the C semantics, that fsync is called.

🌐
LinuxQuestions.org
linuxquestions.org › questions › programming-9 › fflush-and-fsync-378849
fflush and fsync?
Hello.... I want to ask a question on C programming on Linux. There are 2 functions: fflush and fsync, both said that they are putting the data to
🌐
curl
curl.se › mail › lib-2008-04 › 0391.html
Curl: Re: fflush and fsync
So if you're running a program which finishes with fflush+fsync+fclose, and then another program on the same machine to read the newly written file, you really don't need the fflush+fsync. If they make a difference, it indicates a bug elsewhere.
🌐
Coderanch
coderanch.com › t › 278811 › java › fflush-fsync
fflush and fsync (I/O and Streams forum at Coderanch)
For writers and outputstreams, there is no need for fsync or any equivalent; it's all handled by flush() or close(). If you're using a RandomAccessFile you need to call close() at the end to achieve the effect of a fflush and fsync, and if you're using a FileChannel you can call either close() or force() - the latter allows the channel to remain open, like flush().
🌐
LWN.net
lwn.net › Articles › 457667
Ensuring data reaches disk [LWN.net]
Remember that fwrite()s to the ... essence, associating a file stream with a synchronous file descriptor means that an fsync() call is not needed on the file descriptor after the fflush()....
Top answer
1 of 4
4

1. As you correctly concluded from your research fflush synchronizes the user-space buffered data to kernel-level cache (since it's working with FILE objects that reside at user-level and are invisible to kernel), whereas fsync or sync (working directly with file descriptors) synchronize kernel cached data with device. However, the latter comes without a guarantee that the data has been actually written to the storage device — as these usually come with their own caches as well. I would expect the same holds for msync called with MS_SYNC flag as well.

Relatedly, I find the distinction between synchronized and synchronous operations very useful when talking about the topic. Here's how Robert Love puts it succinctly:

A synchronous write operation does not return until the written data is—at least—stored in the kernel’s buffer cache. [...] A synchronized operation is more restrictive and safer than a merely synchronous operation. A synchronized write operation flushes the data to disk, ensuring that the on-disk data is always synchronized vis-à-vis the corresponding kernel buffers.

With that in mind you can call open with O_SYNC flag (together with some other flag that opens the file with a write permission) to enforce synchronized write operations. Again, as you correctly assumed this will work only with WRITE THROUGH disk caching policy, which effectively amounts to disabling disk caching.

You can read this answer about how to disable disk caching on Linux. Be sure to also check this website which also covers SCSI-based in addition to ATA-based devices (to read about different types of disks see this page on Microsoft SQL Server 2005, last updated: Apr 19, 2018).

Speaking of which, it is very informative to read about how the issue is dealt with on Windows machines:

To open a file for unbuffered I/O, call the CreateFile function with the FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH flags. This prevents the file contents from being cached and flushes the metadata to disk with each write. For more information, see CreateFile.

Apparently, this is how Microsoft SQL Server 2005 family ensures data integrity:

All versions of SQL Server open the log and data files using the Win32 CreateFile function. The dwFlagsAndAttributes member includes the FILE_FLAG_WRITE_THROUGH option when opened by SQL Server. [...] This option instructs the system to write through any intermediate cache and go directly to disk. The system can still cache write operations, but cannot lazily flush them.

I'm saying this is informative in particular because of this blog post from 2012 showing that some SATA disks ignore the FILE_FLAG_WRITE_THROUGH! I don't know what the current state of affairs is, but it seems that in order to ensure that writing to a disk is truly synchronized, you need to:

  1. Disable disk caching using your device drivers.
  2. Make sure that the specific device you're using supports write-through/no-caching policy.

However, if you're looking for a guarantee of data integrity you could just buy a disk with its own battery-based power supply that goes beyond capacitors (which is usually only enough for completing the on-going write processes). As put in the conclusion in the blog article mentioned above:

Bottom-line, use Enterprise-Class disks for your data and transaction log files. [...] Actually, the situation is not as dramatic as it seems. Many RAID controllers have battery-backed cache and do not need to honor the write-through requirement.

2. To (partially) answer the second question, this is from the man pages SYNC(2):

According to the standard specification (e.g., POSIX.1-2001), sync() schedules the writes, but may return before the actual writing is done. However, since version 1.3.20 Linux does actually wait. (This still does not guarantee data integrity: modern disks have large caches.)

This would imply that fsync and sync work differently, however, note they're both implemented in unistd.h which suggests some consistency between them. However, I would follow Robert Love who does not recommend using sync syscall when writing your own code.

The only real use for sync() is in the implementation of the sync utility. Applications should use fsync() and fdatasync() to commit to disk the data of only the requisite file descriptors. Note that sync() may take several minutes or longer to complete on a busy system.

2 of 4
0

"I don't have any solution, but certainly admire the problem."

From all I read from your good references, is that there is no standard. The standard ends somewhere in the kernel. The kernel controls the device driver and the device driver (possibly supplied by the disk manufacturer) controls the disk through an API (device has small computer on board). The manufacturer may have added capacitors/battery with just enough power to flush its device buffers in case of power failure, or he may have not. The device may provide a sync function but whether this truely syncs (flushes) the device buffers is not known (device dependent). So unless you select and install a device according to your specifications (and verify those specs), you are never sure.

🌐
Rust Internals
internals.rust-lang.org › libs
<File as Write>::flush should call fsync - libs - Rust Internals
April 9, 2017 - I noticed ::flush on unix is currently a no-op. I was expecting it to call fsync. Thoughts?
🌐
PHP
php.net › manual › en › function.fsync.php
PHP: fsync - Manual
Two points worth noting: 1. fsync() is not suitable for high throughput, use it only when the durability of a file write really matters to you. 2. fsync() includes an implicit call to fflush() so you don't need to manually flush before you sync.
🌐
PHP.Watch
php.watch › versions › 8.1 › fsync-fdatasync
New `fsync` and `fdatasync` functions - PHP 8.1 • PHP.Watch
PHP already has fflush function ... to the operating system. The new fsync and fdatasync functions are similar to fflush, but they also request the operating system to flush the operating systems write buffers to the actual storage media....
Find elsewhere
🌐
GitHub
github.com › LLNL › UnifyFS › issues › 374
Design: should fflush() sync extents (it currently doesn't) · Issue #374 · llnl/UnifyFS
October 8, 2019 - fsync() works though. Should we make it so fflush() behaves the same as fsync()? They're not supposed to behave the same in POSIX (sync to OS buffers, vs sync to disk). Do we want to cheat and make fflush() sync out the extents too? The benefit would be that if you're using stream IO, you already have a file pointer, so it's easier to sync with fflush() than fsync().
Author   tonyhutter
🌐
Alibaba Cloud
topic.alibabacloud.com › a › connection-and-difference-between-font-colorredfflushfont-and-fsync_8_8_32111254.html
Connection and difference between fflush and fsync
Fsync accepts an int-type file descriptor. ... Fflush: writes the buffer calling write function in the C library to the disk [actually writing the buffer to the kernel].
🌐
Google Groups
groups.google.com › g › android-ndk › c › jcObbZx2pqg
fflush does not flush
If you go back, you'll see that the data was not > saved to disk. First and foremost: fflush() flushes the buffer in your process, causing a write() call. This does *not* do a synchronous disk write. For that, you need to use fsync(), which takes a file descriptor (so after you fflush(fp) you ...
🌐
Linux Man Pages
man7.org › linux › man-pages › man2 › fsync.2.html
fsync(2) - Linux manual page
fsync() transfers ("flushes") all modified in-core data of (i.e., modified buffer cache pages for) the file referred to by the file descriptor fd to the disk device (or other permanent storage device) so that all changed information can be retrieved even if the system crashes or is rebooted.
🌐
Linux Man Pages
linux.die.net › man › 2 › fsync
fsync(2) - Linux man page
fsync() transfers ("flushes") all modified in-core data of (i.e., modified buffer cache pages for) the file referred to by the file descriptor fd to the disk device (or other permanent storage device) so that all changed information can be retrieved even after the system crashed or was rebooted.
🌐
steveyang
steveyang.blog › 首頁 › [linux] fflush(file*), sync(), syncfs(), fsync(fd), fdatasync(fd)
[Linux] fflush(FILE*), sync(), syncfs(), fsync(fd), fdatasync(fd) - steveyang
July 28, 2022 - fsync() transfers ("flushes") all modified in-core data of (ie, modified buffer cache pages for) the file referred to by the file descriptor fd to the disk device (or other permanent storage device) so that all changed information can be retrieved even if the system crashes or is rebooted.
🌐
Narkive
comp.os.vms.narkive.com › zSCcDFpJ › dec-c-fsync-and-fflush
DEC C fsync and fflush
fflush() is in the C standard, which says it causes data to be "delivered to the host environment to be written to the file." It seems to be carefully worded to allow for buffering and synchronization activities that may complete after the function returns. fsync() is not specified in the C ...
🌐
YouTube
youtube.com › hey delphi
Windows : Difference between fflush and fsync - YouTube
Windows : Difference between fflush and fsyncTo Access My Live Chat Page, On Google, Search for "hows tech developer connect"As promised, I have a secret fea...
Published   May 8, 2023
Views   6
🌐
Derick Rethans
derickrethans.nl › phpinternalsnews-77.html
PHP Internals News: Episode 77: fsync: Buffers All The Way Down — Derick Rethans
February 25, 2021 - So again we have much as we have fflush for files. We have flush for regular output that you're trying to send to a web server. And that function will flush the internal output buffers of PHP, and it will then try and flush your web server buffers. There's an interesting parallel here because much like with fsync, flush versus fsync, you can't necessarily guarantee with fflush what the operating system will do.
🌐
GitHub
github.com › apache › nuttx › issues › 15840
[BUG] Littlefs only syncing with `fsync`, but not `fflush` · Issue #15840 · apache/nuttx
February 14, 2025 - Description / Steps to reproduce the issue This may not be considered a bug, but the behaviour of fflush on files in a littlefs filesystem does not match what I would expect to see. My setup is an RP2040 based MCU connected to an SD card...
Author   linguini1
Top answer
1 of 3
8

fwrite is writing to an internal buffer first, then sometimes (at fflush or fclose or when the buffer is full) calling the OS function write.

The OS is also doing some buffering and writes to the device might get delayed.

fsync is assuring that the OS is writing its buffers to the device.

In your case where you open-write-close you don't need to fsync. The OS knows which parts of the file are not yet written to the device. So if a second process wants to read the file the OS knows that it has the file content in memory and will not read the file content from the device.

Of course when thinking about power outage it might (depending on the circumstances) be a good idea to fsync to be sure that the file content is written to the device (which as Andrew points out, does not necessarily mean that the content is written to disc, because the device itself might do buffering).

2 of 3
4

Up to now I didn't notice, that fflush (which is called upon fclose) doesn't write to the file system, but only in an intermediate buffer. Could it be, that the time between 3) and 4) is too short and the change from 2) is not yet written to disc, so when I reopen with 4) I get a truncated file which, when it is closed again leads to permanent loss of those data?

No. A system that behaved that way would be unusable.

Should I use fsync() in that case after each file write?

No, that will just slow things down.

What do I have to consider for power outtages? It is not unlikeley, that the data corruption is related to power down.

Use a filesystem that's resistant to such corruption. Possibly even consider using a safer modification algorithm such as writing out a new version of the file with a different name, syncing, and then renaming it on top of the existing file.