Thread (49 messages) 49 messages, 14 authors, 2026-02-06

Re: [RFC v1] man/man2/close.2: CAVEATS: Document divergence from POSIX.1-2024

From: Jan Kara <jack@suse.cz>
Date: 2026-01-26 12:15:32
Also in: linux-fsdevel

On Sun 25-01-26 10:37:01, Zack Weinberg wrote:
On Sat, Jan 24, 2026, at 4:57 PM, The 8472 wrote:
quoted
quoted
    Delayed errors reported by close()

        In a variety of situations, most notably when writing to a file
        that is hosted on a network file server, write(2) operations may
        “optimistically” return successfully as soon as the write has
        been queued for processing.

        close(2) waits for confirmation that *most* of the processing
        for previous writes to a file has been completed, and reports
        any errors that the earlier write() calls *would have* reported,
        if they hadn’t returned optimistically.  Especially, close()
        will report “disk full” (ENOSPC) and “disk quota exceeded”
        (EDQUOT) errors that write() didn’t wait for.
The Rust standard library team is also interested in this topic, there
is lively discussion[1] whether it makes sense to surface errors from
close at all. Our current default is to ignore them.
It is my understanding that errors may not have happened yet at
the time of close due to delayed writeback or additional descriptors
pointing to the description, e.g. in a forked child, and thus
close() is not a reliable mechanism for error detection and
fsync() is the only available option.

[1] https://github.com/rust-lang/libs-team/issues/705
This is something I care about a lot as well, but I currently don’t
have an *opinion*.  To form an informed opinion, I need the answers
to these questions:
quoted
quoted
     [QUERY: Do delayed errors ever happen in any of these situations?

        - The fd is not the last reference to the open file description

        - The OFD was opened with O_RDONLY

        - The OFD was opened with O_RDWR but has never actually
          been written to

        - No data has been written to the OFD since the last call to
          fsync() for that OFD

        - No data has been written to the OFD since the last call to
          fdatasync() for that OFD

        If we can give some guidance about when people don’t need to
        worry about delayed errors, it would be helpful.]
In particular, I really hope delayed errors *aren’t* ever reported
when you close a file descriptor that *isn’t* the last reference
to its open file description, because the thread-safe way to close
stdout without losing write errors[2] depends on that not happening.
So I've checked and in Linux ->flush callback for the file is called
whenever you close a file descriptor (regardless whether there are other
file descriptors pointing to the same file description) so it's upto
filesystem implementation what it decides to do and which error it will
return... Checking the implementations e.g. FUSE and NFS *will* return
delayed writeback errors on *first* descriptor close even if there are
other still open descriptors for the description AFAICS.
And whether the Rust stdlib can legitimately say “leaving aside the
additional cost of calling fsync(), you do not *need* the error return
from close() because you can call fsync() first,” depends on whether
it’s actually true that you *won’t* ever get a delayed error from
close() if you called fsync() first and didn’t do any more output in
between (assume the fd has no duplicates here).  I would not be
surprised at all if those FUSE guys insisted on their right to make

    char msg[] = "soon I will be invincible\n";
    int fd = open("/test-fuse-fs/test.txt", O_WRONLY, 0666);
    write(fd, msg, sizeof(msg) - 1);
    fsync(fd);
    close(fd);

return an error *only* from the close, not the write or the fsync.
So fsync(2) must make sure data is persistently stored and return error if
it was not. Thus as a VFS person I'd consider it a filesystem bug if an
error preveting reading data later was not returned from fsync(2). OTOH
that doesn't necessarily mean that later close doesn't return an error -
e.g. FUSE does communicate with the server on close that can fail and
error can be returned.

With this in mind let me now try to answer your remaining questions:
quoted
quoted
        - The OFD was opened with O_RDONLY
If the filesystem supports atime, close can in principle report that atime
update failed. 
quoted
quoted
        - The OFD was opened with O_RDWR but has never actually
          been written to
The same as above but with inode mtime updates.
quoted
quoted
        - No data has been written to the OFD since the last call to
          fsync() for that OFD
No writeback errors should happen in this case. As I wrote above I'd
consider this a filesystem bug.
quoted
quoted
        - No data has been written to the OFD since the last call to
          fdatasync() for that OFD
Errors can happen because some inode metadata (in practice probably only
inode time stamps) may still need to be written out.

So in the cases described above (except for fsync()) you may get delayed
errors on close. But since in all those cases no data is lost, I don't
think 99.9% of applications care at all...

								Honza
-- 
Jan Kara [off-list ref]
SUSE Labs, CR
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help