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

The 8472 kernel@infinite-source.de
Sat Jan 24 19:34:01 GMT 2026


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/
[1] https://github.com/rust-lang/libs-team/issues/705



More information about the Libc-alpha mailing list