[RFC v1] man/man2/close.2: CAVEATS: Document divergence from POSIX.1-2024
Jan Kara
jack@suse.cz
Thu Feb 5 09:34:19 GMT 2026
I've noticed we didn't reply to one question here:
On Wed 28-01-26 11:58:07, Zack Weinberg wrote:
> On Mon, Jan 26, 2026, at 7:49 PM, Jeff Layton wrote:
> > 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.
> ...
> > 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:
> >
> >> >> - The OFD was opened with O_RDONLY
> >
> > If the filesystem supports atime, close can in principle report that atime
> > update failed.
> >
> >> >> - The OFD was opened with O_RDWR but has never actually
> >> >> been written to
> >
> > The same as above but with inode mtime updates.
> >
> >> >> - 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.
> >
> >> >>
> >> >> - 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...
>
> ... regrettably I think this does mean the close(3) manpage still needs
> to tell people to watch out for errors, and should probably say that
> errors _can_ happen even if the file wasn’t written to, but are much
> less likely to be important in that case.
>
> And my “how to close stdout in a thread-safe manner” sample code is
> wrong, because I was wrong to think that the error reporting only
> happened on the _final_ close, when the OFD is destroyed.
>
> ... What happens if the close is implicit in a dup2() operation? Here’s
> that erroneous “how to close stdout” fragment, with comments
> indicating what I thought could and could not fail at the time I wrote
> it:
>
> // These allocate new fds, which can always fail, e.g. because
> // the program already has too many files open.
> int new_stdout = open("/dev/null", O_WRONLY);
> if (new_stdout == -1) perror_exit("/dev/null");
> int old_stdout = dup(1);
> if (old_stdout == -1) perror_exit("dup(1)");
>
> flockfile(stdout);
> if (fflush(stdout)) perror_exit("stdout: write error");
> dup2(new_stdout, 1); // cannot fail, atomically replaces fd 1
> funlockfile(stdout);
>
> // this close may receive delayed write errors from previous writes
> // to stdout
> if (close(old_stdout)) perror_exit("stdout: write error");
>
> // this close cannot fail, because it only drops an alternative
> // reference to the open file description now installed as fd 1
> close(new_stdout);
>
> Note in particular that the first close _operation_ on fd 1 is in
> consequence of dup2(new_stdout, 1). The dup2() manpage specifically
> says “the close is performed silently (i.e. any errors during the
> close are not reported by dup()” but, if stdout points to a file on
> an NFS mount, are those errors _lost_, or will they actually be
> reported by the subsequent close(old_stdout)?
It is simply lost (the error is propagated from the filesystem to VFS which
just ignores it).
> Incidentally, the dup2() manpage has a very similar example in its
> NOTES section, also presuming that close only reports errors on the
> _final_ close, not when it “merely” drops reference >=2 to an OFD.
>
> (I’m starting to think we need dup3(old, new, O_SWAP_FDS). Or is that
> already a thing somehow?)
I don't think a functionality like this currently exists.
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
More information about the Libc-alpha
mailing list