Re: flock, FAGAIN, and FWOULDBLOCK

Michael Kerrisk
2009-02-23T03:55:05Z

Matthew,

On 2/23/09, Matthew Wilcox <matthew@wil.cx> wrote:
> On Sun, Feb 22, 2009 at 09:43:36PM -0500, Carlos O'Donell wrote:
>> flock is not POSIX, it's an interface invented by 4.2BSD, and was
>> previously emulated by glibc. The glibc wrapper implemented flock with
>> fcntl and made sure to return EWOULDBLOCK.
>
> glibc's emulation of flock() using fcntl() really belongs to the Dark
> Ages of Linux. According to the comments in the kernel, flock(2) was
> added in June 1995. That's four years before parisc-linux really got
> going.
>
> The semantics of flock-locks and fcntl-locks are really, really
> different. Emulating one with the other was a really bad idea.

Quite.

>> > + ret = sys_flock(fd, cmd);
>> > + if (ret == -EAGAIN)
>> > + ret = -EWOULDBLOCK; /* fuck you HPUX */
>>
>> A more robust solution would be?
>>
>> if ((ret == -EAGAIN) || (ret == -EWOULDBLOK))
>> ret = -EWOULDBLOCK
>
> How would that differ from what Kyle wrote? Why would you want to
> assign -EWOULDBLOCK to ret if ret is already -EWOULDBLOCK?
>
>> This covers our ass since POSIX says that EAGAIN and EWOULDBLOCK *may*
>> be the same.
>
> That's irrelevant. The only thing that matters is what the kernel does.
>
>> > but somehow I suspect this interchangeable use of EAGAIN and EWOULDBLOCK
>> > is going to reveal latent problems in this part of the kernel I would
>> > rather not delve into...
>>
>> The ABI is fixed, so all we can do is cleanup the uses in the kernel,
>> and make sure we adhere to the documented APIs.
>
> We actually can do better than this ...
>
> #ifdef __KERNEL__
> #define EWOULDBLOCK EAGAIN
> #else
> #define EWOULDBLOCK /* whatever the fuck HPUX uses */
> #endif
>
> Now our kernel never returns -EWOULDBLOCK, only -EAGAIN. Correct
> applications must check for both. Incorrect applications tend to only
> check for AGAIN, not WOULDBLOCK. Problem solved.

I'm not sure how you define "correct" here. An application that
follows the BSD implementation standard need only check for
EWOULDBLOCK from flock(), I believe. (I can find no system that
documents otherwise for flock().)

If you are talking more generally, POSIX.1-2001, which doesn't specify
flock(), only refers to the use of EWOULDBLOCK in the context of
socket-related calls, where it says that a non-blocking call can fail
with either EAGAIN or EWOULDBLOCK, so I suppose that a portable
sockets application must check for both. (In all other cases of
non-blocking calls (e.g., read()/write() from files other than
sockets, sigtimedwait(), lockf(), mq_send(), mq_receive()) that fail
in circumstances where they would otherwise block, the error is always
EAGAIN, with the exception noted earlier for fcntl(F_SETLK) (EACCES or
EWOULDBLOCK).)

Cheers,

Michael

--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
git://git.kernel.org/pub/scm/docs/man-pages/man-pages.git
man-pages online: http://www.kernel.org/doc/man-pages/online_pages.html
Found a bug? http://www.kernel.org/doc/man-pages/reporting_bugs.html