Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

favorite Unix misfeature (was: 25 years ago today...)

10 views
Skip to first unread message

Brian Harvey

unread,
Jun 8, 2008, 1:13:25 PM6/8/08
to
glen herrmannsfeldt <g...@ugcs.caltech.edu> writes:
>Mark Crispin wrote:
>(snip)
>
>> I've been waiting 25+ years for this UNIX design bug to be fixed, and to
>> be able to analyze and debug freshly dead process corpses (and perhaps
>> give them CPR and revive them) instead of pickled corpses. I'm not
>> holding my breath.
>
>I keep waiting for the math library to be included without adding
>a -lm onto cc commands. It can't be that hard to do, but it wouldn't
>be unix if they changed it. Same for core files.

There are many makefile-confusers like that. One annoyance is that MacOS
doesn't have /usr/local. Another is the dozen different places X11 might
live. But those are all surmountable.

My candidate for the biggest problem is the semantics of file I/O: the lack of
mandatory file locking, the fact that creating a new file with the same name
as an old one immediately deletes the old file, no distinction between write
mode and read/alter, etc. (Yes, some of these are now available as options,
but not as the default, and therefore not as the behavior of all the system
utilities.)

Unfortunately this isn't fixable. I once taught an OS class in which students
did projects modifying FreeBSD, and one of the assignments was to implement
PDP-10 file semantics. It turned out to break everything; the system wouldn't
even boot successfully. (We rescued the assignment by having them use the old
file semantics for processes running as root.)

Mark Crispin

unread,
Jun 8, 2008, 2:38:15 PM6/8/08
to
On Sun, 8 Jun 2008, Brian Harvey posted:

> My candidate for the biggest problem is the semantics of file I/O: the lack of
> mandatory file locking,

It's worse than you portray it.

UNIX has two different forms of locking: flock() locking and POSIX-style
locking via fcntl(). Both are defined as advisory.

flock() locking is whole-file. It only works on local filesystems. On
network filesystems, it either returns success but is a no-op or returns
an error. The latter behavior was briefly on Linux, and was a big
surprise to applications which for the prior 2 decades had assumed that a
failure return from a no-block flock() meant that the lock was in use.

fcntl() locking is file-region. It works on network filesystems but via a
pair of notorious daemons (lockd and statd) that are easily made deadlock
and thus take down the entire cluster. Every few years, SUN claims to
have fixed this problem, and equally reliably I demonstrate that they have
not.

fcntl() locking also has what the BSD developers call "completely stupid
semantics" in their man page:
This interface follows the completely stupid semantics of System V and
IEEE Std 1003.1-1988 (``POSIX.1'') that require that all locks associated
with a file for a given process are removed when any file descriptor for
that file is closed by that process. This semantic means that applica-
tions must be aware of any files that a subroutine library may access.
For example if an application for updating the password file locks the
password file database while making the update, and then calls
getpwname(3) to retrieve a record, the lock will be lost because
getpwname(3) opens, reads, and closes the password database. The data-
base close will release all locks that the process has associated with
the database, even if the library routine never requested a lock on the
database. Another minor semantic problem with this interface is that
locks are not inherited by a child process created using the fork(2)
function.

The said "completely stupid semantics" have caused me many years of
recurring anguish, particularly on platforms like Solaris and Tru64 which
pretend that they have flock() locking but instead call fcntl() locking
internally.

On top of that, you can't even assume that they tell the truth when they
say that the locking is advisory! Cygwin calls Windows locking internally
so the locks are mandatory.

What an application programmer really needs are what TOPS-20 and later
versions of TOPS-10 both had: both advisory *and* mandatory locking that
works reliably on both local and remote filesystems.

You can get around the lack of mandatory locking by clever use of advisory
locking. For example, my application uses two advisory locks, one to
synchronize between shared write and the other to guarantee exclusive
write. I'd only need one lock if mandatory locking was provided in the
open() mode the way it is on both TOPS-20 and TOPS-10.

> the fact that creating a new file with the same name
> as an old one immediately deletes the old file,

Did TOPS-10 have a separate "create" vs. "open write"? ISTR that it did
not. IIRC, if you opened an existing file for write as opposed to
read-write on TOPS-10, your writes would go to new disk blocks as opposed
to superceding the existing ones (and defer the directory update to close
time) which is certainly friendlier than the UNIX behavior.

TOPS-20 had file versions. Big wind.

> no distinction between write
> mode and read/alter,

What version of UNIX lacked O_RDWR? Some old PDP-11 version?

> Unfortunately this isn't fixable. I once taught an OS class in which students
> did projects modifying FreeBSD, and one of the assignments was to implement
> PDP-10 file semantics. It turned out to break everything; the system wouldn't
> even boot successfully. (We rescued the assignment by having them use the old
> file semantics for processes running as root.)

Do you remember what broken and why?

-- Mark --

http://panda.com/mrc
Democracy is two wolves and a sheep deciding what to eat for lunch.
Liberty is a well-armed sheep contesting the vote.

Brian Harvey

unread,
Jun 8, 2008, 3:18:24 PM6/8/08
to
Mark Crispin <m...@Panda.COM> writes:
>Did TOPS-10 have a separate "create" vs. "open write"? ISTR that it did
>not. IIRC, if you opened an existing file for write as opposed to
>read-write on TOPS-10, your writes would go to new disk blocks as opposed
>to superceding the existing ones (and defer the directory update to close
>time) which is certainly friendlier than the UNIX behavior.

Right, ENTER created a new file.

>Do you remember what broken and why?

Well, the biggest (but fixable) problem is that devices are files, and the
whole idea of creating a new one didn't make sense. So our first fix was to
exempt "special files" (devices) from using PDP-10 semantics. The other big
problem was programs that used files created with a-w protection as poor man's
locks; a second create would succeed instead of failing (because the first
file wasn't in the directory yet so its protection wasn't seen). There were
other problems that I don't remember with specific applications.

Mark Crispin

unread,
Jun 8, 2008, 3:34:33 PM6/8/08
to
On Sun, 8 Jun 2008, Brian Harvey posted:
> The other big
> problem was programs that used files created with a-w protection as poor man's
> locks; a second create would succeed instead of failing (because the first
> file wasn't in the directory yet so its protection wasn't seen).

Actually, you can't rely upon O_EXCL on ordinary UNIX due to NFS.

What you end up having to do is to create a file with a random name that
you are reasonably confident is unique to your process (e.g., encode your
process id as part of the name), make a hard link to the desired name,
ignore the return value from the link, and then check the link count of
your random name. If the link count is 2, you successfully acquired the
lock.

All of this is because of NFS' statelessness and non-atomicity. The part
about ignoring the return from the link is something that many novices
miss; the non-atomicity means that the return (whether success or failure)
can be a lie.

This is a piece of knowledge that I dearly wish that I could forget.

Johnny Billquist

unread,
Jun 8, 2008, 7:33:45 PM6/8/08
to
Mark Crispin skrev:

> On Sun, 8 Jun 2008, Brian Harvey posted:
>> The other big
>> problem was programs that used files created with a-w protection as
>> poor man's
>> locks; a second create would succeed instead of failing (because the
>> first
>> file wasn't in the directory yet so its protection wasn't seen).
>
> Actually, you can't rely upon O_EXCL on ordinary UNIX due to NFS.
>
> What you end up having to do is to create a file with a random name that
> you are reasonably confident is unique to your process (e.g., encode
> your process id as part of the name), make a hard link to the desired
> name, ignore the return value from the link, and then check the link
> count of your random name. If the link count is 2, you successfully
> acquired the lock.
>
> All of this is because of NFS' statelessness and non-atomicity. The
> part about ignoring the return from the link is something that many
> novices miss; the non-atomicity means that the return (whether success
> or failure) can be a lie.
>
> This is a piece of knowledge that I dearly wish that I could forget.

Hmm. Correct me if I'm wrong, but don't mkdir() actually guarantee atomicity
(even over NFS)? Which is why some programs create and delete directories as
ways of doing locks.

Johnny

--
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: b...@softjar.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol

0 new messages