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)