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: The 8472 <hidden>
Date: 2026-01-24 19:34:19
Also in: linux-fsdevel

On 23/01/2026 01:33, Zack Weinberg wrote:

[...]
ERRORS
        EBADF  The fd argument was not a valid, open file descriptor.
Unfortunately EBADF from FUSE is passed through unfiltered by the kernel
on close[0], that makes it more difficult to reliably detect bugs relating
to double-closes of file descriptors.

[...]
    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.

        (To wait for *all* processing to complete, it is necessary to
        use fsync(2) as well.)

        Because of these delayed errors, it’s important to check the
        return value of close() and handle any errors it reports.
        Ignoring delayed errors can cause silent loss of data.

        However, when handling delayed errors, keep in mind that the
        close() call should *not* be repeated.  When close() has a
        delayed error to report, it still closes the file before
        returning.  The file descriptor number might already have been
        reused for some other file, especially in multithreaded
        programs.  To make another attempt at the failed writes, it’s
        necessary to reopen the file and start all over again.

     [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.]
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.

Some users do care specifically about the unusual behavior
on NFS, and don't want to use a heavy hammer like fsync. It's unfortunate
that there's no middle ground to get errors on an open file descriptor
or initiate the NFS flush behavior without a full fsync.


[0] https://lore.kernel.org/linux-fsdevel/1b946a20-5e8a-497e-96ef-f7b1e037edcb@infinite-source.de/ (local)
[1] https://github.com/rust-lang/libs-team/issues/705
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help