diff -u linux-2.5.15-flock/fs/locks.c linux-2.5.15-flock/fs/locks.c
--- linux-2.5.15-flock/fs/locks.c	Tue May 21 21:45:51 2002
+++ linux-2.5.15-flock/fs/locks.c	Wed May 22 01:13:56 2002
@@ -419,13 +419,20 @@
 /* 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 *waiter)
+static inline void __locks_delete_block(struct file_lock *waiter)
 {
 	list_del_init(&waiter->fl_block);
 	list_del_init(&waiter->fl_link);
 	waiter->fl_next = NULL;
 }
 
+static void locks_delete_block(struct file_lock *waiter)
+{
+	spin_lock(&file_lock_lock);
+	__locks_delete_block(waiter);
+	spin_unlock(&file_lock_lock);
+}
+
 /* Insert waiter into blocker's block list.
  * We use a circular list so that processes can be easily woken up in
  * the order they blocked. The documentation doesn't require this but
@@ -438,7 +445,7 @@
 		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);
+		__locks_delete_block(waiter);
 	}
 	list_add_tail(&waiter->fl_block, &blocker->fl_block);
 	waiter->fl_next = blocker;
@@ -454,7 +461,7 @@
 	while (!list_empty(&blocker->fl_block)) {
 		struct file_lock *waiter = list_entry(blocker->fl_block.next,
 				struct file_lock, fl_block);
-		locks_delete_block(waiter);
+		__locks_delete_block(waiter);
 		if (waiter->fl_notify)
 			waiter->fl_notify(waiter);
 		else
@@ -600,7 +607,7 @@
 	int result;
 	locks_insert_block(blocker, waiter);
 	result = interruptible_sleep_on_locked(&waiter->fl_wait, 0);
-	locks_delete_block(waiter);
+	__locks_delete_block(waiter);
 	return result;
 }
 
@@ -609,7 +616,7 @@
 	int result;
 	locks_insert_block(blocker, waiter);
 	result = interruptible_sleep_on_locked(&waiter->fl_wait, time);
-	locks_delete_block(waiter);
+	__locks_delete_block(waiter);
 	return result;
 }
 
@@ -674,6 +681,26 @@
 	return 0;
 }
 
+/* This function takes no locks. */
+static int posix_find_conflict(struct inode *inode, struct file_lock *caller)
+{
+	struct file_lock **before;
+	for_each_lock(inode, before) {
+		struct file_lock *fl = *before;
+		if (!IS_POSIX(fl))
+			continue;
+		if (!posix_locks_conflict(caller, fl))
+			continue;
+		if (!(caller->fl_flags & FL_SLEEP))
+			return -EAGAIN;
+		if (posix_locks_deadlock(caller, fl))
+			return -EDEADLK;
+		locks_insert_block(fl, caller);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
 int locks_mandatory_locked(struct inode *inode)
 {
 	fl_owner_t owner = current->files;
@@ -697,7 +724,6 @@
 			 struct file *filp, loff_t offset,
 			 size_t count)
 {
-	struct file_lock **before;
 	struct file_lock *new_fl = locks_alloc_lock(0);
 	int error;
 
@@ -707,47 +733,37 @@
 	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_flags = FL_POSIX | FL_ACCESS | FL_SLEEP;
 	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;
-	spin_lock(&file_lock_lock);
 
-repeat:
-	/* Search the lock list for this inode for locks that conflict with
-	 * the proposed read/write.
-	 */
-	for_each_lock(inode, before) {
-		struct file_lock *fl = *before;
-		if (!IS_POSIX(fl))
-			continue;
-		if (fl->fl_start > new_fl->fl_end)
+	for (;;) {
+		spin_lock(&file_lock_lock);
+		error = posix_find_conflict(filp->f_dentry->d_inode, new_fl);
+		spin_unlock(&file_lock_lock);
+		if (error != -EAGAIN)
 			break;
-		if (!posix_locks_conflict(new_fl, fl))
-			continue;
+		error = wait_event_interruptible(new_fl->fl_wait, !new_fl->fl_next);
 
-		error = -EAGAIN;
-		if (filp && (filp->f_flags & O_NONBLOCK))
-			break;
-		error = -EDEADLK;
-		if (posix_locks_deadlock(new_fl, fl))
-			break;
-	
-		error = locks_block_on(fl, new_fl);
-		if (error != 0)
+		/* Permissions may have changed while we slept */
+		if ((inode->i_mode & (S_ISGID | S_IXGRP)) != S_ISGID) {
+			if (error) {
+				locks_delete_block(new_fl);
+			}
+			error = 0;
 			break;
+		}
 
-		/*
-		 * If we've been sleeping someone might have
-		 * changed the permissions behind our back.
-		 */
-		if ((inode->i_mode & (S_ISGID | S_IXGRP)) != S_ISGID)
-			break;
-		goto repeat;
+		if (!error)
+			continue;
+
+		locks_delete_block(new_fl);
+		break;
 	}
-	spin_unlock(&file_lock_lock);
+		
 	locks_free_lock(new_fl);
 	return error;
 }
@@ -801,7 +817,7 @@
 		}
 		goto out;
 	}
-	locks_insert_lock(&inode->i_flock, new_fl);
+	locks_insert_lock(before, new_fl);
 	error = 0;
 
 out:
@@ -903,22 +919,9 @@
 
 	spin_lock(&file_lock_lock);
 	if (caller->fl_type != F_UNLCK) {
-		for_each_lock(inode, before) {
-			struct file_lock *fl = *before;
-			if (!IS_POSIX(fl))
-				continue;
-			if (!posix_locks_conflict(caller, fl))
-				continue;
-			error = -EAGAIN;
-			if (!(caller->fl_flags & FL_SLEEP))
-				goto out;
-			error = -EDEADLK;
-			if (posix_locks_deadlock(caller, fl))
-				goto out;
-			error = -EAGAIN;
-			locks_insert_block(fl, caller);
+		error = posix_find_conflict(inode, caller);
+		if (error)
 			goto out;
-  		}
   	}
 
 	for_each_lock(inode, before) {
@@ -1247,9 +1250,7 @@
 		if (!error)
 			continue;
 
-		spin_lock(&file_lock_lock);
 		locks_delete_block(lock);
-		spin_unlock(&file_lock_lock);
 		break;
 	}
 
@@ -1397,9 +1398,7 @@
 		if (!error)
 			continue;
 
-		spin_lock(&file_lock_lock);
 		locks_delete_block(file_lock);
-		spin_unlock(&file_lock_lock);
 		break;
 	}
 
@@ -1532,9 +1531,7 @@
 		if (!error)
 			continue;
 
-		spin_lock(&file_lock_lock);
 		locks_delete_block(file_lock);
-		spin_unlock(&file_lock_lock);
 		break;
 	}
 
@@ -1603,7 +1600,9 @@
 void
 posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
 {
+	spin_lock(&file_lock_lock);
 	locks_insert_block(blocker, waiter);
+	spin_unlock(&file_lock_lock);
 }
 
 /**
@@ -1615,8 +1614,10 @@
 void
 posix_unblock_lock(struct file_lock *waiter)
 {
+	spin_lock(&file_lock_lock);
 	if (!list_empty(&waiter->fl_block))
-		locks_delete_block(waiter);
+		__locks_delete_block(waiter);
+	spin_unlock(&file_lock_lock);
 }
 
 static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
