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;
+}
