bill@twwells.uucp (T. William Wells) (06/06/89)
I'm looking for information on how to prevent two unrelated processes from accessing an unspecified resource. The method should be independent of the kind of UNIX being used and should, ideally, work even when the processes are running on different machines attached to the same network. I only know of four methods that might work. 1) Opening a lock file with O_EXCL. 2) Using link, mknod, or mkdir to create the lock. (But aren't there some systems where mkdir isn't atomic?) 3) Creating a file with permissions 000 (but this won't necessarily work if one of the requestors' is root, right?) 4) Using a server process to handle either the requests or the access. I'd appreciate hard information about which methods are usable and the advantages and disadvantages of each. Please respond via e-mail and I will summarize. --- Bill { uunet | novavax } !twwells!bill
bill@twwells.com (T. William Wells) (06/14/89)
Well, I have a number of responses to my question. > 1) Opening a lock file with O_EXCL. Not present in V7, so not portable. > 2) Using link, mknod, or mkdir to create the lock. (But > aren't there some systems where mkdir isn't atomic?) Mknod is not always available to the unprivileged (V7 again), and mkdir isn't atomic on a number of systems. Link seems to be the favorite. Chris Torek says that link can misbehave when using NFS: if the link request gets handled correctly but the reply to the requester gets lost, NFS will retry the request. If the server has forgotten that it succeeded in doing the link, it will retry the link, fail because the link is already there, and return the failure. The effect is that the link is created but the program thinks that it has not. (Is NFS really that dumb? Stateless doesn't have to mean mindless!) I see a way that this can be dealt with. Suppose that you first create a file whose name is constructed from your system name and pid. In an ideal world, that would be unique. Then do the link. If the link fails, check the number of links to your file. If it is 2, you can ignore the link failure. Does anyone see anything wrong with this? (Other than the problem with the system name?) > 3) Creating a file with permissions 000 (but this won't > necessarily work if one of the requestors' is root, right?) As I said, this doesn't work with root. I suppose that one could do a setuid and *then* do this; that means forking off a subprocess if one wants to remain root. Any reason that won't work? (Never mind that it is wasteful. I know that.) (And also: I know that 000 isn't necessary. Anything that forbids writing would do.) > 4) Using a server process to handle either the requests or the access. No one had much good to say about this; the comments boiled down to: "how"? Here's one way: I create a file from my machine name and pid. I wait till it goes away. When it does, I proceed. When I'm done, I create another file with some fixed name, just to let the server know that I'm done. To have the server perform the request, I would put the request data into the file and not exit till that file is deleted. (To tie up the pid.) Of course, this involves busy loops in both the user process and the server; I don't recommend it. I just thought I'd point out that it is possible to use this method, even with vanilla Unix. The following people contributed to the above: Chris Torek uunet!mimsy!chris Gordon Burditt gould!sun!Central!sneaky!gordon John F. Haugh II uunet!cs.utexas.edu!rpp386.Cactus.ORG!jfh Arndt Jonasson, uunet!mcvax!zyx.ZYX.SE!arndt, suggested a variation on the link method: instead of linking a file, *unlink* it. The idea that the default state is that the lock file exists. When you want the resource, you *un*link the lock file. If that succeeds, you go. If not, you fail. This should also have the same problem as the link solution: you can get back a failure when the unlink actually succeeds. I can't think of a reliable method of detecting this, however. --- Bill { uunet | novavax | ankh | sunvice } !twwells!bill bill@twwells.com
eloranta@tukki.jyu.fi (Jussi Eloranta) (06/15/89)
How can I lock a tape frive for example intelligently? (bsd 4.2) Links are not usable int his case since all program won't check for that lock. The only thing that I figured out was just to chown + chmod the tape special files in /dev. But this surely contains some race conditions.. I also file locks (flock and lockf) since they are 'advisory' locks, besides the fork would be a problem... Does anyone know a bettert way to do this? Jussi -- ============================================================================ Jussi Eloranta Internet(/Bitnet): University of Jyvaskyla, eloranta@tukki.jyu.fi Finland [128.214.7.5]
deboor@buddy.Berkeley.EDU (Adam R de Boor) (06/21/89)
unlink isn't an atomic operation under NFS. You'd think it would be (you'd think file creation would be atomic too...), but it isn't. I've had cases where unlinks of the same file on two systems both succeeded, though *one* should have returned ENOENT. I eventually went with an election algorithm (slightly different problem -- the locking was to determine which server was to be the master...) a