diff -urNX ../kernels/exclude ../kernels/linux-ac13/fs/lockd/clntlock.c linux-ac13+lock/fs/lockd/clntlock.c
--- ../kernels/linux-ac13/fs/lockd/clntlock.c	Sun Apr  2 18:31:32 2000
+++ linux-ac13+lock/fs/lockd/clntlock.c	Sun Jun 11 02:06:57 2000
@@ -162,8 +162,7 @@
 {
 	struct nlm_host	  *host = (struct nlm_host *) ptr;
 	struct nlm_wait	  *block;
-	struct file_lock  *fl;
-	struct inode	  *inode;
+	struct list_head *tmp;
 
 	/* This one ensures that our parent doesn't terminate while the
 	 * reclaim is in progress */
@@ -171,19 +170,21 @@
 	lockd_up();
 
 	/* First, reclaim all locks that have been granted previously. */
-	do {
-		for (fl = file_lock_table; fl; fl = fl->fl_nextlink) {
-			inode = fl->fl_file->f_dentry->d_inode;
-			if (inode->i_sb->s_magic == NFS_SUPER_MAGIC
-			 && nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr)
-			 && fl->fl_u.nfs_fl.state != host->h_state
-			 && (fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) {
-				fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED;
-				nlmclnt_reclaim(host, fl);
-				break;
-			}
+restart:
+	tmp = file_lock_list.next;
+	while (tmp != &file_lock_list) {
+		struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
+		struct inode *inode = fl->fl_file->f_dentry->d_inode;
+		if (inode->i_sb->s_magic == NFS_SUPER_MAGIC &&
+				nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr) &&
+				fl->fl_u.nfs_fl.state != host->h_state &&
+				(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) {
+			fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED;
+			nlmclnt_reclaim(host, fl);
+			goto restart;
 		}
-	} while (fl);
+		tmp = tmp->next;
+	}
 
 	host->h_reclaiming = 0;
 	wake_up(&host->h_gracewait);
diff -urNX ../kernels/exclude ../kernels/linux-ac13/fs/lockd/svclock.c linux-ac13+lock/fs/lockd/svclock.c
--- ../kernels/linux-ac13/fs/lockd/svclock.c	Sat May 13 12:43:55 2000
+++ linux-ac13+lock/fs/lockd/svclock.c	Sun Jun 11 02:06:57 2000
@@ -347,7 +347,7 @@
 	/* Append to list of blocked */
 	nlmsvc_insert_block(block, NLM_NEVER);
 
-	if (!block->b_call.a_args.lock.fl.fl_prevblock) {
+	if (!list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
 		/* Now add block to block list of the conflicting lock
 		   if we haven't done so. */
 		dprintk("lockd: blocking on this lock.\n");
diff -urNX ../kernels/exclude ../kernels/linux-ac13/fs/locks.c linux-ac13+lock/fs/locks.c
--- ../kernels/linux-ac13/fs/locks.c	Sun Jun 11 01:45:30 2000
+++ linux-ac13+lock/fs/locks.c	Sun Jun 11 05:14:29 2000
@@ -108,100 +108,97 @@
 #include <linux/malloc.h>
 #include <linux/file.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 
-struct file_lock *file_lock_table = NULL;
+LIST_HEAD(file_lock_list);
+static LIST_HEAD(blocked_list);
 
-/*
- * Allocate an empty lock structure. We can use GFP_KERNEL now that
- * all allocations are done in advance.
- */
-static struct file_lock *locks_empty_lock(void)
-{
-	/* Okay, let's make a new file_lock structure... */
-	return ((struct file_lock *) kmalloc(sizeof(struct file_lock),
-						GFP_KERNEL));
-}
-
-/*
- * Initialize a new lock from an existing file_lock structure.
- */
-static struct file_lock *locks_init_lock(struct file_lock *new,
-					 struct file_lock *fl)
-{
-	if (new) {
-		memset(new, 0, sizeof(*new));
-		new->fl_owner = fl->fl_owner;
-		new->fl_pid = fl->fl_pid;
-		init_waitqueue_head(&new->fl_wait);
-		new->fl_file = fl->fl_file;
-		new->fl_flags = fl->fl_flags;
-		new->fl_type = fl->fl_type;
-		new->fl_start = fl->fl_start;
-		new->fl_end = fl->fl_end;
-		new->fl_notify = fl->fl_notify;
-		new->fl_insert = fl->fl_insert;
-		new->fl_remove = fl->fl_remove;
-		new->fl_u = fl->fl_u;
-	}
-	return new;
-}
+static kmem_cache_t *filelock_cache;
 
-/* Allocate a new lock, and initialize its fields from fl.
- * The lock is not inserted into any lists until locks_insert_lock() or 
- * locks_insert_block() are called.
- */
-static inline struct file_lock *locks_alloc_lock(struct file_lock *fl)
+/* Allocate an empty lock structure. */
+static struct file_lock *locks_alloc_lock(void)
 {
-	return locks_init_lock(locks_empty_lock(), fl);
+	struct file_lock *fl;
+	fl = kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
+	return fl;
 }
 
-/* Free lock not inserted in any queue.
- */
+/* Free a lock which is not in use. */
 static inline void locks_free_lock(struct file_lock *fl)
 {
+	if (fl == NULL) {
+		BUG();
+		return;
+	}
+
 	if (waitqueue_active(&fl->fl_wait))
 		panic("Attempting to free lock with active wait queue");
 
-	if (fl->fl_nextblock != NULL || fl->fl_prevblock != NULL)
+	if (!list_empty(&fl->fl_block))
 		panic("Attempting to free lock with active block list");
-		
-	kfree(fl);
-	return;
+
+	if (!list_empty(&fl->fl_link))
+		panic("Attempting to free lock on active lock list");
+
+	kmem_cache_free(filelock_cache, fl);
 }
 
-/* Verify a call to flock() and fill in a file_lock structure with
- * an appropriate FLOCK lock.
+/*
+ * Initialises the fields of the file lock which are invariant for
+ * free file_locks.
  */
-static int flock_make_lock(struct file *filp, struct file_lock *fl,
-			   unsigned int cmd)
+static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags)
 {
-	memset(fl, 0, sizeof(*fl));
+	struct file_lock *lock = (struct file_lock *) foo;
 
-	init_waitqueue_head(&fl->fl_wait);
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) !=
+					SLAB_CTOR_CONSTRUCTOR)
+		return;
 
-	switch (cmd & ~LOCK_NB) {
-	case LOCK_SH:
-		fl->fl_type = F_RDLCK;
-		break;
-	case LOCK_EX:
-		fl->fl_type = F_WRLCK;
-		break;
-	case LOCK_UN:
-		fl->fl_type = F_UNLCK;
-		break;
-	default:
-		return (0);
-	}
+	lock->fl_next = NULL;
+	INIT_LIST_HEAD(&lock->fl_link);
+	INIT_LIST_HEAD(&lock->fl_block);
+	init_waitqueue_head(&lock->fl_wait);
+}
 
+/*
+ * Initialize a new lock from an existing file_lock structure.
+ */
+static void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
+{
+	new->fl_owner = fl->fl_owner;
+	new->fl_pid = fl->fl_pid;
+	new->fl_file = fl->fl_file;
+	new->fl_flags = fl->fl_flags;
+	new->fl_type = fl->fl_type;
+	new->fl_start = fl->fl_start;
+	new->fl_end = fl->fl_end;
+	new->fl_notify = fl->fl_notify;
+	new->fl_insert = fl->fl_insert;
+	new->fl_remove = fl->fl_remove;
+	new->fl_u = fl->fl_u;
+}
+
+/* Fill in a file_lock structure with an appropriate FLOCK lock. */
+static struct file_lock *flock_make_lock(struct file *filp, unsigned int type)
+{
+	struct file_lock *fl = locks_alloc_lock();
+	if (fl == NULL)
+		return NULL;
+
+	fl->fl_owner = NULL;
+	fl->fl_file = filp;
 	fl->fl_flags = FL_FLOCK;
+	fl->fl_type = type;
 	fl->fl_start = 0;
 	fl->fl_end = OFFSET_MAX;
-	fl->fl_file = filp;
-	fl->fl_owner = NULL;
+	fl->fl_notify = NULL;
+	fl->fl_insert = NULL;
+	fl->fl_remove = NULL;
 	
-	return (1);
+	return fl;
 }
 
 /* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
@@ -212,21 +209,6 @@
 {
 	loff_t start;
 
-	memset(fl, 0, sizeof(*fl));
-	
-	init_waitqueue_head(&fl->fl_wait);
-	fl->fl_flags = FL_POSIX;
-
-	switch (l->l_type) {
-	case F_RDLCK:
-	case F_WRLCK:
-	case F_UNLCK:
-		fl->fl_type = l->l_type;
-		break;
-	default:
-		return (0);
-	}
-
 	switch (l->l_whence) {
 	case 0: /*SEEK_SET*/
 		start = 0;
@@ -250,9 +232,23 @@
 	if (l->l_len == 0)
 		fl->fl_end = OFFSET_MAX;
 	
-	fl->fl_file = filp;
 	fl->fl_owner = current->files;
 	fl->fl_pid = current->pid;
+	fl->fl_file = filp;
+	fl->fl_flags = FL_POSIX;
+	fl->fl_notify = NULL;
+	fl->fl_insert = NULL;
+	fl->fl_remove = NULL;
+
+	switch (l->l_type) {
+	case F_RDLCK:
+	case F_WRLCK:
+	case F_UNLCK:
+		fl->fl_type = l->l_type;
+		break;
+	default:
+		return (0);
+	}
 
 	return (1);
 }
@@ -280,26 +276,12 @@
 /* Remove waiter from blocker's block list.
  * When blocker ends up pointing to itself then the list is empty.
  */
-static void locks_delete_block(struct file_lock *blocker,
-			       struct file_lock *waiter)
+static void locks_delete_block(struct file_lock *waiter)
 {
-	struct file_lock *nextblock;
-	struct file_lock *prevblock;
-	
-	nextblock = waiter->fl_nextblock;
-	prevblock = waiter->fl_prevblock;
-
-	if (nextblock == NULL)
-		return;
-	
-	nextblock->fl_prevblock = prevblock;
-	prevblock->fl_nextblock = nextblock;
-
-	waiter->fl_prevblock = waiter->fl_nextblock = NULL;
-	if (blocker->fl_nextblock == blocker)
-		/* No more locks on blocker's blocked list */
-		blocker->fl_prevblock = blocker->fl_nextblock = NULL;
-	return;
+	list_del(&waiter->fl_block);
+	INIT_LIST_HEAD(&waiter->fl_block);
+	list_del(&waiter->fl_link);
+	INIT_LIST_HEAD(&waiter->fl_link);
 }
 
 /* Insert waiter into blocker's block list.
@@ -310,29 +292,15 @@
 static void locks_insert_block(struct file_lock *blocker, 
 			       struct file_lock *waiter)
 {
-	struct file_lock *prevblock;
-
-	if (waiter->fl_prevblock) {
-		printk(KERN_ERR "locks_insert_block: remove duplicated lock "
-			"(pid=%d %Ld-%Ld type=%d)\n",
-			waiter->fl_pid, (long long)waiter->fl_start,
-			(long long)waiter->fl_end, waiter->fl_type);
-		locks_delete_block(waiter->fl_prevblock, waiter);
-	}
-
-	if (blocker->fl_prevblock == NULL)
-		/* No previous waiters - list is empty */
-		prevblock = blocker;
-	else
-		/* Previous waiters exist - add to end of list */
-		prevblock = blocker->fl_prevblock;
-
-	prevblock->fl_nextblock = waiter;
-	blocker->fl_prevblock = waiter;
-	waiter->fl_nextblock = blocker;
-	waiter->fl_prevblock = prevblock;
-	
-	return;
+	if (!list_empty(&waiter->fl_block)) {
+		printk(KERN_ERR "locks_insert_block: removing duplicated lock "
+			"(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid,
+			waiter->fl_start, waiter->fl_end, waiter->fl_type);
+		locks_delete_block(waiter);
+	}
+	list_add_tail(&waiter->fl_block, &blocker->fl_block);
+//	list_add(&waiter->fl_link, &blocked_list);
+//	waiter->fl_next = blocker;
 }
 
 /* Wake up processes blocked waiting for blocker.
@@ -341,9 +309,8 @@
  */
 static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
 {
-	struct file_lock *waiter;
-
-	while ((waiter = blocker->fl_nextblock) != NULL) {
+	while (!list_empty(&blocker->fl_block)) {
+		struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_block);
 		/* N.B. Is it possible for the notify function to block?? */
 		if (waiter->fl_notify)
 			waiter->fl_notify(waiter);
@@ -358,10 +325,9 @@
 			/* Remove waiter from the block list, because by the
 			 * time it wakes up blocker won't exist any more.
 			 */
-			locks_delete_block(blocker, waiter);
+			locks_delete_block(waiter);
 		}
 	}
-	return;
 }
 
 /* Insert file lock fl into an inode's lock list at the position indicated
@@ -369,18 +335,14 @@
  */
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
 {
-	fl->fl_nextlink = file_lock_table;
-	fl->fl_prevlink = NULL;
-	if (file_lock_table != NULL)
-		file_lock_table->fl_prevlink = fl;
-	file_lock_table = fl;
-	fl->fl_next = *pos;	/* insert into file's list */
+	list_add(&fl->fl_link, &file_lock_list);
+
+	/* insert into file's list */
+	fl->fl_next = *pos;
 	*pos = fl;
 
 	if (fl->fl_insert)
 		fl->fl_insert(fl);
-
-	return;
 }
 
 /* Delete a lock and free it.
@@ -390,31 +352,25 @@
  */
 static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
 {
-	struct file_lock *thisfl;
-	struct file_lock *prevfl;
-	struct file_lock *nextfl;
-	
-	thisfl = *thisfl_p;
-	*thisfl_p = thisfl->fl_next;
+	int (*lock)(struct file *, int, struct file_lock *);
+	struct file_lock *fl = *thisfl_p;
 
-	prevfl = thisfl->fl_prevlink;
-	nextfl = thisfl->fl_nextlink;
+	*thisfl_p = fl->fl_next;
+	fl->fl_next = NULL;
 
-	if (nextfl != NULL)
-		nextfl->fl_prevlink = prevfl;
+	list_del(&fl->fl_link);
+	INIT_LIST_HEAD(&fl->fl_link);
 
-	if (prevfl != NULL)
-		prevfl->fl_nextlink = nextfl;
-	else
-		file_lock_table = nextfl;
+	if (fl->fl_remove)
+		fl->fl_remove(fl);
 
-	if (thisfl->fl_remove)
-		thisfl->fl_remove(thisfl);
-	
-	locks_wake_up_blocks(thisfl, wait);
-	locks_free_lock(thisfl);
-
-	return;
+	locks_wake_up_blocks(fl, wait);
+	lock = fl->fl_file->f_op->lock;
+	if (lock) {
+		fl->fl_type = F_UNLCK;
+		lock(fl->fl_file, F_SETLK, fl);
+	}
+	locks_free_lock(fl);
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. Common functionality
@@ -502,8 +458,7 @@
 static int posix_locks_deadlock(struct file_lock *caller_fl,
 				struct file_lock *block_fl)
 {
-	struct file_lock *fl;
-	struct file_lock *bfl;
+	struct list_head *tmp;
 	void		 *caller_owner, *blocked_owner;
 	unsigned int	 caller_pid, blocked_pid;
 
@@ -514,11 +469,14 @@
 
 next_task:
 	if (caller_owner == blocked_owner && caller_pid == blocked_pid)
-		return (1);
-	for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) {
-		if (fl->fl_owner == NULL || fl->fl_nextblock == NULL)
+		return 1;
+	list_for_each(tmp, &file_lock_list) {
+		struct list_head *btmp;
+		struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
+		if (fl->fl_owner == NULL || list_empty(&fl->fl_block))
 			continue;
-		for (bfl = fl->fl_nextblock; bfl != fl; bfl = bfl->fl_nextblock) {
+		list_for_each(btmp, &fl->fl_block) {
+			struct file_lock *bfl = list_entry(tmp, struct file_lock, fl_block);
 			if (bfl->fl_owner == blocked_owner &&
 			    bfl->fl_pid == blocked_pid) {
 				if (fl->fl_owner == caller_owner &&
@@ -531,7 +489,7 @@
 			}
 		}
 	}
-	return (0);
+	return 0;
 }
 
 int locks_mandatory_locked(struct inode *inode)
@@ -558,19 +516,16 @@
 			 size_t count)
 {
 	struct file_lock *fl;
-	struct file_lock tfl;
+	struct file_lock *new_fl = locks_alloc_lock();
 	int error;
 
-	memset(&tfl, 0, sizeof(tfl));
-
-	tfl.fl_file = filp;
-	tfl.fl_flags = FL_POSIX | FL_ACCESS;
-	tfl.fl_owner = current->files;
-	tfl.fl_pid = current->pid;
-	init_waitqueue_head(&tfl.fl_wait);
-	tfl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
-	tfl.fl_start = offset;
-	tfl.fl_end = offset + count - 1;
+	new_fl->fl_owner = current->files;
+	new_fl->fl_pid = current->pid;
+	new_fl->fl_file = filp;
+	new_fl->fl_flags = FL_POSIX | FL_ACCESS;
+	new_fl->fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
+	new_fl->fl_start = offset;
+	new_fl->fl_end = offset + count - 1;
 
 	error = 0;
 	lock_kernel();
@@ -588,7 +543,7 @@
 		/* Block for writes against a "read" lock,
 		 * and both reads and writes against a "write" lock.
 		 */
-		if (posix_locks_conflict(&tfl, fl)) {
+		if (posix_locks_conflict(new_fl, fl)) {
 			error = -EAGAIN;
 			if (filp && (filp->f_flags & O_NONBLOCK))
 				break;
@@ -596,12 +551,12 @@
 			if (signal_pending(current))
 				break;
 			error = -EDEADLK;
-			if (posix_locks_deadlock(&tfl, fl))
+			if (posix_locks_deadlock(new_fl, fl))
 				break;
 
-			locks_insert_block(fl, &tfl);
-			interruptible_sleep_on(&tfl.fl_wait);
-			locks_delete_block(fl, &tfl);
+			locks_insert_block(fl, new_fl);
+			interruptible_sleep_on(&new_fl->fl_wait);
+			locks_delete_block(new_fl);
 
 			/*
 			 * If we've been sleeping someone might have
@@ -613,6 +568,7 @@
 		}
 	}
 	unlock_kernel();
+	locks_free_lock(new_fl);
 	return error;
 }
 
@@ -620,7 +576,7 @@
  * the head of the list, but that's secret knowledge known only to the next
  * two functions.
  */
-static int flock_lock_file(struct file *filp, struct file_lock *caller,
+static int flock_lock_file(struct file *filp, unsigned int lock_type,
 			   unsigned int wait)
 {
 	struct file_lock *fl;
@@ -628,14 +584,14 @@
 	struct file_lock **before;
 	struct inode * inode = filp->f_dentry->d_inode;
 	int error, change;
-	int unlock = (caller->fl_type == F_UNLCK);
+	int unlock = (lock_type == F_UNLCK);
 
 	/*
 	 * If we need a new lock, get it in advance to avoid races.
 	 */
 	if (!unlock) {
 		error = -ENOLCK;
-		new_fl = locks_alloc_lock(caller);
+		new_fl = flock_make_lock(filp, lock_type);
 		if (!new_fl)
 			goto out;
 	}
@@ -645,8 +601,8 @@
 	change = 0;
 	before = &inode->i_flock;
 	while (((fl = *before) != NULL) && (fl->fl_flags & FL_FLOCK)) {
-		if (caller->fl_file == fl->fl_file) {
-			if (caller->fl_type == fl->fl_type)
+		if (filp == fl->fl_file) {
+			if (lock_type == fl->fl_type)
 				goto out;
 			change = 1;
 			break;
@@ -682,7 +638,7 @@
 			goto out;
 		locks_insert_block(fl, new_fl);
 		interruptible_sleep_on(&new_fl->fl_wait);
-		locks_delete_block(fl, new_fl);
+		locks_delete_block(new_fl);
 		goto repeat;
 	}
 	locks_insert_lock(&inode->i_flock, new_fl);
@@ -722,8 +678,8 @@
 	 * We may need two file_lock structures for this operation,
 	 * so we get them in advance to avoid races.
 	 */
-	new_fl  = locks_empty_lock();
-	new_fl2 = locks_empty_lock();
+	new_fl  = locks_alloc_lock();
+	new_fl2 = locks_alloc_lock();
 	error = -ENOLCK; /* "no luck" */
 	if (!(new_fl && new_fl2))
 		goto out;
@@ -746,7 +702,7 @@
 				goto out;
 			locks_insert_block(fl, caller);
 			interruptible_sleep_on(&caller->fl_wait);
-			locks_delete_block(fl, caller);
+			locks_delete_block(caller);
 			goto repeat;
   		}
   	}
@@ -852,7 +808,7 @@
 	if (!added) {
 		if (caller->fl_type == F_UNLCK)
 			goto out;
-		locks_init_lock(new_fl, caller);
+		locks_copy_lock(new_fl, caller);
 		locks_insert_lock(before, new_fl);
 		new_fl = NULL;
 	}
@@ -862,8 +818,9 @@
 			 * so we have to use the second new lock (in this
 			 * case, even F_UNLCK may fail!).
 			 */
-			left = locks_init_lock(new_fl2, right);
+			locks_copy_lock(new_fl2, right);
 			locks_insert_lock(before, left);
+			left = new_fl2;
 			new_fl2 = NULL;
 		}
 		right->fl_start = caller->fl_end + 1;
@@ -875,43 +832,58 @@
 	}
 out:
 	/*
-	 * Free any unused locks.  (They haven't
-	 * ever been used, so we use kfree().)
+	 * Free any unused locks.
 	 */
 	if (new_fl)
-		kfree(new_fl);
+		locks_free_lock(new_fl);
 	if (new_fl2)
-		kfree(new_fl2);
+		locks_free_lock(new_fl2);
 	return error;
 }
 
+static inline int flock_translate_cmd(int cmd) {
+	switch (cmd &~ LOCK_NB) {
+	case LOCK_SH:
+		return F_RDLCK;
+	case LOCK_EX:
+		return F_WRLCK;
+	case LOCK_UN:
+		return F_UNLCK;
+	}
+	return -EINVAL;
+}
+
 /* flock() system call entry point. Apply a FL_FLOCK style lock to
  * an open file descriptor.
  */
 asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
 {
-	struct file_lock file_lock;
 	struct file *filp;
-	int error;
+	int error, type;
 
-	lock_kernel();
 	error = -EBADF;
 	filp = fget(fd);
 	if (!filp)
 		goto out;
-	error = -EINVAL;
-	if (!flock_make_lock(filp, &file_lock, cmd))
+
+	error = flock_translate_cmd(cmd);
+	if (error < 0)
 		goto out_putf;
+	type = error;
+
 	error = -EBADF;
-	if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
+	if ((type != F_UNLCK) && !(filp->f_mode & 3))
 		goto out_putf;
-	error = flock_lock_file(filp, &file_lock,
+
+	lock_kernel();
+	error = flock_lock_file(filp, type,
 				(cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+	unlock_kernel();
+
 out_putf:
 	fput(filp);
 out:
-	unlock_kernel();
-	return (error);
+	return error;
 }
 
 /* Report the first existing lock that would conflict with l.
@@ -920,7 +892,7 @@
 int fcntl_getlk(unsigned int fd, struct flock *l)
 {
 	struct file *filp;
-	struct file_lock *fl,file_lock;
+	struct file_lock *fl, *file_lock = locks_alloc_lock();
 	struct flock flock;
 	int error;
 
@@ -936,20 +908,20 @@
 	if (!filp)
 		goto out;
 
-	if (!posix_make_lock(filp, &file_lock, &flock))
+	if (!posix_make_lock(filp, file_lock, &flock))
 		goto out_putf;
 
 	if (filp->f_op->lock) {
-		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
+		error = filp->f_op->lock(filp, F_GETLK, file_lock);
 		if (error < 0)
 			goto out_putf;
 		else if (error == LOCK_USE_CLNT)
 		  /* Bypass for NFS with no locking - 2.0.36 compat */
-		  fl = posix_test_lock(filp, &file_lock);
+		  fl = posix_test_lock(filp, file_lock);
 		else
-		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
+		  fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock);
 	} else {
-		fl = posix_test_lock(filp, &file_lock);
+		fl = posix_test_lock(filp, file_lock);
 	}
  
 	flock.l_type = F_UNLCK;
@@ -968,6 +940,7 @@
 out_putf:
 	fput(filp);
 out:
+	locks_free_lock(file_lock);
 	return error;
 }
 
@@ -977,7 +950,7 @@
 int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
 {
 	struct file *filp;
-	struct file_lock file_lock;
+	struct file_lock *file_lock = locks_alloc_lock();
 	struct flock flock;
 	struct inode *inode;
 	int error;
@@ -1019,7 +992,7 @@
 	}
 
 	error = -EINVAL;
-	if (!posix_make_lock(filp, &file_lock, &flock))
+	if (!posix_make_lock(filp, file_lock, &flock))
 		goto out_putf;
 	
 	error = -EBADF;
@@ -1057,15 +1030,16 @@
 	}
 
 	if (filp->f_op->lock != NULL) {
-		error = filp->f_op->lock(filp, cmd, &file_lock);
+		error = filp->f_op->lock(filp, cmd, file_lock);
 		if (error < 0)
 			goto out_putf;
 	}
-	error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW);
+	error = posix_lock_file(filp, file_lock, cmd == F_SETLKW);
 
 out_putf:
 	fput(filp);
 out:
+	locks_free_lock(file_lock);
 	return error;
 }
 
@@ -1076,7 +1050,7 @@
 void locks_remove_posix(struct file *filp, fl_owner_t owner)
 {
 	struct inode * inode = filp->f_dentry->d_inode;
-	struct file_lock file_lock, *fl;
+	struct file_lock *fl;
 	struct file_lock **before;
 
 	/*
@@ -1086,19 +1060,8 @@
 	before = &inode->i_flock;
 	while ((fl = *before) != NULL) {
 		if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) {
-			int (*lock)(struct file *, int, struct file_lock *);
-			lock = filp->f_op->lock;
-			if (lock) {
-				file_lock = *fl;
-				file_lock.fl_type = F_UNLCK;
-			}
 			locks_delete_lock(before, 0);
-			if (lock) {
-				lock(filp, F_SETLK, &file_lock);
-				/* List may have changed: */
-				goto repeat;
-			}
-			continue;
+			goto repeat;
 		}
 		before = &fl->fl_next;
 	}
@@ -1142,15 +1105,15 @@
 void
 posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
 {
+	lock_kernel();
 	locks_insert_block(blocker, waiter);
-	return;
+	unlock_kernel();
 }
 
 void
 posix_unblock_lock(struct file_lock *waiter)
 {
-	if (waiter->fl_prevblock)
-		locks_delete_block(waiter->fl_prevblock, waiter);
+	locks_delete_block(waiter);
 	return;
 }
 
@@ -1177,8 +1140,8 @@
 		     kdevname(inode->i_dev), inode->i_ino,
 		     (long long)fl->fl_start, (long long)fl->fl_end);
 	sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n",
-		(long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
-		(long)fl->fl_next, (long)fl->fl_nextblock);
+		(long)fl, (long)fl->fl_link.prev, (long)fl->fl_link.next,
+		(long)fl->fl_next, (long)fl->fl_block.next);
 }
 
 static void move_lock_status(char **p, off_t* pos, off_t offset)
@@ -1205,35 +1168,43 @@
 
 int get_locks_status(char *buffer, char **start, off_t offset, int length)
 {
-	struct file_lock *fl;
-	struct file_lock *bfl;
+	struct list_head *tmp;
 	char *q = buffer;
 	off_t pos = 0;
-	int i;
+	int i = 0;
 
-	for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
-		lock_get_status(q, fl, i, "");
+	lock_kernel();
+	list_for_each(tmp, &file_lock_list) {
+		struct list_head *btmp;
+		struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
+		lock_get_status(q, fl, ++i, "");
 		move_lock_status(&q, &pos, offset);
 
 		if(pos >= offset+length)
 			goto done;
 
-		if ((bfl = fl->fl_nextblock) == NULL)
-			continue;
-		do {
+		list_for_each(btmp, &fl->fl_block) {
+			struct file_lock *bfl = list_entry(btmp,
+					struct file_lock, fl_block);
 			lock_get_status(q, bfl, i, " ->");
 			move_lock_status(&q, &pos, offset);
 
 			if(pos >= offset+length)
 				goto done;
-		} while ((bfl = bfl->fl_nextblock) != fl);
+		}
 	}
 done:
+	unlock_kernel();
 	*start = buffer;
 	if(q-buffer < length)
 		return (q-buffer);
 	return length;
 }
 
-
-
+void __init filelock_init(void)
+{
+	filelock_cache = kmem_cache_create("file lock cache",
+			sizeof(struct file_lock), 0, 0, init_once, NULL);
+	if (!filelock_cache)
+		panic("cannot create file lock slab cache");
+}
diff -urNX ../kernels/exclude ../kernels/linux-ac13/include/linux/fs.h linux-ac13+lock/include/linux/fs.h
--- ../kernels/linux-ac13/include/linux/fs.h	Sun Jun 11 01:45:35 2000
+++ linux-ac13+lock/include/linux/fs.h	Sun Jun 11 02:13:19 2000
@@ -522,10 +522,8 @@
 
 struct file_lock {
 	struct file_lock *fl_next;	/* singly linked list for this inode  */
-	struct file_lock *fl_nextlink;	/* doubly linked list of all locks */
-	struct file_lock *fl_prevlink;	/* used to simplify lock removal */
-	struct file_lock *fl_nextblock; /* circular list of blocked processes */
-	struct file_lock *fl_prevblock;
+	struct list_head fl_link;	/* doubly linked list of all locks */
+	struct list_head fl_block; /* circular list of blocked processes */
 	fl_owner_t fl_owner;
 	unsigned int fl_pid;
 	wait_queue_head_t fl_wait;
@@ -550,7 +548,7 @@
 #define OFFSET_MAX	INT_LIMIT(loff_t)
 #endif
 
-extern struct file_lock			*file_lock_table;
+extern struct list_head file_lock_list;
 
 #include <linux/fcntl.h>
 
diff -urNX ../kernels/exclude ../kernels/linux-ac13/init/main.c linux-ac13+lock/init/main.c
--- ../kernels/linux-ac13/init/main.c	Sun Jun 11 01:45:43 2000
+++ linux-ac13+lock/init/main.c	Sun Jun 11 05:50:13 2000
@@ -97,6 +97,7 @@
 extern void bdev_init(void);
 extern int init_pcmcia_ds(void);
 extern int usb_init(void);
+extern void filelock_init(void);
 
 extern void free_initmem(void);
 extern void filesystem_setup(void);
@@ -588,6 +589,7 @@
 	bdev_init();
 	inode_init(mempages);
 	file_table_init();
+	filelock_init();
 #if defined(CONFIG_SYSVIPC)
 	ipc_init();
 #endif
diff -urNX ../kernels/exclude ../kernels/linux-ac13/kernel/ksyms.c linux-ac13+lock/kernel/ksyms.c
--- ../kernels/linux-ac13/kernel/ksyms.c	Sun Jun 11 01:45:43 2000
+++ linux-ac13+lock/kernel/ksyms.c	Sun Jun 11 02:06:58 2000
@@ -207,7 +207,7 @@
 EXPORT_SYMBOL(generic_buffer_fdatasync);
 EXPORT_SYMBOL(page_hash_bits);
 EXPORT_SYMBOL(page_hash_table);
-EXPORT_SYMBOL(file_lock_table);
+EXPORT_SYMBOL(file_lock_list);
 EXPORT_SYMBOL(posix_lock_file);
 EXPORT_SYMBOL(posix_test_lock);
 EXPORT_SYMBOL(posix_block_lock);
