bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [patch #332] POSIX record file locking


From: Michael Banck
Subject: Re: [patch #332] POSIX record file locking
Date: Fri, 20 Jan 2006 14:16:18 +0100

Hi Thomas,

On Thu, Jan 19, 2006 at 08:26:52PM -0800, Thomas Bushnell BSG wrote:
> I find tracking down URL's and opening attachments a pain, and enough
> of a pain that reviewing a patch is less likely to happen on my part
> when that's the only way it's in the message.  
>
> I have no objection to the use of savannah or other ways of describing
> a patch, but I would appreciate it if patches are emailed in such a
> way that the text of the diff appears as straightforward plaintext in
> the message.  (It's perfectly fine with me if a URL or attachment is
> there in addition, of course.)

You are totally right of course.  In fact, Marcus just asked yesterday
on IRC whether those notifications of Savannah really serve a purpose,
as the patch is not sent along inlined.

Actually, I did not consider the possibility that a notice might be sent
to bug-hurd when I uploaded the patch.

This patch is not new, it got submitted by Neal in early 2001.  However,
lately we seem to hit more and more places where the lack of proper
POSIX file locking is blocking us from getting packages compiled for
Debian, so I wanted to have a try at Neal's patch.  As the original
submission in Savannah was unusable (encoded HTML entities and against
an out of date tree), I decided to grab the original mail from the
bug-hurd mbox, rediff it and then put it on the patch tracker for later
use in e.g. the Debian package.

This is the orignial comment by Neal:

This patch adds support for POSIX file locking to the Hurd. As I do not
have a POSIX manual, this is a best effort at conformance. What does
that mean? As far as I can tell, the behavior, with the exceptions
listed below, matches that exhibited by GNU/Linux and the descriptions
which I have found in Stevens' ``Advanced Programming in the UNIX
Environment'' and Gay's ``Advanced Unix.''

* F_GETLK is only half implement. Currently, we have no way to determine
* the sender of a message (it is not sufficient to know the owner of a
* protid, as a process can fork), therefore, in the case where we need
* to return the pid, we fail returning EOPNOTSUPP. This should not be a
* road block in advertising to applications that we support POSIX file
* locking as the F_GETLK operation is rarely used. This is, however, an
* important problem as other facilities also require this support, e.g.
* System V IPC.

* According to POSIX, when a process forks, the child should not inherit
* any of the parent's locks. Currently, we merely add a reference to the
* send right associated with each file descriptor.
* libc/hurd/dtable.c:fork_child_dtable could get new protids, however,
* this implies that they no longer share the same file pointer. Thus,
* this re-emphasizes the importance of determining the sender of a
* message.

* When a file descriptor is closed, the locks associated with the protid
* need to be dropped. At the moment, we only dereference the send right
* (Cf. libc/hurd/fs-close.c:_hurd_fd_close and
* libc/hurd/hurd/port.h:_hurd_port_locked_set), i.e. the locks are
* dropped when all of the references to the protid are released.
* Consider:

fd1 = open ("foo", ...);
fd2 = dup (fd1);
fcntl (fd1, F_SETLKW, &lock);
close (fd2);
/* LOCK should now be dropped. */

Thus, _hurd_fd_close should free any locks.

* The definition of flock_t is sketchy. If we take a look at
* <hurd/hurd_types.defs>, we find:

type flock_t = struct[5] of int;

And looking at <bits/fcntl.h> shows:

struct flock
{
int l_type;
int l_whence;
#ifndef __USE_FILE_OFFSET64
__off_t l_start;
__off_t l_len;
#else
__off64_t l_start;
__off64_t l_len;
#endif
__pid_t l_pid;
};

Thus, when l_start and l_len are 64 bits, we overflow.

* We have no way to associate multiple opens of the same file. Consider:

fd1 = open ("foo", ...);
fd2 = open ("foo", ...);
fcntl (fd1, F_SETLKW, &lock);
close (fd2);
/* LOCK should now be dropped. */

I imagine this being extremely difficult to implement correctly.

* In libdiskfs, I have reimplemented file_lock and file_lock_stat using
* fcntl. This is a transparent change.

* A test suite is included in this patch and shows up in
* hurd/libfshelp-tests.

`race' locks a file, reads an integer, increments it, writes the result
to the file and then unlocks the file -- 10,000 times. It is intended
that multiple instances of this program be run at the same time. Race
takes three arguments: the file to use, the start of the lock and the
length. For obvious reasons, it is important that all instances of race
have locks that overlap.

For example:






# rm -f foo && ( ./race foo 2 0 & ./race foo 2 3 & \
> ./race foo 0 3 )
Was blocked 5482 times
Was blocked 5485 times
Was blocked 5479 times
# cat foo
30000

We see here that each process was blocked several thousand times and
that the result in the file foo is 30000. Perfect.

Locks is an interactive shell that has one ``file'' and ten open file
descriptors. Using some simple commands, one can test to see if locks
are established, cleared, and enforced. The principal command is `lock,'
which takes four parameters. The first is the file descriptor to lock,
the second is the start of the lock, the third is the length of the lock
(0 = until EOF) and the last is the type of lock to establish from the
set {0: F_UNLCK, 1: F_RDLCK, 2: F_WRLCK}. Help on the other commands can
be gotten using the `help' command.

A small run:
# ./locks
> lock 0 10 0 1
0: Start = 10; Length = 0; Type = F_RDLCK

Lock from byte 10 through the EOF.

> lock 0 20 0 0
0: Start = 10; Length = 10; Type = F_RDLCK

Unlock from byte 20 through the EOF.

> lock 0 11 8 2
0: Start = 10; Length = 1; Type = F_RDLCK
Start = 11; Length = 8; Type = F_WRLCK
Start = 19; Length = 1; Type = F_RDLCK

Upgrade bytes 11 through 19 to a write lock.

> lock 0 9 10 1
0: Start = 9; Length = 2; Type = F_RDLCK
Start = 11; Length = 8; Type = F_WRLCK
Start = 19; Length = 1; Type = F_RDLCK

Add a read lock to byte 9.

> lock 1 0 10 1
1: Start = 0; Length = 10; Type = F_RDLCK

Read lock the first ten bytes of the file through file descriptor 1.

> lock 1 10 0 1
Resource temporarily unavailable

Attempts to read lock the rest of the file. This, however, fails as
there are outstanding write locks held through file descriptor 1.

> lock 1 10 0 0
1: Start = 0; Length = 10; Type = F_RDLCK

What happens when file descriptor tries to unlock the blocked range?

> lock 1 10 0 2
Resource temporarily unavailable
Nothing.

A bunch of tests live in hurd/libfshelp-tests/locks-test. One can run
them through the test program using:
`./locks < locks-test 2>&1 | less'. If it core dumps or triggers an
assertion, that is a bug. Report it.


Here is the patch against current CVS (I used hurd-20010412 to verify
the interdiff with the original patch for omissions):

hurd/ChangeLog
2001-04-10  Neal H. Walfield  <neal@cs.uml.edu>

        * fs.defs: New rpc file_record_lock.
        * hurd_typed.defs: Import <fcntl.h>.

libdiskfs/ChangeLog
2001-04-11  Neal H. Walfield  <neal@cs.uml.edu>

        * Makefile (FSSRCS): Add file-record-lock.c.
        * diskfs.h (struct peropen): Change the type of lock_status
        from an int to a struct rlock_peropen.
        (struct node): Change the type of userbox from a struct lock_box
        to a struct rlock_box.
        * dir-lookup.c (diskfs_S_dir_lookup): Use fshelp_tweak_rlock
        as fshelp_acquire_lock is now depreciated.
        * file-lock-stat.c (diskfs_S_file_lock_stat): Total rewrite
        around the new record locking functions.
        * file-lock.c (diskfs_S_file_lock): Total rewrite around the
        new record locking functions.
        * file-record-lock.c: New file.  Implement
        diskfs_S_file_record_lock.
        * node-make.c (diskfs_make_node):  Initialize userbox with
        fshelp_rlock_init.
        * peropen-make.c (diskfs_make_peropen): Initialize lock_status
        using fshelp_rlock_po_init.
        * peropen-rele.c (diskfs_release_peropen): Release lock_status
        using fshelp_rlock_drop_peropen.
        
libfshelp/ChangeLog
2001-04-12  Neal H. Walfield  <neal@cs.uml.edu>

        * fshelp.h (struct rlock_box): New structure.
        (struct rlock_peropen): Likewise.
        (fshelp_rlock_init): New funtion.
        (fshelp_rlock_po_init): Likewise.
        (fshelp_rlock_drop_peropen): Likewise.
        (fshelp_rlock_tweak): Likewise.
        (fshelp_rlock_peropen_status): Likewise.
        (fshelp_rlock_node_status): Likewise.
        * rlock-drop-peropen.c: New file.  Implement
        fshelp_rlock_drop_peropen.
        * rlock-status.c: New file.  Implement
        fshelp_rlock_peropen_status and fshelp_rlock_node_status.
        * rlock-tweak.c: New file.  Implement fshelp_rlock_tweak.
        * rlock.h: New file.
        * extern-inline.c: New file.
        * Makefile (LCLHDRS): Add rlock.h.
        (SRCS): Add extern-inline.c, rlock-drop-peropen.c, rlock-tweak.c
        and rlock-status.c.

libfshelp-tests/ChangeLog
2001-04-11  Neal H. Walfield  <neal@cs.uml.edu>

        * ChangeLog: New file, mentioning itself in this sentence.
        * Makefile: New file.
        * README: Likewise.
        * fork.c: Likewise.
        * locks: Likewise.
        * locks-test: Likewise.
        * locks.c: Likewise.
        * race.c: Likewise.

libnetfs/ChangeLog
2001-04-11  Neal H. Walfield  <neal@cs.uml.edu>

        * file-record-lock.c: New file.  Implement
        netfs_S_file_record_lock.
        * Makefile (SRCS): Add file-record-lock.c

libtrivfs/ChangeLog
2001-04-11  Neal H. Walfield  <neal@cs.uml.edu>

        * file-record-lock.c: New file.  Implement
        trivfs_S_file_record_lock.
        * Makefile (SRCS): Add file-record-lock.c

diff -Naur hurd-20010412-snapshot/hurd/fs.defs hurd-20010412/hurd/fs.defs
--- hurd-20010412-snapshot/hurd/fs.defs 2002-06-13 21:51:40.000000000 +0200
+++ hurd-20010412/hurd/fs.defs  2006-01-19 12:04:53.000000000 +0100
@@ -352,3 +352,11 @@
        RPT
        parent: mach_port_t;
        out new_file: mach_port_send_t);
+
+/* Do fcntl type locking.  Cf.  <fcntl.h>.  */
+routine file_record_lock (
+       file: file_t;
+       RPT
+       cmd: int;
+       inout flock: flock_t);
+
diff -Naur hurd-20010412-snapshot/hurd/hurd_types.defs 
hurd-20010412/hurd/hurd_types.defs
--- hurd-20010412-snapshot/hurd/hurd_types.defs 2002-08-04 20:33:40.000000000 
+0200
+++ hurd-20010412/hurd/hurd_types.defs  2006-01-19 12:04:53.000000000 +0100
@@ -240,3 +240,5 @@
 import <sys/resource.h>;
 import <sys/utsname.h>;
 import <hurd/hurd_types.h>;
+import <fcntl.h>;
+
diff -Naur hurd-20010412-snapshot/libdiskfs/Makefile 
hurd-20010412/libdiskfs/Makefile
--- hurd-20010412-snapshot/libdiskfs/Makefile   2002-06-27 21:19:13.000000000 
+0200
+++ hurd-20010412/libdiskfs/Makefile    2006-01-19 12:10:49.000000000 +0100
@@ -26,7 +26,8 @@
        file-get-trans.c file-get-transcntl.c file-getcontrol.c \
        file-getfh.c file-getlinknode.c file-lock-stat.c \
        file-lock.c file-set-size.c file-set-trans.c file-statfs.c \
-       file-sync.c file-syncfs.c file-utimes.c file-reparent.c
+       file-sync.c file-syncfs.c file-utimes.c file-record-lock.c \
+       file-reparent.c
 IOSRCS= io-async-icky.c io-async.c io-duplicate.c io-get-conch.c io-revoke.c \
        io-map-cntl.c io-map.c io-modes-get.c io-modes-off.c \
        io-modes-on.c io-modes-set.c io-owner-mod.c io-owner-get.c \
diff -Naur hurd-20010412-snapshot/libdiskfs/dir-lookup.c 
hurd-20010412/libdiskfs/dir-lookup.c
--- hurd-20010412-snapshot/libdiskfs/dir-lookup.c       2002-05-14 
00:04:48.000000000 +0200
+++ hurd-20010412/libdiskfs/dir-lookup.c        2006-01-19 12:05:01.000000000 
+0100
@@ -468,12 +468,27 @@
 
   if (! error)
     {
+      struct flock lock =
+        {
+         l_start: 0,
+         l_len: 0,
+         l_whence: SEEK_SET
+       };
+
       if (flags & O_EXLOCK)
-       error = fshelp_acquire_lock (&np->userlock, &newpi->po->lock_status,
-                                    &np->lock, LOCK_EX);
+        {
+         lock.l_type = F_WRLCK;
+         error = fshelp_rlock_tweak (&np->userlock, &np->lock,
+                                     &newpi->po->lock_status, flags, 0, 0,
+                                     F_SETLK, &lock);
+       }
       else if (flags & O_SHLOCK)
-       error = fshelp_acquire_lock (&np->userlock, &newpi->po->lock_status,
-                                    &np->lock, LOCK_SH);
+        {
+         lock.l_type = F_RDLCK;
+         error = fshelp_rlock_tweak (&np->userlock, &np->lock,
+                                     &newpi->po->lock_status, flags, 0, 0,
+                                     F_SETLK, &lock);
+       }
       if (error)
        ports_port_deref (newpi); /* Get rid of NEWPI.  */
     }
diff -Naur hurd-20010412-snapshot/libdiskfs/diskfs.h 
hurd-20010412/libdiskfs/diskfs.h
--- hurd-20010412-snapshot/libdiskfs/diskfs.h   2002-06-27 21:19:13.000000000 
+0200
+++ hurd-20010412/libdiskfs/diskfs.h    2006-01-19 12:05:01.000000000 +0100
@@ -50,8 +50,8 @@
 /* One of these is created for each node opened by dir_lookup. */
 struct peropen
 {
-  int filepointer;
-  int lock_status;
+  off_t filepointer;
+  struct rlock_peropen lock_status;
   int refcnt;
   int openstat;
 
@@ -96,7 +96,7 @@
 
   struct transbox transbox;
 
-  struct lock_box userlock;
+  struct rlock_box userlock;
 
   struct conch conch;
 
diff -Naur hurd-20010412-snapshot/libdiskfs/file-lock-stat.c 
hurd-20010412/libdiskfs/file-lock-stat.c
--- hurd-20010412-snapshot/libdiskfs/file-lock-stat.c   1995-11-13 
22:51:06.000000000 +0100
+++ hurd-20010412/libdiskfs/file-lock-stat.c    2006-01-19 12:05:01.000000000 
+0100
@@ -1,38 +1,43 @@
-/*
-   Copyright (C) 1994, 1995 Free Software Foundation
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful, 
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-/* Written by Michael I. Bushnell.  */
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+ 
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 #include "priv.h"
 #include "fs_S.h"
 
+#include <fcntl.h>
+#include <sys/file.h>
+
 kern_return_t
 diskfs_S_file_lock_stat (struct protid *cred,
                         int *mystatus,
                         int *otherstatus)
 {
+  struct node *node;
+
   if (!cred)
     return EOPNOTSUPP;
-  
-  mutex_lock (&cred->po->np->lock);
-  *mystatus = cred->po->lock_status;
-  *otherstatus = cred->po->np->userlock.type;
-  mutex_unlock (&cred->po->np->lock);
+
+  node = cred->po->np;
+
+  mutex_lock (&node->lock);
+  *mystatus = fshelp_rlock_peropen_status (&cred->po->lock_status);
+  *otherstatus = fshelp_rlock_node_status (&node->userlock);
+  mutex_unlock (&node->lock);
+
   return 0;
 }
diff -Naur hurd-20010412-snapshot/libdiskfs/file-lock.c 
hurd-20010412/libdiskfs/file-lock.c
--- hurd-20010412-snapshot/libdiskfs/file-lock.c        1994-05-05 
15:14:29.000000000 +0200
+++ hurd-20010412/libdiskfs/file-lock.c 2006-01-19 12:05:01.000000000 +0100
@@ -1,38 +1,56 @@
-/*
-   Copyright (C) 1993, 1994 Free Software Foundation
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful, 
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-/* Written by Michael I. Bushnell.  */
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+ 
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 #include "priv.h"
 #include "fs_S.h"
 
+#include <fcntl.h>
+#include <sys/file.h>
+
 kern_return_t
 diskfs_S_file_lock (struct protid *cred, int flags)
 {
   error_t err;
-  if (!cred)
+  struct flock lock;
+  struct node *node;
+
+  if (! cred)
     return EOPNOTSUPP;
-  mutex_lock (&cred->po->np->lock);
-  err = fshelp_acquire_lock (&cred->po->np->userlock, &cred->po->lock_status,
-                            &cred->po->np->lock, flags);
-  mutex_unlock (&cred->po->np->lock);
+
+  lock.l_start = 0;
+  lock.l_whence = SEEK_SET;
+  lock.l_len = 0;
+
+  if (flags & LOCK_UN)
+    lock.l_type = F_UNLCK;
+  else if (flags & LOCK_SH)
+    lock.l_type = F_RDLCK;
+  else if (flags & LOCK_EX)
+    lock.l_type = F_WRLCK;
+  else
+    return EINVAL;
+
+  node = cred->po->np;
+  mutex_lock (&node->lock);
+  err = fshelp_rlock_tweak (&node->userlock, &node->lock,
+                           &cred->po->lock_status, cred->po->openstat,
+                           0, 0, flags & LOCK_NB ? F_SETLK : F_SETLKW,
+                           &lock);
+  mutex_unlock (&node->lock);
   return err;
 }
-
-    
diff -Naur hurd-20010412-snapshot/libdiskfs/file-record-lock.c 
hurd-20010412/libdiskfs/file-record-lock.c
--- hurd-20010412-snapshot/libdiskfs/file-record-lock.c 1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libdiskfs/file-record-lock.c  2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,43 @@
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+ 
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "priv.h"
+#include "diskfs.h"
+
+#include <errno.h>
+#include <hurd/fshelp.h>
+
+error_t
+diskfs_S_file_record_lock (struct protid *cred, int cmd, struct flock *lock)
+{
+  struct node *node;
+  error_t err;
+
+  if (! cred)
+    return EOPNOTSUPP;
+
+  node = cred->po->np;
+
+  mutex_lock (&node->lock);
+  err = fshelp_rlock_tweak (&node->userlock, &node->lock,
+                           &cred->po->lock_status, cred->po->openstat,
+                           node->dn_stat.st_size, cred->po->filepointer,
+                           cmd, lock);
+  mutex_unlock (&node->lock);
+  return err;
+}
diff -Naur hurd-20010412-snapshot/libdiskfs/node-make.c 
hurd-20010412/libdiskfs/node-make.c
--- hurd-20010412-snapshot/libdiskfs/node-make.c        2002-06-27 
21:19:13.000000000 +0200
+++ hurd-20010412/libdiskfs/node-make.c 2006-01-19 12:11:51.000000000 +0100
@@ -48,7 +48,7 @@
 
   fshelp_transbox_init (&np->transbox, &np->lock, np);
   iohelp_initialize_conch (&np->conch, &np->lock);
-  fshelp_lock_init (&np->userlock);
+  fshelp_rlock_init (&np->userlock);
 
   return np;
 }
diff -Naur hurd-20010412-snapshot/libdiskfs/peropen-make.c 
hurd-20010412/libdiskfs/peropen-make.c
--- hurd-20010412-snapshot/libdiskfs/peropen-make.c     2002-03-26 
15:59:52.000000000 +0100
+++ hurd-20010412/libdiskfs/peropen-make.c      2006-01-19 12:22:15.000000000 
+0100
@@ -16,7 +16,10 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 #include "priv.h"
+#include <errno.h>
+#include <stdlib.h>
 #include <sys/file.h>
+#include <hurd/fshelp.h>
 
 /* Create and return a new peropen structure on node NP with open
    flags FLAGS.  */
@@ -24,13 +27,16 @@
 diskfs_make_peropen (struct node *np, int flags, struct peropen *context,
                     struct peropen **ppo)
 {
+  error_t err;
   struct peropen *po = *ppo = malloc (sizeof (struct peropen));
-
   if (! po)
     return ENOMEM;
 
+  err = fshelp_rlock_po_init (&po->lock_status);
+  if (err)
+    return NULL;
+
   po->filepointer = 0;
-  po->lock_status = LOCK_UN;
   po->refcnt = 0;
   po->openstat = flags;
   po->np = np;
diff -Naur hurd-20010412-snapshot/libdiskfs/peropen-rele.c 
hurd-20010412/libdiskfs/peropen-rele.c
--- hurd-20010412-snapshot/libdiskfs/peropen-rele.c     1998-04-13 
21:36:24.000000000 +0200
+++ hurd-20010412/libdiskfs/peropen-rele.c      2006-01-19 12:05:01.000000000 
+0100
@@ -39,9 +39,7 @@
   if (po->shadow_root_parent)
     mach_port_deallocate (mach_task_self (), po->shadow_root_parent);
 
-  if (po->lock_status != LOCK_UN)
-    fshelp_acquire_lock (&po->np->userlock, &po->lock_status,
-                        &po->np->lock, LOCK_UN);
+  fshelp_rlock_drop_peropen (&po->lock_status);
 
   diskfs_nput (po->np);
 
diff -Naur hurd-20010412-snapshot/libfshelp/Makefile 
hurd-20010412/libfshelp/Makefile
--- hurd-20010412-snapshot/libfshelp/Makefile   2001-07-03 03:10:17.000000000 
+0200
+++ hurd-20010412/libfshelp/Makefile    2006-01-19 12:23:53.000000000 +0100
@@ -29,8 +29,11 @@
        get-identity.c \
        perms-isowner.c perms-iscontroller.c perms-access.c \
        perms-checkdirmod.c \
-       touch.c
-LCLHDRS = fshelp.h locks.h trans.h
+       touch.c \
+       extern-inline.c \
+       rlock-drop-peropen.c rlock-tweak.c rlock-status.c
+
+LCLHDRS = fshelp.h locks.h trans.h rlock.h
 installhdrs = fshelp.h
 
 HURDLIBS=shouldbeinlibc threads
diff -Naur hurd-20010412-snapshot/libfshelp/extern-inline.c 
hurd-20010412/libfshelp/extern-inline.c
--- hurd-20010412-snapshot/libfshelp/extern-inline.c    1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp/extern-inline.c     2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,25 @@
+/*
+   Copyright (C) 2001 Free Software Foundation
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, 
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define FSHELP_EXTERN_INLINE
+
+#include "fshelp.h"
+
diff -Naur hurd-20010412-snapshot/libfshelp/fshelp.h 
hurd-20010412/libfshelp/fshelp.h
--- hurd-20010412-snapshot/libfshelp/fshelp.h   2002-06-11 23:38:48.000000000 
+0200
+++ hurd-20010412/libfshelp/fshelp.h    2006-01-19 12:05:01.000000000 +0100
@@ -18,18 +18,24 @@
 #ifndef _HURD_FSHELP_
 #define _HURD_FSHELP_
 
+#ifndef FSHELP_EXTERN_INLINE
+#define FSHELP_EXTERN_INLINE extern inline
+#endif
+
 /* This library implements various things that are generic to
    all or most implementors of the filesystem protocol.  It
    presumes that you are using the iohelp library as well.  It
    is divided into separate facilities which may be used independently.  */
 
 #include <errno.h>
+#include <stdlib.h>
 #include <mach.h>
 #include <hurd/hurd_types.h>
 #include <cthreads.h>
 #include <hurd/iohelp.h>
 #include <sys/stat.h>
 #include <maptime.h>
+#include <fcntl.h>
 
 
 /* Passive translator linkage */
@@ -168,19 +174,81 @@
   int shcount;
 };
 
-/* Call when a user makes a request to acquire an lock via file_lock.
+/* Initialize lock_box BOX.  (The user int passed to fshelp_acquire_lock
+   should be initialized with LOCK_UN.).  */
+void fshelp_lock_init (struct lock_box *box);
+
+/* Call when a user makes a request to acquire a lock via file_lock.
    There should be one lock box per object and one int per open; these
    are passed as arguments BOX and USER respectively.  FLAGS are as
    per file_lock.  MUT is a mutex which will be held whenever this
    routine is called, to lock BOX->wait.  */
 error_t fshelp_acquire_lock (struct lock_box *box, int *user,
                             struct mutex *mut, int flags);
+
+/* Record locking.  */
+
+/* Unique to a node; initialize with fshelp_rlock_init.  */
+struct rlock_box
+{
+  struct rlock_list *locks;    /* List of locks on the file.  */
+};
 
+/* Initialize the rlock_box BOX.  */
+FSHELP_EXTERN_INLINE
+error_t fshelp_rlock_init (struct rlock_box *box)
+{
+  box->locks = NULL;
+  return 0;
+}
 
-/* Initialize lock_box BOX.  (The user int passed to fshelp_acquire_lock
-   should be initialized with LOCK_UN.).  */
-void fshelp_lock_init (struct lock_box *box);
+/* Unique to a peropen.  */
+struct rlock_peropen
+{
+  /* This is a pointer to a pointer to a rlock_lock (and not a pointer
+     to a rlock_list) as it really serves two functions:
+       o the list of locks owned by this peropen
+       o the unique peropen identifier that all locks on this peropen share.  
*/
+  struct rlock_list **locks;
+};
+
+FSHELP_EXTERN_INLINE
+error_t fshelp_rlock_po_init (struct rlock_peropen *po)
+{
+  po->locks = malloc (sizeof (struct rlock_list *));
+  if (! po->locks)
+    return ENOMEM;
+
+  *po->locks = NULL;
+  return 0;
+}
+
+/* Release all of the locks held by a given peropen.  */
+error_t fshelp_rlock_drop_peropen (struct rlock_peropen *po);
+
+/* Call when a user makes a request to tweak a lock as via fcntl.  There
+   should be one rlock box per object.  BOX is the rlock box associated
+   with the object.  MUT is a mutex which should be held whenever this
+   routine is called; it should be unique on a pernode basis.  PO is the
+   peropen identifier.  OPEN_MODE is how the file was opened (from the O_*
+   set).  SIZE is the size of the object in question.  CURPOINTER is the
+   current position of the file pointer.  CMD is from the set F_GETLK,
+   F_SETLK, F_SETLKW.  LOCK is passed by the user and is as defined by
+   <fcntl.h>.  */
+error_t fshelp_rlock_tweak (struct rlock_box *box, struct mutex *mutex,
+                           struct rlock_peropen *po, int open_mode,
+                           off_t size, off_t curpointer, int cmd,
+                           struct flock *lock);
+
+/* These functions allow for easy emulation of file_lock and
+   file_lock_stat.  */
+
+/* Returns the type (from the set LOCK_UN, LOCK_SH, LOCK_EX) of the most
+   restictive lock held by the PEROPEN.  */
+int fshelp_rlock_peropen_status (struct rlock_peropen *po);
 
+/* Like fshelp_rlock_peropen_status except for all users of BOX.  */
+int fshelp_rlock_node_status (struct rlock_box *box);
 
 
 struct port_bucket;            /* shut up C compiler */
diff -Naur hurd-20010412-snapshot/libfshelp/rlock-drop-peropen.c 
hurd-20010412/libfshelp/rlock-drop-peropen.c
--- hurd-20010412-snapshot/libfshelp/rlock-drop-peropen.c       1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp/rlock-drop-peropen.c        2006-01-19 
12:05:01.000000000 +0100
@@ -0,0 +1,51 @@
+/*
+   Copyright (C) 2001 Free Software Foundation
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, 
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "fshelp.h"
+#include "rlock.h"
+
+#include <stdlib.h>
+#include <cthreads.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+error_t
+fshelp_rlock_drop_peropen (struct rlock_peropen *po)
+{
+  struct rlock_list *l;
+  struct rlock_list *t;
+
+  for (l = *po->locks; l; l = t)
+    {
+      if (l->waiting)
+       {
+         l->waiting = 0;
+         condition_broadcast (&l->wait);
+       }
+
+      list_unlink (node, l);
+
+      t = l->po.next;
+      free (l);
+    }
+
+  return 0;
+}
diff -Naur hurd-20010412-snapshot/libfshelp/rlock-status.c 
hurd-20010412/libfshelp/rlock-status.c
--- hurd-20010412-snapshot/libfshelp/rlock-status.c     1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp/rlock-status.c      2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,52 @@
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fshelp.h"
+#include "rlock.h"
+#include <fcntl.h>
+#include <sys/file.h>
+
+int fshelp_rlock_peropen_status (struct rlock_peropen *po)
+{
+  struct rlock_list *l;
+
+  if (! *po->locks)
+    return LOCK_UN;
+
+  for (l = *po->locks; l; l = l->po.next)
+    if (l->type == F_WRLCK)
+      return LOCK_EX;
+
+  return LOCK_SH;
+}
+
+/* Like fshelp_rlock_peropen_status except for all users of NODE.  */
+int fshelp_rlock_node_status (struct rlock_box *box)
+{
+  struct rlock_list *l;
+
+  if (! box->locks)
+    return LOCK_UN;
+
+  for (l = box->locks; l; l = l->node.next)
+    if (l->type == F_WRLCK)
+      return LOCK_EX;
+
+  return LOCK_SH;
+}
+
diff -Naur hurd-20010412-snapshot/libfshelp/rlock-tweak.c 
hurd-20010412/libfshelp/rlock-tweak.c
--- hurd-20010412-snapshot/libfshelp/rlock-tweak.c      1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp/rlock-tweak.c       2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,552 @@
+/*
+   Copyright (C) 2001 Free Software Foundation
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, 
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "fshelp.h"
+#include "rlock.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <cthreads.h>
+
+static inline int overlap (off_t start, off_t len, struct rlock_list *l)
+{
+  return ((len == 0 && l->len == 0)
+         || (len == 0 && l->start + l->len > start)
+         || (l->len == 0 && start + len > l->start)
+         || (l->start + l->len > start && start + len > l->start));
+}
+
+error_t
+fshelp_rlock_tweak (struct rlock_box *box, struct mutex *mutex,
+                   struct rlock_peropen *po, int open_mode,
+                   off_t obj_size, off_t cur_pointer, int cmd,
+                   struct flock *lock)
+{
+  inline struct rlock_list *
+  gen_lock (off_t start, off_t len, int type)
+    {
+      struct rlock_list *l = malloc (sizeof (struct rlock_list));
+      if (! l)
+        return NULL;
+
+      rlock_list_init (po, l);
+      l->start = start;
+      l->len = len;
+      l->type = type;
+
+      list_link (po, po->locks, l);
+      list_link (node, &box->locks, l);
+      return l;
+    }
+
+  inline void
+  rele_lock (struct rlock_list *l, int wake_waiters)
+    {
+      list_unlink (po, l);
+      list_unlink (node, l);
+
+      if (wake_waiters && l->waiting)
+       condition_broadcast (&l->wait);
+
+      free (l);
+    }
+
+  error_t
+  unlock_region (off_t start, off_t len)
+    {
+      struct rlock_list *l;
+
+      for (l = *po->locks; l; l = l->po.next)
+       {
+         if (l->len != 0 && l->start + l->len <= start)
+           /* We start after the locked region ends.  */
+           {
+             continue;
+           }
+         else if (len != 0 && start + len <= l->start)
+           /* We end before this region starts.  Since we are sorted,
+              we are done.  */
+           {
+             return 0;
+           }
+         else if (start <= l->start
+                  && (len == 0
+                      || (l->len != 0
+                          && l->start + l->len <= start + len)))
+           /* We wrap the locked region; consume it.  */
+           {
+             rele_lock (l, 1);
+             continue;
+           }
+         else if (start <= l->start
+                  && (l->len == 0
+                      || (l->start < start + len)))
+           /* The locked region is having its head unlocked.  */
+           {
+             assert (len != 0);
+             assert (l->len == 0 || start + len < l->start + l->len);
+
+             if (l->len != 0)
+               l->len -= start + len - l->start;
+             l->start = start + len;
+
+             if (l->waiting)
+               {
+                 l->waiting = 0;
+                 condition_broadcast (&l->wait);
+               }
+           }
+         else if (l->start < start
+                  && ((start < l->start + l->len
+                       && (len == 0 || l->start + l->len <= start + len))
+                      || (len == 0 && l->len == 0)))
+           /* The locked region needs its tail unlocked.  */
+           {
+             assert (len == 0
+                     || (l->len != 0 && l->start + l->len <= start + len));
+
+             l->len = start - l->start;
+
+             if (l->waiting)
+               {
+                 l->waiting = 0;
+                 condition_broadcast (&l->wait);
+               }
+
+             continue;
+           }
+         else if (l->start < start
+                  && (l->len == 0
+                      || (len != 0
+                          && start + len < l->start + l->len)))
+           /* The locked region wraps us (absolutely); crave out the
+              middle.  */
+           {
+             struct rlock_list *upper_half;
+
+             assert (len != 0);
+             
+             upper_half = gen_lock (start + len,
+                                    l->len 
+                                      ? l->start + l->len - (start + len)
+                                      : 0,
+                                    l->type);
+             if (! upper_half)
+               return ENOMEM;
+
+             l->len = start - l->start;
+
+             return 0;
+           }
+         else if (start < l->start
+                  && len != 0
+                  && start + len <= l->start)
+           /* The locked region starts after our end.  */
+           {
+             return 0;
+           }
+         else
+           assert (! "Impossible!");
+       }
+
+      return 0;
+    }
+
+  inline struct rlock_list *
+  find_conflict (off_t start, off_t len, int type)
+    {
+      struct rlock_list *l;
+
+      for (l = box->locks; l; l = l->node.next)
+       {
+         if (po->locks == l->po_id)
+           continue;
+
+         if ((l->type == F_WRLCK || type == F_WRLCK)
+             && overlap (start, len, l))
+           return l;
+       }
+
+      return NULL;
+    }
+
+  inline error_t
+  merge_in (off_t start, off_t len, int type)
+    {
+      struct rlock_list *l;
+
+      for (l = *po->locks; l; l = l->po.next)
+       {
+         if (l->start <= start
+             && (l->len == 0
+                 || (len != 0
+                     && start + len <= l->start + l->len)))
+           /* Our start and end fall between the locked region
+              (i.e. we are wrapped).  */
+           {
+             struct rlock_list *head = NULL;
+             struct rlock_list *tail = NULL;
+
+             if (type == l->type || type == F_RDLCK)
+               return 0;
+
+             assert (type == F_WRLCK && l->type == F_RDLCK);
+
+             if (l->start < start)
+               /* We need to split the head off.  */
+               {
+                 head = gen_lock (l->start, start - l->start, F_RDLCK);
+                 if (! head)
+                   return ENOMEM;
+               }
+
+             if ((l->len == 0 && len != 0)
+                 || start + len < l->start + l->len)
+               /* We need to split the tail off.  */
+               {
+                 tail = gen_lock (start + len,
+                                  l->len
+                                    ? l->start + l->len - (start + len)
+                                    : 0,
+                                  F_RDLCK);
+                 if (! tail)
+                   {
+                     if (head)
+                       rele_lock (head, 0);
+                     return ENOMEM;
+                   }
+               }
+
+             if (head)
+               {
+                 off_t shift = start - l->start;
+
+                 if (l->len != 0)
+                   l->len -= shift;
+                 l->start += shift;
+               }
+
+             if (tail)
+               l->len = tail->start - l->start;
+
+             if (! tail)
+               /* There is a chance we can merge some more.  */
+               {
+                 start = l->start;
+                 len = l->len;
+
+                 rele_lock (l, 1);
+                 continue;
+               }
+             else
+               {
+                 l->type = F_WRLCK;
+                 return 0;
+               }
+           }
+         else if (start <= l->start
+                  && (len == 0
+                      || (l->len != 0
+                          && l->start + l->len <= start + len)))
+           /* We fully wrap the locked region.  */
+           {
+             struct rlock_list *head;
+
+             if (type == l->type || type == F_WRLCK)
+               {
+                 rele_lock (l, 1);
+                 /* Try to merge more.  */
+                 continue;
+               }
+
+             assert (type == F_RDLCK && l->type == F_WRLCK);
+
+             if (start < l->start)
+               /* Generate our head.  */
+               {
+                 head = gen_lock (start, l->start - start, F_RDLCK);
+                 if (! head)
+                   return ENOMEM;
+               }
+             else
+               head = NULL;
+
+             if (l->len != 0
+                 && (len == 0 || l->start + l->len < start + len))
+               /* We have a tail, try to merge it also.  */
+               {
+                 if (len != 0)
+                   len = start + len - (l->start + l->len);
+                 start = l->start + l->len;
+
+                 continue;
+               }
+             else
+               /* Our end is silently consumed.  */
+               {
+                 /* If we do not have a tail, we must have had a head
+                    (if not, the first case would have caught us).  */
+                 assert (head);
+                 return 0;
+               }
+           }
+         else if (l->start < start
+                  && (len == 0
+                      || (start <= l->start + l->len
+                          && start + len > l->start + l->len)))
+           /* Our start falls within the locked region or exactly one
+              byte after it and our end falls beyond it.  We know that
+              we cannot consume the entire region.  */
+           {
+             assert (l->len != 0);
+
+             if (type == l->type)
+               /* Merge the two areas.  */
+               {
+                 if (len != 0)
+                   len += start - l->start;
+                 start = l->start;
+
+                 rele_lock (l, 1);
+
+                 /* Try to merge in more.  */
+                 continue;
+               }
+             else if (start == l->start + l->len)
+                 /* We fall just after the locked region (there is no
+                    intersection) and we are not the same type.  */
+               {
+                 /* The is nothing to do except continue the search.  */
+                 continue;
+               }
+             else if (type == F_WRLCK)
+               /* We comsume the intersection.  */
+               {
+                 assert (l->type == F_RDLCK);
+
+                 l->len -= l->start + l->len - start;
+
+                 /* Don't create the lock now; we might be able to
+                    consume more locks.  */
+                 continue;
+               }
+             else
+               /* We are dominated; the locked region comsumes the
+                  intersection.  */
+               {
+                 off_t common = l->start + l->len - start;
+
+                 assert (type == F_RDLCK);
+                 assert (l->type == F_WRLCK);
+
+                 start += common;
+                 if (len != 0)
+                   len -= common;
+
+                 /* There is still a chance that we can consume more
+                    locks.  */
+                 continue;
+               }
+           }
+         else if (start < l->start
+                  && (l->len == 0
+                      || l->start <= start + len))
+           /* Our start falls before the locked region and our
+              end falls (inclusively) between it or one byte before it.
+              Note, we know that we do not consume the entire locked
+              area.  */
+           {
+             assert (len != 0);
+             assert (l->len == 0 || start + len < l->start + l->len);
+
+             if (type == l->type)
+               /* Merge the two areas.  */
+               {
+                 if (l->len)
+                   l->len += l->start - start;
+                 l->start = start;
+                 return 0;
+               }
+             else if (l->start == start + len)
+               /* Our end falls just before the start of the locked
+                  region, however, we are not the same type.  Just
+                  insert it.  */
+               {
+                 continue;
+               }
+             else if (type == F_WRLCK)
+               /* We consume the intersection.  */
+               {
+                 struct rlock_list *e;
+                 off_t common = start + len - l->start;
+
+                 assert (l->type == F_RDLCK);
+
+                 e = gen_lock (start, len, F_WRLCK);
+                 if (! e)
+                   return ENOMEM;
+
+                 if (l->len)
+                   l->len -= common;
+                 l->start += common;
+
+                 return 0;
+               }
+             else
+               /* The locked region comsumes the intersection.  */
+               {
+                 struct rlock_list *e;
+
+                 assert (l->type == F_WRLCK);
+                 assert (type == F_RDLCK);
+
+                 e = gen_lock (start, l->start - start, F_RDLCK);
+                 if (! e)
+                   return ENOMEM;
+
+                 return 0;
+               }
+           }
+         else if (start < l->start
+                  && len != 0
+                  && start + len <= l->start)
+           /* We start and end before this locked region.  Therefore,
+              knowing that the list is sorted, the merge is done.  */
+           {
+             break;
+           }
+         else
+           /* We start beyond the end of this locked region.  */
+           {
+             assert (start >= l->start + l->len);
+             assert (l->len != 0);
+             continue;
+           }
+       }
+
+      return (gen_lock (start, len, type) ? 0 : ENOMEM);
+    }
+
+  struct rlock_list *e;
+  off_t start;
+  off_t len;
+
+  if (cmd != F_GETLK
+      && cmd != F_SETLK
+      && cmd != F_SETLKW)
+    return EOPNOTSUPP;
+
+  if (lock->l_type != F_UNLCK
+      && lock->l_type != F_RDLCK
+      && lock->l_type != F_WRLCK)
+    return EINVAL;
+
+  if (lock->l_type == F_UNLCK)
+    {
+      if (cmd == F_SETLKW)
+        /* If we are unlocking a region, map F_SETLKW to F_SETLK.  */
+        cmd = F_SETLK;
+      else if (cmd == F_GETLK)
+       /* Impossible!  */
+       return EINVAL;
+    }
+
+  if (lock->l_type == F_RDLCK && !(open_mode & O_READ))
+    return EACCES;
+  if (lock->l_type == F_WRLCK && !(open_mode & O_WRITE))
+    return EACCES;
+
+  switch (lock->l_whence)
+    {
+    case SEEK_SET: 
+      start = lock->l_start;
+      break;
+
+    case SEEK_CUR:
+      start = cur_pointer + lock->l_start;
+      break;
+
+    case SEEK_END:
+      start = obj_size + lock->l_start;
+      break;
+
+    default:
+      return EINVAL;
+    }
+
+  if (start < 0)
+    return EINVAL;
+
+  len = lock->l_len;
+  if (len < 0)
+    return EINVAL;
+
+  if (cmd == F_SETLK && lock->l_type == F_UNLCK)
+    return unlock_region (start, len);
+
+retry:
+  e = find_conflict (start, len, lock->l_type);
+
+  if (cmd == F_GETLK)
+    {
+      if (e)
+       {
+#if 0
+         lock->l_type = e->l_type;
+         lock->l_start = e->start;
+         lock->l_whence = SEEK_SET;
+         lock->l_len = e->len;
+         lock->l_pid = -1;  /* XXX: This is so wrong it makes me puke.  */
+         return 0;
+#else
+         return EOPNOTSUPP;
+#endif
+       }
+      else
+       {
+         lock->l_type = F_UNLCK;
+         return 0;
+       }
+    }
+  else
+    {
+      assert (cmd == F_SETLK || cmd == F_SETLKW);
+
+      if (! e)
+       return merge_in (start, len, lock->l_type);
+      else
+        {
+         if (cmd == F_SETLKW)
+           {
+             e->waiting = 1;
+             if (hurd_condition_wait (&e->wait, mutex))
+               return EINTR;
+             goto retry;
+           }
+         else
+           return EAGAIN;
+       }
+    }
+}
diff -Naur hurd-20010412-snapshot/libfshelp/rlock.h 
hurd-20010412/libfshelp/rlock.h
--- hurd-20010412-snapshot/libfshelp/rlock.h    1970-01-01 01:00:00.000000000 
+0100
+++ hurd-20010412/libfshelp/rlock.h     2006-01-19 12:05:01.000000000 +0100
@@ -0,0 +1,88 @@
+/*
+   Copyright (C) 2001 Free Software Foundation
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, 
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef FSHELP_RLOCK_H
+#define FSHELP_RLOCK_H
+
+#include <cthreads.h>
+#include <string.h>
+
+struct rlock_linked_list
+{
+  struct rlock_list *next;
+  struct rlock_list **prevp;
+};
+
+struct rlock_list
+{
+  off_t start;
+  off_t len;
+  int type;
+
+  struct rlock_linked_list node;
+  struct rlock_linked_list po;
+
+  struct condition wait;
+  int waiting;
+
+  void *po_id;
+};
+
+extern inline error_t
+rlock_list_init (struct rlock_peropen *po, struct rlock_list *l)
+{
+  memset (l, 0, sizeof (struct rlock_list));
+  condition_init (&l->wait);
+  l->po_id = po->locks;
+  return 0;
+}
+
+/* void list_list (X ={po,node}, struct rlock_list **head,
+                  struct rlock_list *node)
+ 
+   Insert a node in the given list, X, in sorted order.  */
+#define list_link(X, head, node)                               \
+       do                                                      \
+         {                                                     \
+           struct rlock_list **e;                              \
+           for (e = head;                                      \
+                *e && ((*e)->start < node->start);             \
+                e = &(*e)->X.next)                             \
+             ;                                                 \
+           node->X.next = *e;                                  \
+           if (node->X.next)                                   \
+             node->X.next->X.prevp = &node->X.next;            \
+           node->X.prevp = e;                                  \
+           *e = node;                                          \
+         }                                                     \
+       while (0)
+
+/* void list_unlock (X = {po,node}, struct rlock_list *node)  */
+#define list_unlink(X, node)                                   \
+       do                                                      \
+         {                                                     \
+           *node->X.prevp = node->X.next;                      \
+           if (node->X.next)                                   \
+             node->X.next->X.prevp = node->X.prevp;            \
+         }                                                     \
+       while (0)
+
+#endif /* FSHELP_RLOCK_H */
diff -Naur hurd-20010412-snapshot/libfshelp-tests/Makefile 
hurd-20010412/libfshelp-tests/Makefile
--- hurd-20010412-snapshot/libfshelp-tests/Makefile     1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp-tests/Makefile      2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,36 @@
+# Makefile libfshelp test cases
+#
+#   Copyright (C) 2001 Free Software Foundation, Inc.
+#
+#   This program is free software; you can redistribute it and/or
+#   modify it under the terms of the GNU General Public License as
+#   published by the Free Software Foundation; either version 2, or (at
+#   your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := libfshelp-tests
+makemode := utilities
+
+targets = race locks fork
+SRCS = race.c locks.c fork.c
+
+MIGSTUBS = fsUser.o ioUser.o
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+HURDLIBS =
+
+include ../Makeconf
+
+race: race.o fsUser.o ioUser.o
+fork: fork.o fsUser.o
+locks: locks.o
+
+race locks: ../libfshelp/libfshelp.a ../libports/libports.a \
+           ../libthreads/libthreads.a
diff -Naur hurd-20010412-snapshot/libfshelp-tests/README 
hurd-20010412/libfshelp-tests/README
--- hurd-20010412-snapshot/libfshelp-tests/README       1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp-tests/README        2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,102 @@
+These programs are used to help test the algorithms in the libfshelp
+library.
+
+Record Locking
+==============
+
+Race
+----
+
+Race locks a file, reads an integer, increments it, writes the result to
+the file and then unlocks the file -- 10,000 times.  It is intended that
+multiple instances of this program be run at the same time.  Race takes
+three arguments:  the file to use, the start of the lock and the length.
+For obvious reasons, it is important that all instances of race have
+locks that overlap.  For example:
+
+       # rm -f foo && ( ./race foo 2 0 & ./race foo 2 3 & \
+       > ./race foo 0 3 )
+       Was blocked 5482 times
+       Was blocked 5485 times
+       Was blocked 5479 times
+       # cat foo
+       30000
+
+We see here that each process was blocked several thousand times and that
+the result in the file foo is 30000.  Perfect.
+
+Locks
+-----
+
+Locks is an interactive shell that has one ``file'' and ten open file
+descriptors.  Using some simple commands, one can test to see if locks
+are established, cleared, and enforced.  The principal command is
+`lock,' which takes four parameters.  The first is the file descriptor
+to lock, the second is the start of the lock, the third is the length of
+the lock (0 = until EOF) and the last is the type of lock to establish
+from the set {0: F_UNLCK, 1: F_RDLCK, 2: F_WRLCK}.  Help on the other
+commands can be gotten using the `help' command.
+
+A small run:
+
+       # ./locks
+       > lock 0 10 0 1
+         0:    Start =   10; Length =    0; Type = F_RDLCK
+
+Lock from byte 10 through the EOF.
+
+       > lock 0 20 0 0
+         0:    Start =   10; Length =   10; Type = F_RDLCK
+
+Unlock from byte 20 through the EOF.
+
+       > lock 0 11 8 2
+         0:    Start =   10; Length =    1; Type = F_RDLCK
+               Start =   11; Length =    8; Type = F_WRLCK
+               Start =   19; Length =    1; Type = F_RDLCK
+
+Upgrade bytes 11 through 19 to a write lock.
+
+       > lock 0 9 10 1
+         0:    Start =    9; Length =    2; Type = F_RDLCK
+               Start =   11; Length =    8; Type = F_WRLCK
+               Start =   19; Length =    1; Type = F_RDLCK
+
+Add a read lock to byte 9.
+
+       > lock 1 0 10 1
+         1:    Start =    0; Length =   10; Type = F_RDLCK
+
+Read lock the first ten bytes of the file through file descriptor 1.
+
+       > lock 1 10 0 1
+       Resource temporarily unavailable
+
+Attempts to read lock the rest of the file.  This, however, fails as
+there are outstanding write locks held through file descriptor 1.
+
+       > lock 1 10 0 0
+         1:    Start =    0; Length =   10; Type = F_RDLCK
+
+What happens when file descriptor tries to unlock the blocked range?
+
+       > lock 1 10 0 2
+       Resource temporarily unavailable
+
+Nothing.
+
+A bunch of tests live in locks-test.  One can run them through the test
+program using: `./locks < locks-test 2>&1 | less'.  If it core dumps or
+triggers an assertion, that is a bug.  Report it.
+
+Fork
+----
+
+Tests to see if the a child inherits the locks across a fork.  According
+to POSIX, the child should not.
+
+       # ./fork foo
+       Parent has a write lock; Others have a write lock.
+       Child has a write lock; Others have a write lock.
+
+We are not POSIX compliant.
diff -Naur hurd-20010412-snapshot/libfshelp-tests/fork.c 
hurd-20010412/libfshelp-tests/fork.c
--- hurd-20010412-snapshot/libfshelp-tests/fork.c       1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp-tests/fork.c        2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,79 @@
+/* Test is a process inherits locks after a fork.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <error.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <hurd.h>
+#include "fs_U.h"
+
+char *lock2str (int type)
+{
+  if (type & LOCK_SH)
+    return "read";
+  if (type & LOCK_EX)
+    return "write";
+  if (type & LOCK_UN)
+    return "unlocked";
+ assert (! "Invalid");
+ return NULL;
+}
+
+int main (int argc, char **argv)
+{
+  error_t err;
+  struct flock lock;
+  int fd;
+  pid_t pid;
+  int mine, others;
+
+  if (argc != 2)
+    error (1, 0, "Usage: %s file", argv[0]);
+
+  lock.l_whence = SEEK_SET;
+  lock.l_start = 0;
+  lock.l_len = 0;
+  lock.l_type = F_WRLCK;
+  
+  fd = file_name_lookup (argv[1], O_READ | O_WRITE | O_CREAT, 0666);
+  if (fd == MACH_PORT_NULL)
+    error (1, errno, "file_name_lookup");
+
+  err = file_record_lock (fd, F_SETLK, &lock);
+  if (err)
+    error (1, err, "file_record_lock");
+
+  pid = fork ();
+  if (pid == -1)
+    error (1, errno, "fork");
+
+  err = file_lock_stat (fd, &mine, &others);
+  if (err)
+    error (1, err, "file_lock_stat");
+
+  printf ("%s has a %s lock; Others have a %s lock.\n",
+         pid ? "Parent" : "Child", lock2str (mine), lock2str (others));
+
+  mach_port_deallocate (mach_task_self (), fd);
+
+  return 0;
+}
diff -Naur hurd-20010412-snapshot/libfshelp-tests/locks-tests 
hurd-20010412/libfshelp-tests/locks-tests
--- hurd-20010412-snapshot/libfshelp-tests/locks-tests  1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp-tests/locks-tests   2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,585 @@
+echo Legend:
+echo +   => Shared region
+echo x   => Exclusive region
+echo ' ' => Unlocked region
+echo .   => Clearing region
+echo []  => Start/End of a region
+echo After each lock command, the proposed region is shown followed
+echo by the result of applying it.
+echo * Established region wraps new region
+echo ** Both boundaries align
+echo [
+exec lock 0 1 10 1
+echo   [+++++++++++++]
+echo [ [+++++++++++++]
+exec lock 0 1 10 1
+echo   [+++++++++++++]
+echo [ [+++++++++++++]
+exec lock 0 1 10 2
+echo   [xxxxxxxxxxxxx]
+echo [ [xxxxxxxxxxxxx]
+exec lock 0 1 10 1
+echo   [+++++++++++++]
+echo [ [xxxxxxxxxxxxx]
+exec lock 0 1 10 2
+echo   [xxxxxxxxxxxxx]
+echo [ [xxxxxxxxxxxxx]
+exec lock 0 1 10 0
+echo   [.............]
+echo [
+exec lock 0 10 0 1
+echo         [++++++++
+echo [       [++++++++
+exec lock 0 10 0 1
+echo         [++++++++
+echo [       [++++++++
+exec lock 0 10 0 2
+echo         [xxxxxxxx
+echo [       [xxxxxxxx
+exec lock 0 10 0 2
+echo         [xxxxxxxx
+echo [       [xxxxxxxx
+exec lock 0 10 0 1
+echo         [++++++++
+echo [       [xxxxxxxx
+exec lock 0 10 0 0
+echo         [........
+echo [
+echo ** Left boundaries align
+exec lock 0 1 10 1
+echo   [+++++++++++]
+echo [ [+++++++++++]
+exec lock 0 1 5 1
+echo   [+++++]
+echo [ [+++++++++++]
+exec lock 0 1 5 2
+echo   [xxxxx]
+echo [ [xxxxx][++++]
+exec lock 0 1 3 1
+echo   [++]
+echo [ [xxxxx][++++]
+exec lock 0 1 10 0
+echo   [............
+echo [
+exec lock 0 1 10 1
+echo   [+++++++++++]
+echo [ [+++++++++++]
+exec lock 0 1 9 2
+echo   [xxxxxxxx]
+echo [ [xxxxxxxx][+]
+exec lock 0 1 5 0
+echo   [...]
+echo [      [***][+]
+exec lock 0 6 3 0
+echo        [.]
+echo [         [*][+]
+exec lock 0 9 1 0
+echo          [.]
+echo [           [+]
+exec lock 0 10 1 0
+echo             [.]
+echo [
+exec lock 0 1 0 1
+echo   [++++++++++++
+echo [ [++++++++++++
+exec lock 0 1 5 1
+echo   [++++]
+echo [ [++++++++++++
+exec lock 0 1 5 2
+echo   [xxxx]
+echo [ [xxxx][++++++
+exec lock 0 1 0 0
+echo   [............
+echo [
+exec lock 0 5 0 2
+echo     [xxxxxxxxxx
+echo [   [xxxxxxxxxx
+exec lock 0 5 5 1
+echo     [++++]
+echo [   [xxxxxxxxxx
+exec lock 0 5 0 1
+echo     [++++++++++
+echo [   [xxxxxxxxxx
+exec lock 0 0 0 0
+echo [..............
+echo [
+echo ** Common right side
+exec lock 0 5 5 1
+echo       [+++++]
+echo [     [+++++]
+exec lock 0 9 1 1
+echo           [+]
+echo [     [+++++]
+exec lock 0 9 1 2
+echo           [x]
+echo [     [++][x]
+exec lock 0 5 4 2
+echo       [xx]
+echo [     [xxxxx]
+exec lock 0 8 2 2
+echo           [x]
+echo [     [xxxxx]
+exec lock 0 9 1 0
+echo           [.]
+echo [     [xxx]
+exec lock 0 5 4 0
+echo       [...]
+echo [
+exec lock 0 5 0 1
+echo     [++++++++++
+echo [   [++++++++++
+exec lock 0 10 0 1
+echo          [+++++
+echo [   [++++++++++
+exec lock 0 10 0 2
+echo          [xxxxx
+echo [   [+++][xxxxx
+exec lock 0 5 0 0
+echo     [..........
+echo [
+echo ** Completely interior
+exec lock 0 5 10 1
+echo      [++++++++]
+echo [    [++++++++]
+exec lock 0 6 8 1
+echo       [++++++]
+echo [    [++++++++]
+exec lock 0 8 3 1
+echo         [+]
+echo [    [++++++++]
+exec lock 0 8 3 2
+echo         [x]
+echo [    [+][x][++]
+exec lock 0 12 1 2
+echo             x
+echo [    [++xxx+x+]
+exec lock 0 6 8 0
+echo       [......]
+echo [    [+]    [+]
+exec lock 0 0 0 0
+echo [..............
+echo [
+exec lock 0 5 0 1
+echo      [+++++++++
+echo [    [+++++++++
+exec lock 0 10 0 1
+echo           [++++
+echo [    [+++++++++
+exec lock 0 10 0 2
+echo           [xxxx
+echo [    [+++][xxxx
+exec lock 0 11 0 0
+echo             [..
+echo [    [+++][x]
+exec lock 0 6 0 0
+echo        [.......
+echo [    [+]
+exec lock 0 5 0 0
+echo      [.........
+echo [
+exec lock 0 10 0 1
+echo          [+++++
+echo [        [+++++
+exec lock 0 11 0 1
+echo           [+]
+echo [        [+++++
+exec lock 0 11 0 1
+echo           [+]
+echo [        [+++++
+exec lock 0 11 1 2
+echo           [x]
+echo [        [+x+++
+exec lock 0 13 0 1
+echo             [+]
+echo [        [+x+++
+exec lock 0 10 0 0
+echo          [.....
+echo [
+echo * We wrap the locked region
+echo ** Left boundaries align
+exec lock 0 1 10 1
+echo  [++++]
+echo [[++++]
+exec lock 0 1 15 1
+echo  [++++++++]
+echo [[++++++++]
+exec lock 0 1 16 1
+echo  [+++++++++]
+echo [[+++++++++]
+exec lock 0 1 20 2
+echo  [xxxxxxxxxxxxx]
+echo [[xxxxxxxxxxxxx]
+exec lock 0 1 30 1
+echo  [+++++++++++++++++++]
+echo [[xxxxxxxxxxxxx][++++]
+exec lock 0 22 11 2
+echo                   [xxx]
+echo [[xxxxxxxxxxxxx][+][xx]
+exec lock 0 1 40 0
+echo  [.........................]
+echo [
+exec lock 0 1 0 1
+echo  [++++++++++
+echo [[++++++++++
+exec lock 0 1 0 1
+echo  [++++++++++
+echo [[++++++++++
+exec lock 0 1 0 2
+echo  [xxxxxxxxxx
+echo [[xxxxxxxxxx
+exec lock 0 0 0 0
+echo [...........
+echo [
+exec lock 0 1 0 1
+echo  [++++++++++
+echo [[++++++++++
+exec lock 0 10 0 1
+echo       [+++++
+echo [[++++++++++
+exec lock 0 10 0 2
+echo       [xxxxx
+echo [[+++][xxxxx
+exec lock 0 0 0 0
+echo [...........
+echo [
+echo ** Right boundaries align
+exec lock 0 5 10 1
+echo     [++++++++]
+echo [   [++++++++]
+exec lock 0 4 11 1
+echo    [+++++++++]
+echo [  [+++++++++]
+exec lock 0 3 12 2
+echo   [xxxxxxxxxx]
+echo [ [xxxxxxxxxx]
+exec lock 0 0 15 2
+echo [xxxxxxxxxxxx]
+echo [xxxxxxxxxxxx]
+exec lock 0 0 0 0
+echo [.............
+echo [
+exec lock 0 5 0 1
+echo      [++++++++
+echo [    [++++++++
+exec lock 0 4 0 1
+echo     [+++++++++
+echo [   [+++++++++
+exec lock 0 3 0 2
+echo    [xxxxxxxxxx
+echo [  [xxxxxxxxxx
+exec lock 0 2 0 2
+echo   [xxxxxxxxxxx
+echo [ [xxxxxxxxxxx
+exec lock 0 0 0 2
+echo [xxxxxxxxxxxxx
+echo [xxxxxxxxxxxxx
+exec lock 0 0 0 0
+echo [.............
+echo [
+echo ** Consume locked region
+exec lock 0 5 10 1
+echo      [++++++++]
+echo [    [++++++++]
+exec lock 0 4 12 1
+echo     [++++++++++]
+echo [   [++++++++++]
+exec lock 0 2 16 1
+echo   [++++++++++++++]
+echo [ [++++++++++++++]
+exec lock 0 1 18 2
+echo  [xxxxxxxxxxxxxxxx]
+echo [[xxxxxxxxxxxxxxxx]
+exec lock 0 0 24 2
+echo [xxxxxxxxxxxxxxxxxxxxx]
+echo [xxxxxxxxxxxxxxxxxxxxx]
+exec lock 0 0 30 0
+echo [.........................]
+echo [
+exec lock 0 5 3 1
+echo      [++]
+echo [    [++]
+exec lock 0 10 5 1
+echo            [++++]
+echo [    [++]  [++++]
+exec lock 0 20 5 2
+echo                      [xxxx]
+echo [    [++]  [++++]    [xxxx]
+exec lock 0 4 30 2
+echo     [xxxxxxxxxxxxxxxxxxxxxxxxxx]
+echo [   [xxxxxxxxxxxxxxxxxxxxxxxxxx]
+exec lock 0 1 35 1
+echo   [++++++++++++++++++++++++++++++]
+echo [ [+[xxxxxxxxxxxxxxxxxxxxxxxxxx]+]
+exec lock 0 0 40 1
+echo [+++++++++++++++++++++++++++++++++++]
+echo [++][xxxxxxxxxxxxxxxxxxxxxxxxxx][+++]
+exec lock 0 0 0 0
+echo [....................................
+echo [
+exec lock 0 5 5 1
+echo      [+++]
+echo [    [+++]
+exec lock 0 4 0 1
+echo     [++++++]
+echo [   [++++++]
+exec lock 0 4 0 0
+echo     [..........
+echo [
+exec lock 0 5 3 1
+echo      [++]
+echo [    [++]
+exec lock 0 10 5 1
+echo              [++++]
+echo [    [++]    [++++]
+exec lock 0 0 0 1
+echo [++++++++++++++++++++
+echo [++++++++++++++++++++
+exec lock 0 0 0 0
+echo [....................
+echo [
+exec lock 0 5 3 1
+echo      [++]
+echo [    [++]
+exec lock 0 10 3 1
+echo             [++]
+echo [    [++]   [++]
+exec lock 0 4 0 1
+echo     [++++++++++++++
+echo [   [++++++++++++++
+exec lock 0 10 3 2
+echo             [**]
+echo [   [++++++][**][++
+exec lock 0 0 0 2
+echo [xxxxxxxxxxxxxxxxxx
+echo [xxxxxxxxxxxxxxxxxx
+exec lock 0 0 0 0
+echo [..................
+echo [
+echo * Our start is within the locked region or one byte after and our
+echo   end is after the end of the locked region.
+echo ** The regions are the same type: Merge into a single large region
+exec lock 0 5 5 1
+echo      [+++]
+echo [    [+++]
+exec lock 0 6 5 1
+echo       [+++]
+echo [    [++++]
+exec lock 0 8 8 1
+echo         [++++++]
+echo [    [+++++++++]
+exec lock 0 16 4 1
+echo                 [++]
+echo [    [+++++++++++++]
+exec lock 0 20 0 1
+echo                     [+++
+echo [    [++++++++++++++++++
+exec lock 0 5 16 0
+echo      [..............]
+echo [                    [+++
+exec lock 0 20 0 0
+echo                      [...
+echo [
+exec lock 0 6 6 2
+echo       [xxxx]
+echo [     [xxxx]
+exec lock 0 7 7 2
+echo        [xxxxx]
+echo [     [xxxxxx]
+exec lock 0 14 7 2
+echo               [xxxxx]
+echo [     [xxxxxxxxxxxxx]
+exec lock 0 21 0 2
+echo                      [xx
+echo [     [xxxxxxxxxxxxxxxxx
+exec lock 0 6 0 0
+echo       [.................
+echo [
+echo ** Different types just after the end of the locked region
+exec lock 0 1 3 1
+echo  [++]
+echo [[++]
+exec lock 0 4 3 2
+echo      [xx]
+echo [[++][xx]
+exec lock 0 7 3 1
+echo          [++]
+echo [[++][xx][++]
+exec lock 0 10 0 2
+echo              [xxx
+echo [[++][xx][++][xxx
+exec lock 0 5 0 0
+echo       [.........
+echo [[++]x
+exec lock 0 5 0 1
+echo       [+++
+echo [[++]x[+++
+exec lock 0 1 0 0
+echo  [...
+echo [
+echo ** New region consumes the intersection.
+exec lock 0 5 5 1
+echo      [+++]
+echo [    [+++]
+exec lock 0 8 6 2
+echo          [xxx]
+echo [    [++][xxx]
+exec lock 0 6 0 2
+echo         [xxxxxx
+echo [    [+][xxxxxx
+exec lock 0 5 0 0
+echo      [.........
+echo [
+echo ** New region is dominated
+exec lock 0 5 5 2
+echo      [xxx]
+echo [    [xxx]
+exec lock 0 8 6 1
+echo         [++++]
+echo [    [xxx][++]
+exec lock 0 6 0 1
+echo        [++++++
+echo [    [xxx][+++
+exec lock 0 5 0 0 
+echo      [........
+echo [
+echo * Our start falls before the locked region.  Our end falls just
+echo   before or with in the region (although we do not consume it)
+echo ** The regions are the same type: Merge into a single large region
+exec lock 0 10 5 1
+echo           [+++]
+echo [         [+++]
+exec lock 0 5 5 1
+echo      [+++]
+echo [    [++++++++]
+exec lock 0 4 4 1
+echo     [++]
+echo [   [+++++++++]
+exec lock 0 0 10 1
+echo [+++++++++]
+echo [+++++++++++++]
+exec lock 0 0 15 0
+echo [...............]
+echo [
+exec lock 0 10 0 1
+echo           [++++
+echo [         [++++
+exec lock 0 5 5 1
+echo      [+++]
+echo [    [+++++++++
+exec lock 0 4 1 1
+echo     +
+echo [   [++++++++++
+exec lock 0 0 0 1
+echo [++++++++++++++
+echo [++++++++++++++
+exec lock 0 0 0 0
+echo [....
+echo [
+exec lock 0 10 5 2
+echo           [xxx]
+echo [         [xxx]
+exec lock 0 5 5 2
+echo      [xxx]
+echo [    [xxxxxxxx]
+exec lock 0 4 4 2
+echo     [xx]
+echo [   [xxxxxxxxx]
+exec lock 0 0 10 2
+echo [xxxxxxxxx]
+echo [xxxxxxxxxxxxx]
+exec lock 0 0 15 0
+echo [...............]
+echo [
+exec lock 0 10 0 2
+echo           [xxxx
+echo [         [xxxx
+exec lock 0 5 5 2
+echo      [xxx]
+echo [    [xxxxxxxxx
+exec lock 0 4 1 2
+echo     x
+echo [   [xxxxxxxxxx
+exec lock 0 0 0 2
+echo [xxxxxxxxxxxxxx
+echo [xxxxxxxxxxxxxx
+exec lock 0 0 0 0
+echo [....
+echo [
+echo ** Different types just before the start of the locked region
+exec lock 0 5 5 1
+echo       [+++]
+echo [     [+++]
+exec lock 0 3 2 2
+echo    [x]
+echo [  [x][+++]
+exec lock 0 2 1 1
+echo   +
+echo [ +[x][+++]
+exec lock 0 1 0 2
+echo  [xxxx
+echo [[xxxx
+exec lock 0 0 1 1
+echo +
+echo +[xxxx
+exec lock 0 0 0 0
+echo [....
+echo [....
+exec lock 0 5 0 1
+echo      [++++
+echo [    [++++
+exec lock 0 0 5 2
+echo [xxxxxxxxx
+echo [xxxxxxxxx
+exec lock 0 0 0 0
+echo [....
+echo [
+echo ** New region consumes the intersection.
+exec lock 0 5 5 1
+echo      [+++]
+echo [    [+++]
+exec lock 0 4 3 2
+echo     [x]
+echo [   [x][+]
+exec lock 0 2 0 2
+echo    [xxxxxx
+echo [  [xxxxxx
+exec lock 0 0 0 0
+echo [....
+echo [
+exec lock 0 5 0 1
+echo      [++++++
+echo [    [++++++
+exec lock 0 4 5 2
+echo     [xxx]
+echo [   [xxx][++
+exec lock 0 4 0 0
+echo     [....
+echo [
+exec lock 0 5 0 1
+echo      [++++
+echo [    [++++
+exec lock 0 0 0 2
+echo [xxxxxxxxxx
+echo [xxxxxxxxxx
+exec lock 0 0 0 0
+echo [....
+echo [
+echo ** New region is dominated
+exec lock 0 5 5 2
+echo      [xxx]
+echo [    [xxx]
+exec lock 0 4 5 1
+echo     [+++]
+echo [   +[xxx]
+exec lock 0 0 0 0
+echo [...
+echo [
+exec lock 0 5 0 2
+echo     [xxxx
+echo [   [xxxx
+exec lock 0 0 0 1
+echo [++++++++
+echo [+++[xxxx
+exec lock 0 0 0 0
+echo [....
+echo [
diff -Naur hurd-20010412-snapshot/libfshelp-tests/locks.c 
hurd-20010412/libfshelp-tests/locks.c
--- hurd-20010412-snapshot/libfshelp-tests/locks.c      1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp-tests/locks.c       2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,325 @@
+/* Test record locking.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "../libfshelp/fshelp.h"
+#include "../libfshelp/rlock.h"
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef PEROPENS
+#define PEROPENS 10
+#endif
+
+struct rlock_box box;
+struct rlock_peropen peropens[PEROPENS];
+off_t pointers[PEROPENS];
+off_t file_size;
+
+struct command
+{
+  char *name;
+  int (*func)(char *cmds);
+  char *doc;
+};
+
+error_t cmd_help (char *);
+error_t cmd_comment (char *);
+error_t cmd_echo (char *);
+error_t cmd_lock (char *);
+error_t cmd_list (char *);
+error_t cmd_seek (char *);
+error_t cmd_exec (char *);
+
+struct command commands [] =
+  {
+    { "help", cmd_help, "Print this screen" },
+    { "#", cmd_comment, "Comment (Must _start_ the line)." },
+    { "echo", cmd_echo, "Echo the line." },
+    { "lock", cmd_lock, 
+         "po start length type\n"
+         "\ttype = { F_UNLCK=0, F_RDLCK,=1, F_WRLCK=2 }" },
+    { "list", cmd_list, "list all locks' status" },
+    { "seek", cmd_seek, "PO1 ... Print the position of the given po.\n"
+                       "\tPO1=N ... Seek a given po." },
+    { "exec", cmd_exec, "Execute a built in echoing the command."}
+  };
+
+error_t
+cmd_help (char *args)
+{
+  int i;
+  printf ("Commands:\n");
+  for (i = 0; i < sizeof (commands) / sizeof (struct command); i ++)
+    printf ("%s\t%s\n", commands[i].name, commands[i].doc);
+  return 0;
+}
+
+error_t
+cmd_comment (char *args)
+{
+  return 0;
+}
+
+error_t
+cmd_echo (char *args)
+{
+  printf ("%s", args);
+  return 0;
+}
+
+error_t
+cmd_lock (char *args)
+{
+  int po, type;
+  off_t start, len;
+  struct flock lock;
+  error_t err;
+
+  if (4 != sscanf (args, "%d %ld %ld %d", &po, &start, &len, &type))
+    {
+      printf ("Syntax error.\n");
+      return 0;
+    }
+
+  lock.l_type = type;
+  lock.l_whence = SEEK_CUR;
+  lock.l_start = start;
+  lock.l_len = len;
+
+  if (po < 0 || po >= PEROPENS)
+    {
+      printf ("Unknown peropen: %d.\n", po);
+      return 0;
+    }
+
+  switch (type)
+    {
+    case 0: lock.l_type = F_UNLCK; break;
+    case 1: lock.l_type = F_RDLCK; break;
+    case 2: lock.l_type = F_WRLCK; break;
+    default: printf ("Unknown type.\n"); return 0;
+    }
+
+  err= fshelp_rlock_tweak (&box, NULL, &peropens[po], O_RDWR,
+                          file_size, pointers[po], F_SETLK,
+                          &lock);
+  if (! err)
+    {
+      char buf[10];
+      sprintf (buf, "%d\n", po);
+      cmd_list (buf);
+    }
+  return err;
+}
+
+error_t
+cmd_list (char *args)
+{
+  char *end;
+
+  void dump (int i)
+    {
+      struct rlock_list *l;
+
+      printf ("%3d:", i);
+      for (l = *peropens[i].locks; l; l = l->po.next)
+        {
+         printf ("\tStart = %4ld; Length = %4ld; Type = ", l->start, l->len);
+         switch (l->type)
+           {
+           case F_RDLCK: printf ("F_RDLCK"); break;
+           case F_WRLCK: printf ("F_WRLCK"); break;
+           case F_UNLCK: printf ("F_UNLCK"); break;
+           default: printf ("UNKNOWN"); break;
+           }
+         printf ("\n");
+       }
+
+      if (*peropens[i].locks == NULL)
+       printf ("\n");
+    }
+
+  while (*args == ' ')
+    args ++;
+
+  if (*args == '\n' || *args == '\0')
+    {
+      int i;
+
+      for (i = 0; i < PEROPENS; i ++)
+       dump (i);
+      return 0;
+    }
+
+  while (1)
+    {
+      int p = strtol (args, &end, 0);
+      if (end == args)
+        {
+         printf ("Syntax error.\n");
+         return 0;
+       }
+
+      if (p < 0 || p > PEROPENS)
+       printf ("%3d:\tOut of range.", p);
+      else
+       dump (p);
+
+      while (*end == ' ')
+       end ++;
+
+      if (*end == '\n' || *end == '\0')
+       return 0;
+      args = end;
+    }
+}
+
+error_t
+cmd_seek (char *args)
+{
+  char *end;
+  int p;
+
+  while (*args == ' ')
+    args ++;
+
+  if (*args == '\n' || *args == '\0')
+    {
+      int i;
+      for (i = 0; i < PEROPENS; i ++)
+        printf ("%3d: %ld\n", i, pointers[i]);
+      return 0;
+    }
+
+  while (1)
+    {
+      int set = 0;
+      int seek_to = 0;
+
+      p = strtol (args, &end, 0);
+      if (end == args)
+        {
+         printf ("Syntax error.\n");
+         return 0;
+       }
+
+      if (*end == '=')
+        {
+         set = 1;
+         args = end + 1;
+         seek_to = strtol (args, &end, 0);
+         if (end == args)
+           {
+             printf ("Syntax error.\n");
+             return 0;
+           }
+       }
+
+      if (p < 0 || p > PEROPENS)
+       printf ("%3d: unknown peropen\n", p);
+      else
+        {
+          printf ("%3d: %ld", p, pointers[p]);
+         if (set)
+           printf (" => %ld\n", pointers[p] = seek_to);
+         else
+           printf ("\n");
+       }
+
+      while (*end == ' ')
+       end ++;
+      if (*end == '\0' || *end == '\n')
+        return 0;
+      args = end;
+    }
+}
+
+error_t
+interpret (char *buffer)
+{
+  int i;
+
+  while (*buffer == ' ')
+    buffer ++;
+
+  if (*buffer == '\n')
+    return 0;
+
+  for (i = 0; i < sizeof (commands) / sizeof (struct command); i ++)
+  if (strncmp (commands[i].name, buffer, strlen (commands[i].name)) == 0)
+    {
+      error_t err;
+      err = commands[i].func (buffer + strlen (commands[i].name) + 1);
+      if (err)
+       printf ("%s\n", strerror (err));
+      return err;
+    }
+
+  printf ("Unknown command.\n");
+  return 0;
+}
+
+error_t
+cmd_exec (char *arg)
+{
+  printf ("%s", arg);
+  interpret (arg);
+  return 0;
+}
+
+int main (int argc, char *argv[])
+{
+  int i;
+
+  if (argc != 1)
+    {
+      printf ("Usage: %s\n"
+             "\tType `help' at the prompt.\n"
+             "\tUsed to test the record locking functions in libfshelp\n",
+             argv[0]);
+      return 1;
+    }
+
+  fshelp_rlock_init (&box);
+  for (i = 0; i < PEROPENS; i ++)
+    fshelp_rlock_po_init (&peropens[i]);
+
+  while (! feof (stdin))
+    {
+      char b[1024];
+
+      printf ("> ");
+      fflush (stdout);
+
+      if (! fgets (b, sizeof (b), stdin))
+       {
+         if (feof (stdin))
+           break;
+         else
+           continue;
+       }
+
+      interpret (b);
+    }
+
+  printf ("\n");
+  return 0;
+}
diff -Naur hurd-20010412-snapshot/libfshelp-tests/race.c 
hurd-20010412/libfshelp-tests/race.c
--- hurd-20010412-snapshot/libfshelp-tests/race.c       1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libfshelp-tests/race.c        2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,82 @@
+/* Test races in the record locking code.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <error.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <hurd.h>
+#include "fs_U.h"
+#include "io_U.h"
+
+int main (int argc, char **argv)
+{
+  error_t err;
+  struct flock lock;
+  int fd;
+  int i;
+  int v;
+  int blocked = 0;
+  char buf[10] = "";
+  char *bufp;
+
+  if (argc != 4)
+    error (1, 0, "Usage: %s file start len", argv[0]);
+
+  lock.l_whence = SEEK_SET;
+  lock.l_start = atoi (argv[2]);
+  lock.l_len = atoi (argv[3]);
+  
+  fd = file_name_lookup (argv[1], O_READ | O_WRITE | O_CREAT, 0666);
+  if (fd == MACH_PORT_NULL)
+    error (1, errno, "file_name_lookup");
+
+  for (i = 0; i < 10000; i ++)
+    {
+      lock.l_type = F_WRLCK;
+      err = file_record_lock (fd, F_SETLK, &lock);
+      if (err)
+        {
+         blocked ++;
+          err = file_record_lock (fd, F_SETLKW, &lock);
+       }
+      if (err)
+        error (1, err, "file_record_lock");
+
+      v = sizeof (buf);
+      bufp = buf;
+      io_read (fd, &bufp, &v, 0, v);
+
+      v = atoi (bufp);
+      sprintf (buf, "%d\n", v + 1);
+
+      v = 10;
+      io_write (fd, buf, sizeof (buf), 0, &v);
+      if (v == 0)
+        error (1, errno, "write (%d)", i);
+
+      lock.l_type = F_UNLCK;
+      file_record_lock (fd, F_SETLK, &lock);
+    }
+
+  mach_port_deallocate (mach_task_self (), fd);
+
+  printf ("Was blocked %d times\n", blocked);
+  return 0;
+}
diff -Naur hurd-20010412-snapshot/libnetfs/Makefile 
hurd-20010412/libnetfs/Makefile
--- hurd-20010412-snapshot/libnetfs/Makefile    2002-05-13 19:39:37.000000000 
+0200
+++ hurd-20010412/libnetfs/Makefile     2006-01-19 12:05:01.000000000 +0100
@@ -30,7 +30,7 @@
        file-get-translator.c file-getcontrol.c file-getlinknode.c \
        file-lock-stat.c file-lock.c file-set-size.c \
        file-set-translator.c file-statfs.c file-sync.c file-syncfs.c \
-       file-utimes.c file-reparent.c fsstubs.c
+       file-utimes.c file-record-lock.c file-reparent.c fsstubs.c
 
 IOSRCS=        io-read.c io-readable.c io-seek.c io-write.c io-stat.c 
io-async.c     \
        io-set-all-openmodes.c io-get-openmodes.c io-set-some-openmodes.c     \
diff -Naur hurd-20010412-snapshot/libnetfs/file-record-lock.c 
hurd-20010412/libnetfs/file-record-lock.c
--- hurd-20010412-snapshot/libnetfs/file-record-lock.c  1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libnetfs/file-record-lock.c   2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,31 @@
+/* 
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+#include "netfs.h"
+#include "fs_S.h"
+
+error_t
+netfs_S_file_record_lock (struct protid *cred,
+                         int cmd,
+                         struct flock *flock)
+{
+  return EOPNOTSUPP;
+}
diff -Naur hurd-20010412-snapshot/libtrivfs/Makefile 
hurd-20010412/libtrivfs/Makefile
--- hurd-20010412-snapshot/libtrivfs/Makefile   2003-02-16 00:18:02.000000000 
+0100
+++ hurd-20010412/libtrivfs/Makefile    2006-01-19 12:16:09.000000000 +0100
@@ -25,7 +25,7 @@
        file-getlinknode.c file-lock.c file-set-trans.c file-statfs.c \
        file-sync.c file-syncfs.c file-set-size.c file-utimes.c file-exec.c \
        file-access.c dir-chg.c file-chg.c file-get-storage-info.c \
-       file-get-fs-options.c file-reparent.c
+       file-get-fs-options.c file-record-lock.c file-reparent.c
 
 IOSRCS=io-async-icky.c io-async.c io-duplicate.c io-map.c io-modes-get.c \
        io-modes-off.c io-modes-on.c io-modes-set.c io-owner-get.c \
diff -Naur hurd-20010412-snapshot/libtrivfs/file-record-lock.c 
hurd-20010412/libtrivfs/file-record-lock.c
--- hurd-20010412-snapshot/libtrivfs/file-record-lock.c 1970-01-01 
01:00:00.000000000 +0100
+++ hurd-20010412/libtrivfs/file-record-lock.c  2006-01-19 12:05:01.000000000 
+0100
@@ -0,0 +1,28 @@
+/* 
+   Copyright (C) 2001 Free Software Foundation
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "priv.h"
+#include "fs_S.h"
+
+kern_return_t
+trivfs_S_file_record_lock (struct trivfs_protid *cred,
+                          mach_port_t reply,
+                          mach_msg_type_name_t reply_type,
+                          int cmd, struct flock *lock)
+{
+  return EOPNOTSUPP;
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]