[RFC v1] man/man2/close.2: CAVEATS: Document divergence from POSIX.1-2024
Alejandro Colomar
alx@kernel.org
Sun Jan 18 22:23:01 GMT 2026
Hi Zack and others,
Just a gentle ping. It would be nice to have an agreement for some
patch.
Have a lovely night!
Alex
On Fri, May 23, 2025 at 02:10:57PM -0400, Zack Weinberg wrote:
> Taking everything said in this thread into account, I have attempted to
> wordsmith new language for the close(2) manpage. Please let me know
> what you think, and please help me with the bits marked in square
> brackets. I can make this into a proper patch for the manpages
> when everyone is happy with it.
>
> zw
>
> ---
>
> DESCRIPTION
> ... existing text ...
>
> close() always succeeds. That is, after it returns, _fd_ has
> always been disconnected from the open file it formerly referred
> to, and its number can be recycled to refer to some other file.
> Furthermore, if _fd_ was the last reference to the underlying
> open file description, the resources associated with the open file
> description will always have been scheduled to be released.
>
> However, close may report _delayed errors_ from a previous I/O
> operation. Therefore, its return value should not be ignored.
>
> RETURN VALUE
> close() returns zero if there are no delayed errors to report,
> or -1 if there _might_ be delayed errors.
>
> When close() returns -1, check _errno_ to see what the situation
> actually is. Most, but not all, _errno_ codes indicate a delayed
> I/O error that should be reported to the user. See ERRORS and
> NOTES for more detail.
>
> [QUERY: Is it ever possible to get delayed errors on close() from
> a file that was opened with O_RDONLY? What about a file that was
> opened with O_RDWR but never actually written to? If people only
> have to worry about delayed errors if the file was actually
> written to, we should say so at this point.
>
> It would also be good to mention whether it is possible to get a
> delayed error on close() even if a previous call to fsync() or
> fdatasync() succeeded and there haven’t been any more writes to
> that file *description* (not necessarily via the fd being closed)
> since.]
>
> ERRORS
> EBADF _fd_ wasn’t open in the first place, or is outside the
> valid numeric range for file descriptors.
>
> EINPROGRESS
> EINTR
> There are no delayed errors to report, but the kernel is
> still doing some clean-up work in the background. This
> situation should be treated the same as if close() had
> returned zero. Do not retry the close(), and do not report
> an error to the user.
>
> EDQUOT
> EFBIG
> EIO
> ENOSPC
> These are the most common errno codes associated with
> delayed I/O errors. They should be treated as a hard
> failure to write to the file that was formerly associated
> with _fd_, the same as if an earlier write(2) had failed
> with one of these codes. The file has still been closed!
> Do not retry the close(). But do report an error to the user.
>
> Depending on the underlying file, close() may return other errno
> codes; these should generally also be treated as delayed I/O errors.
>
> NOTES
> Dealing with error returns from close()
>
> As discussed above, close() always closes the file. Except when
> errno is set to EBADF, EINPROGRESS, or EINTR, an error return from
> close() reports a _delayed I/O error_ from a previous write()
> operation.
>
> It is vital to report delayed I/O errors to the user; failing to
> check the return value of close() can cause _silent_ loss of data.
> The most common situations where this actually happens involve
> networked filesystems, where, in the name of throughput, write()
> often returns success before the server has actually confirmed a
> successful write.
>
> However, it is also vital to understand that _no matter what_
> close() returns, and _no matter what_ it sets errno to, when it
> returns, _the file descriptor passed to close() has been closed_,
> and its number is _immediately_ available for reuse by open(2),
> dup(2), etc. Therefore, one should never retry a close(), not
> even if it set errno to a value that normally indicates the
> operation needs to be retried (e.g. EINTR). Retrying a close()
> is a serious bug, particularly in a multithreaded program; if
> the file descriptor number has already been reused, _that file_
> will get closed out from under whatever other thread opened it.
>
> [Possibly something about fsync/fdatasync here?]
>
> BUGS
> Prior to POSIX.1-2024, there was no official guarantee that
> close() would always close the file descriptor, even on error.
> Linux has always closed the file descriptor, even on error,
> but other implementations might not have.
>
> The only such implementation we have heard of is HP-UX; at least
> some versions of HP-UX’s man page for close() said it should be
> retried if it returned -1 with errno set to EINTR. (If you know
> exactly which versions of HP-UX are affected, or of any other
> Unix where close() doesn’t always close the file descriptor,
> please contact us about it.)
>
> Portable code should nonetheless never retry a failed close(); the
> consequences of a file descriptor leak are far less dangerous than
> the consequences of closing a file out from under another thread.
--
<https://www.alejandro-colomar.es>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20260118/f6a7a630/attachment-0001.sig>
More information about the Libc-alpha
mailing list