diff -urpNX dontdiff linux-2.5.52/fs/lockd/clntproc.c linux-2.5.52-flock/fs/lockd/clntproc.c
--- linux-2.5.52/fs/lockd/clntproc.c    2002-11-17 23:29:21.000000000 -0500
+++ linux-2.5.52-flock/fs/lockd/clntproc.c      2002-12-18 14:03:18.000000000 -0500
@@ -401,12 +401,11 @@ nlmclnt_test(struct nlm_rqst *req, struc
       return 0;
}

-static
void nlmclnt_insert_lock_callback(struct file_lock *fl)
{
       nlm_get_host(fl->fl_u.nfs_fl.host);
}
-static
+
void nlmclnt_remove_lock_callback(struct file_lock *fl)
{
       if (fl->fl_u.nfs_fl.host) {
@@ -462,8 +461,6 @@ nlmclnt_lock(struct nlm_rqst *req, struc
               fl->fl_u.nfs_fl.state = host->h_state;
               fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
               fl->fl_u.nfs_fl.host = host;
-               fl->fl_insert = nlmclnt_insert_lock_callback;
-               fl->fl_remove = nlmclnt_remove_lock_callback;
       }

       return nlm_stat_to_errno(resp->status);
diff -urpNX dontdiff linux-2.5.52/fs/lockd/svclock.c linux-2.5.52-flock/fs/lockd/svclock.c
--- linux-2.5.52/fs/lockd/svclock.c     2002-11-17 23:29:29.000000000 -0500
+++ linux-2.5.52-flock/fs/lockd/svclock.c       2002-12-18 14:23:35.000000000 -0500
@@ -293,7 +293,6 @@ u32
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
                       struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
{
-       struct file_lock        *conflock;
       struct nlm_block        *block;
       int                     error;

@@ -312,59 +311,57 @@ nlmsvc_lock(struct svc_rqst *rqstp, stru
       block = nlmsvc_lookup_block(file, lock, 0);

       lock->fl.fl_flags |= FL_LOCKD;
+       if (wait)
+               lock->fl.fl_flags |= FL_SLEEP;

-again:
-       if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
-               error = posix_lock_file(&file->f_file, &lock->fl);
+       error = vfs_setlock_posix(&file->f_file, &lock->fl);
+       dprintk("lockd: vfs_setlock_posix returned %d\n", -error);
+       if ((error != -EAGAIN) || !wait)
+               goto out;

-               if (block)
-                       nlmsvc_delete_block(block, 0);
-               up(&file->f_sema);
-
-               dprintk("lockd: posix_lock_file returned %d\n", -error);
-               switch(-error) {
-               case 0:
-                       return nlm_granted;
-               case EDEADLK:
-                       return nlm_deadlock;
-               case EAGAIN:
-                       return nlm_lck_denied;
-               default:                        /* includes ENOLCK */
-                       return nlm_lck_denied_nolocks;
+       /* If we don't have a block, create and initialize it. */
+       if (!block) {
+               dprintk("lockd: blocking on this lock (allocating).\n");
+               block = nlmsvc_create_block(rqstp, file, lock, cookie);
+               if (!block) {
+                       error = -ENOLCK;
+                       goto out;
               }
       }

-       if (!wait) {
-               up(&file->f_sema);
-               return nlm_lck_denied;
-       }
+       /* Append to list of blocked locks */
+       nlmsvc_insert_block(block, NLM_NEVER);

-       if (posix_locks_deadlock(&lock->fl, conflock)) {
-               up(&file->f_sema);
-               return nlm_deadlock;
+       /*
+        * There's a race a mile wide there.  vfs_setlock_posix() adds us
+        * to the blocked list, but we may have just slept to allocate
+        * memory.  So check to see whether we're still blocked and issue
+        * a wakeup if we're not.
+        */
+       if (!lock->fl.fl_next) {
+               nlmsvc_insert_block(block, 0);
+               svc_wake_up(block->b_daemon);
       }
+       block = NULL;

-       /* If we don't have a block, create and initialize it. Then
-        * retry because we may have slept in kmalloc. */
-       if (block == NULL) {
-               dprintk("lockd: blocking on this lock (allocating).\n");
-               if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
-                       return nlm_lck_denied_nolocks;
-               goto again;
-       }
+ out:
+       up(&file->f_sema);

-       /* Append to list of blocked */
-       nlmsvc_insert_block(block, NLM_NEVER);
+       if (block)
+               nlmsvc_delete_block(block, 0);

-       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");
-               posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
+       if (!error) {
+               return nlm_granted;
+       } else if (error == -EDEADLK) {
+               return nlm_deadlock;
+       } else if (error == -EAGAIN) {
+               if (wait)
+                       return nlm_lck_blocked;
+               else
+                       return nlm_lck_denied;
+       } else {
+               return nlm_lck_denied_nolocks;
       }
-
-       up(&file->f_sema);
-       return nlm_lck_blocked;
}

/*
@@ -374,8 +371,6 @@ u32
nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
                                      struct nlm_lock *conflock)
{
-       struct file_lock        *fl;
-
       dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
                               file->f_file.f_dentry->d_inode->i_sb->s_id,
                               file->f_file.f_dentry->d_inode->i_ino,
@@ -383,13 +378,15 @@ nlmsvc_testlock(struct nlm_file *file, s
                               (long long)lock->fl.fl_start,
                               (long long)lock->fl.fl_end);

-       if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
+       conflock->fl = lock->fl;        /* a struct copy */
+       vfs_testlock_posix(&file->f_file, &conflock->fl);
+       if (conflock->fl.fl_type != F_UNLCK) {
               dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
-                               fl->fl_type, (long long)fl->fl_start,
-                               (long long)fl->fl_end);
+                               conflock->fl.fl_type,
+                               (long long)conflock->fl.fl_start,
+                               (long long)conflock->fl.fl_end);
               conflock->caller = "somehost";  /* FIXME */
               conflock->oh.len = 0;           /* don't return OH info */
-               conflock->fl = *fl;
               return nlm_lck_denied;
       }

@@ -419,7 +416,7 @@ nlmsvc_unlock(struct nlm_file *file, str
       nlmsvc_cancel_blocked(file, lock);

       lock->fl.fl_type = F_UNLCK;
-       error = posix_lock_file(&file->f_file, &lock->fl);
+       error = vfs_setlock_posix(&file->f_file, &lock->fl);

       return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
}
@@ -490,7 +487,6 @@ nlmsvc_grant_blocked(struct nlm_block *b
{
       struct nlm_file         *file = block->b_file;
       struct nlm_lock         *lock = &block->b_call.a_args.lock;
-       struct file_lock        *conflock;
       int                     error;

       dprintk("lockd: grant blocked lock %p\n", block);
@@ -506,32 +502,13 @@ nlmsvc_grant_blocked(struct nlm_block *b
        * binding */
       if (block->b_granted) {
               nlm_rebind_host(block->b_host);
-               goto callback;
-       }
-
-       /* Try the lock operation again */
-       if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
-               /* Bummer, we blocked again */
-               dprintk("lockd: lock still blocked\n");
-               nlmsvc_insert_block(block, NLM_NEVER);
-               posix_block_lock(conflock, &lock->fl);
-               up(&file->f_sema);
-               return;
-       }
-
-       /* Alright, no conflicting lock. Now lock it for real. If the
-        * following yields an error, this is most probably due to low
-        * memory. Retry the lock in a few seconds.
-        */
-       if ((error = posix_lock_file(&file->f_file, &lock->fl)) < 0) {
-               printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
-                               -error, __FUNCTION__);
-               nlmsvc_insert_block(block, 10 * HZ);
-               up(&file->f_sema);
-               return;
+       } else {
+               /* Try the lock operation again */
+               error = vfs_setlock_posix(&file->f_file, &lock->fl);
+               if (error)
+                       goto err;
       }

-callback:
       /* Lock was granted by VFS. */
       dprintk("lockd: GRANTing blocked lock.\n");
       block->b_granted = 1;
@@ -546,6 +523,18 @@ callback:
                                               nlmsvc_grant_callback) < 0)
               nlm_release_host(block->b_call.a_host);
       up(&file->f_sema);
+       return;
+
+ err:
+       dprintk("lockd: blocked lock retry returned %d\n", error);
+       if (error == -EAGAIN) {
+               /* We actually blocked, so go back to sleep */
+               nlmsvc_insert_block(block, NLM_NEVER);
+       } else {
+               /* Some other error.  We must retry later. */
+               nlmsvc_insert_block(block, 10 * HZ);
+       }
+       up(&file->f_sema);
}

/*
diff -urpNX dontdiff linux-2.5.52/fs/lockd/svcsubs.c linux-2.5.52-flock/fs/lockd/svcsubs.c
--- linux-2.5.52/fs/lockd/svcsubs.c     2002-11-17 23:29:48.000000000 -0500
+++ linux-2.5.52-flock/fs/lockd/svcsubs.c       2002-12-18 14:03:18.000000000 -0500
@@ -176,7 +176,7 @@ again:
                       lock.fl_type  = F_UNLCK;
                       lock.fl_start = 0;
                       lock.fl_end   = OFFSET_MAX;
-                       if (posix_lock_file(&file->f_file, &lock) < 0) {
+                       if (vfs_setlock_posix(&file->f_file, &lock) < 0) {
                               printk("lockd: unlock failure in %s:%d\n",
                                               __FILE__, __LINE__);
                               return 1;
diff -urpNX dontdiff linux-2.5.52/fs/locks.c linux-2.5.52-flock/fs/locks.c
--- linux-2.5.52/fs/locks.c     2002-12-18 14:00:37.000000000 -0500
+++ linux-2.5.52-flock/fs/locks.c       2002-12-18 14:09:44.000000000 -0500
@@ -114,17 +114,18 @@
 *  Stephen Rothwell <[email protected]>, June, 2000.
 */

-#include <linux/slab.h>
-#include <linux/file.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
#include <linux/capability.h>
-#include <linux/timer.h>
-#include <linux/time.h>
+#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/sched.h>
#include <linux/security.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/wait.h>

-#include <asm/semaphore.h>
#include <asm/uaccess.h>

#define IS_POSIX(fl)   (fl->fl_flags & FL_POSIX)
@@ -188,8 +189,6 @@ void locks_init_lock(struct file_lock *f
       fl->fl_type = 0;
       fl->fl_start = fl->fl_end = 0;
       fl->fl_notify = NULL;
-       fl->fl_insert = NULL;
-       fl->fl_remove = NULL;
}

/*
@@ -220,8 +219,6 @@ void locks_copy_lock(struct file_lock *n
       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;
}

@@ -322,8 +319,6 @@ static int flock_to_posix_lock(struct fi
       fl->fl_file = filp;
       fl->fl_flags = FL_POSIX;
       fl->fl_notify = NULL;
-       fl->fl_insert = NULL;
-       fl->fl_remove = NULL;

       return assign_type(fl, l->l_type);
}
@@ -362,8 +357,6 @@ static int flock64_to_posix_lock(struct
       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:
@@ -398,8 +391,6 @@ static int lease_alloc(struct file *filp
       fl->fl_start = 0;
       fl->fl_end = OFFSET_MAX;
       fl->fl_notify = NULL;
-       fl->fl_insert = NULL;
-       fl->fl_remove = NULL;

       *flp = fl;
       return 0;
@@ -475,14 +466,17 @@ static void locks_wake_up_blocks(struct
 */
static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
{
+       struct lock_operations *l_op = NULL;
       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);
+       if (fl->fl_file->f_op)
+               l_op = fl->fl_file->f_op->lock;
+       if (l_op && l_op->lock_insert)
+               l_op->lock_insert(fl);
}

/*
@@ -494,6 +488,7 @@ static void locks_insert_lock(struct fil
static void locks_delete_lock(struct file_lock **thisfl_p)
{
       struct file_lock *fl = *thisfl_p;
+       struct lock_operations *l_op = NULL;

       *thisfl_p = fl->fl_next;
       fl->fl_next = NULL;
@@ -505,8 +500,10 @@ static void locks_delete_lock(struct fil
               fl->fl_fasync = NULL;
       }

-       if (fl->fl_remove)
-               fl->fl_remove(fl);
+       if (fl->fl_file->f_op)
+               l_op = fl->fl_file->f_op->lock;
+       if (l_op && l_op->lock_remove)
+               l_op->lock_remove(fl);

       locks_wake_up_blocks(fl);
       locks_free_lock(fl);
@@ -593,8 +590,15 @@ static int locks_block_on_timeout(struct
       return result;
}

-struct file_lock *
-posix_test_lock(struct file *filp, struct file_lock *fl)
+/**
+ * posix_test_lock - finds a conflicting lock
+ * @filp: the file to search
+ * @fl: the template to check
+ *
+ * This function overwrites @fl with any lock which overlaps it and is
+ * owned by a different task.
+ */
+static void posix_test_lock(struct file *filp, struct file_lock *fl)
{
       struct file_lock *cfl;

@@ -602,12 +606,13 @@ posix_test_lock(struct file *filp, struc
       for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
               if (!IS_POSIX(cfl))
                       continue;
-               if (posix_locks_conflict(cfl, fl))
-                       break;
+               if (!posix_locks_conflict(cfl, fl))
+                       continue;
+
+               *fl = *cfl;
+               break;
       }
       unlock_kernel();
-
-       return (cfl);
}

/* This function tests for deadlock condition before putting a process to
@@ -624,7 +629,7 @@ posix_test_lock(struct file *filp, struc
 * from a broken NFS client. But broken NFS clients have a lot more to
 * worry about than proper deadlock detection anyway... --okir
 */
-int posix_locks_deadlock(struct file_lock *caller_fl,
+static int posix_locks_deadlock(struct file_lock *caller_fl,
                               struct file_lock *block_fl)
{
       struct list_head *tmp;
@@ -652,63 +657,6 @@ next_task:
       return 0;
}

-int locks_mandatory_locked(struct inode *inode)
-{
-       fl_owner_t owner = current->files;
-       struct file_lock *fl;
-
-       /*
-        * Search the lock list for this inode for any POSIX locks.
-        */
-       lock_kernel();
-       for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-               if (!IS_POSIX(fl))
-                       continue;
-               if (fl->fl_owner != owner)
-                       break;
-       }
-       unlock_kernel();
-       return fl ? -EAGAIN : 0;
-}
-
-int locks_mandatory_area(int read_write, struct inode *inode,
-                        struct file *filp, loff_t offset,
-                        size_t count)
-{
-       struct file_lock fl;
-       int error;
-
-       fl.fl_owner = current->files;
-       fl.fl_pid = current->tgid;
-       fl.fl_file = filp;
-       fl.fl_flags = FL_POSIX | FL_ACCESS | FL_SLEEP;
-       fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
-       fl.fl_start = offset;
-       fl.fl_end = offset + count - 1;
-
-       for (;;) {
-               error = posix_lock_file(filp, &fl);
-               if (error != -EAGAIN)
-                       break;
-               error = wait_event_interruptible(fl.fl_wait, !fl.fl_next);
-               if (!error) {
-                       /*
-                        * If we've been sleeping someone might have
-                        * changed the permissions behind our back.
-                        */
-                       if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-                               continue;
-               }
-
-               lock_kernel();
-               locks_delete_block(&fl);
-               unlock_kernel();
-               break;
-       }
-
-       return error;
-}
-
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
 * at the head of the list, but that's secret knowledge known only to
 * flock_lock_file and posix_lock_file.
@@ -788,7 +736,7 @@ out:
 * To all purists: Yes, I use a few goto's. Just pass on to the next function.
 */

-int posix_lock_file(struct file *filp, struct file_lock *request)
+static int posix_lock_file(struct file *filp, struct file_lock *request)
{
       struct file_lock *fl;
       struct file_lock *new_fl, *new_fl2;
@@ -1103,6 +1051,63 @@ out:
       return error;
}

+int locks_mandatory_locked(struct inode *inode)
+{
+       fl_owner_t owner = current->files;
+       struct file_lock *fl;
+
+       /*
+        * Search the lock list for this inode for any POSIX locks.
+        */
+       lock_kernel();
+       for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+               if (!IS_POSIX(fl))
+                       continue;
+               if (fl->fl_owner != owner)
+                       break;
+       }
+       unlock_kernel();
+       return fl ? -EAGAIN : 0;
+}
+
+int locks_mandatory_area(int read_write, struct inode *inode,
+                        struct file *filp, loff_t offset,
+                        size_t count)
+{
+       struct file_lock fl;
+       int error;
+
+       fl.fl_owner = current->files;
+       fl.fl_pid = current->tgid;
+       fl.fl_file = filp;
+       fl.fl_flags = FL_POSIX | FL_ACCESS | FL_SLEEP;
+       fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
+       fl.fl_start = offset;
+       fl.fl_end = offset + count - 1;
+
+       for (;;) {
+               error = posix_lock_file(filp, &fl);
+               if (error != -EAGAIN)
+                       break;
+               error = wait_event_interruptible(fl.fl_wait, !fl.fl_next);
+               if (!error) {
+                       /*
+                        * If we've been sleeping someone might have
+                        * changed the permissions behind our back.
+                        */
+                       if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+                               continue;
+               }
+
+               lock_kernel();
+               locks_delete_block(&fl);
+               unlock_kernel();
+               break;
+       }
+
+       return error;
+}
+
/**
 *     lease_get_mtime
 *     @inode: the inode
@@ -1328,12 +1333,95 @@ asmlinkage long sys_flock(unsigned int f
       return error;
}

+/**
+ * vfs_setlock_posix - apply a POSIX lock to a file
+ * @filp: the file to apply the lock to
+ * @fl: the lock to apply
+ *
+ * This function contains the common code to apply a lock to a file.
+ * It's called by the 32- and 64- bit versions of fcntl_setlk and lockd.
+ * If the underlying filesystem provides a locking method, we call that.
+ * Otherwise we lock locally.
+ */
+int vfs_setlock_posix(struct file *filp, struct file_lock *fl)
+{
+       struct lock_operations *l_op = NULL;
+       int (*lock_file)(struct file *, struct file_lock *) = posix_lock_file;
+       int error;
+
+       switch (fl->fl_type) {
+       case F_RDLCK:
+               if (!(filp->f_mode & FMODE_READ))
+                       return -EBADF;
+               break;
+       case F_WRLCK:
+               if (!(filp->f_mode & FMODE_WRITE))
+                       return -EBADF;
+               break;
+       case F_UNLCK:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       error = security_file_lock(filp, fl->fl_type);
+       if (error)
+               return error;
+
+       if (filp->f_op)
+               l_op = filp->f_op->lock;
+       if (l_op && l_op->set_lock)
+               lock_file = l_op->set_lock;
+
+       for (;;) {
+               error = lock_file(filp, fl);
+               if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
+                       break;
+               if (fl->fl_flags & FL_LOCKD)
+                       break;
+               error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
+               if (!error)
+                       continue;
+
+               lock_kernel();
+               locks_delete_block(fl);
+               unlock_kernel();
+               break;
+       }
+
+       return error;
+}
+
+/**
+ * vfs_testlock_posix - Report any conflicting lock
+ * @filp: the file to examine
+ * @fl: The lock to report any conflicts against
+ *
+ * This function contains the common code to test for conflicting locks.
+ * It's called by the 32- and 64- bit versions of fcntl getlk and by lockd.
+ * Note that this is an inherently racy interface and the only reason to use
+ * it is to implement the user interface.  In-kernel users should attempt to
+ * apply the lock and deal with the failure.
+ */
+void vfs_testlock_posix(struct file *filp, struct file_lock *fl)
+{
+       struct lock_operations *l_op = NULL;
+
+       if (filp->f_op)
+               l_op = filp->f_op->lock;
+       if (l_op && l_op->get_lock) {
+               l_op->get_lock(filp, fl);
+       } else {
+               posix_test_lock(filp, fl);
+       }
+}
+
/* Report the first existing lock that would conflict with l.
 * This implements the F_GETLK command of fcntl().
 */
int fcntl_getlk(struct file *filp, struct flock *l)
{
-       struct file_lock *fl, file_lock;
+       struct file_lock file_lock;
       struct flock flock;
       int error;

@@ -1344,49 +1432,38 @@ int fcntl_getlk(struct file *filp, struc
       if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
               goto out;

+       locks_init_lock(&file_lock);
       error = flock_to_posix_lock(filp, &file_lock, &flock);
       if (error)
               goto out;

-       if (filp->f_op && filp->f_op->lock) {
-               error = filp->f_op->lock(filp, F_GETLK, &file_lock);
-               if (error < 0)
-                       goto out;
-               else if (error == LOCK_USE_CLNT)
-                 /* Bypass for NFS with no locking - 2.0.36 compat */
-                 fl = posix_test_lock(filp, &file_lock);
-               else
-                 fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
-       } else {
-               fl = posix_test_lock(filp, &file_lock);
-       }
+       vfs_testlock_posix(filp, &file_lock);

-       flock.l_type = F_UNLCK;
-       if (fl != NULL) {
-               flock.l_pid = fl->fl_pid;
+       flock.l_type = file_lock.fl_type;
+       if (flock.l_type != F_UNLCK) {
#if BITS_PER_LONG == 32
               /*
                * Make sure we can represent the posix lock via
                * legacy 32bit flock.
                */
               error = -EOVERFLOW;
-               if (fl->fl_start > OFFT_OFFSET_MAX)
+               if (file_lock.fl_start > OFFT_OFFSET_MAX)
                       goto out;
-               if ((fl->fl_end != OFFSET_MAX)
-                   && (fl->fl_end > OFFT_OFFSET_MAX))
+               if ((file_lock.fl_end != OFFSET_MAX)
+                   && (file_lock.fl_end > OFFT_OFFSET_MAX))
                       goto out;
#endif
-               flock.l_start = fl->fl_start;
-               flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
-                       fl->fl_end - fl->fl_start + 1;
+               flock.l_pid = file_lock.fl_pid;
+               flock.l_start = file_lock.fl_start;
+               flock.l_len = file_lock.fl_end == OFFSET_MAX ? 0 :
+                       file_lock.fl_end - file_lock.fl_start + 1;
               flock.l_whence = 0;
-               flock.l_type = fl->fl_type;
       }
       error = -EFAULT;
       if (!copy_to_user(l, &flock, sizeof(flock)))
               error = 0;

-out:
+ out:
       return error;
}

@@ -1395,14 +1472,11 @@ out:
 */
int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock *l)
{
-       struct file_lock *file_lock = locks_alloc_lock(0);
+       struct file_lock file_lock;
       struct flock flock;
       struct inode *inode;
       int error;

-       if (file_lock == NULL)
-               return -ENOLCK;
-
       /*
        * This might block, so we do it before checking the inode.
        */
@@ -1425,57 +1499,17 @@ int fcntl_setlk(struct file *filp, unsig
               }
       }

-       error = flock_to_posix_lock(filp, file_lock, &flock);
+       locks_init_lock(&file_lock);
+       error = flock_to_posix_lock(filp, &file_lock, &flock);
       if (error)
               goto out;
       if (cmd == F_SETLKW) {
-               file_lock->fl_flags |= FL_SLEEP;
+               file_lock.fl_flags |= FL_SLEEP;
       }
-
-       error = -EBADF;
-       switch (flock.l_type) {
-       case F_RDLCK:
-               if (!(filp->f_mode & FMODE_READ))
-                       goto out;
-               break;
-       case F_WRLCK:
-               if (!(filp->f_mode & FMODE_WRITE))
-                       goto out;
-               break;
-       case F_UNLCK:
-               break;
-       default:
-               error = -EINVAL;
-               goto out;
-       }
-
-       error = security_file_lock(filp, file_lock->fl_type);
-       if (error)
-               goto out;
-
-       if (filp->f_op && filp->f_op->lock != NULL) {
-               error = filp->f_op->lock(filp, cmd, file_lock);
-               if (error < 0)
-                       goto out;
-       }
-
-       for (;;) {
-               error = posix_lock_file(filp, file_lock);
-               if ((error != -EAGAIN) || (cmd == F_SETLK))
-                       break;
-               error = wait_event_interruptible(file_lock->fl_wait,
-                               !file_lock->fl_next);
-               if (!error)
-                       continue;

-               lock_kernel();
-               locks_delete_block(file_lock);
-               unlock_kernel();
-               break;
-       }
+       error = vfs_setlock_posix(filp, &file_lock);

 out:
-       locks_free_lock(file_lock);
       return error;
}

@@ -1485,7 +1519,7 @@ int fcntl_setlk(struct file *filp, unsig
 */
int fcntl_getlk64(struct file *filp, struct flock64 *l)
{
-       struct file_lock *fl, file_lock;
+       struct file_lock file_lock;
       struct flock64 flock;
       int error;

@@ -1496,31 +1530,20 @@ int fcntl_getlk64(struct file *filp, str
       if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
               goto out;

+       locks_init_lock(&file_lock);
       error = flock64_to_posix_lock(filp, &file_lock, &flock);
       if (error)
               goto out;

-       if (filp->f_op && filp->f_op->lock) {
-               error = filp->f_op->lock(filp, F_GETLK, &file_lock);
-               if (error < 0)
-                       goto out;
-               else if (error == LOCK_USE_CLNT)
-                 /* Bypass for NFS with no locking - 2.0.36 compat */
-                 fl = posix_test_lock(filp, &file_lock);
-               else
-                 fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
-       } else {
-               fl = posix_test_lock(filp, &file_lock);
-       }
+       vfs_testlock_posix(filp, &file_lock);

-       flock.l_type = F_UNLCK;
-       if (fl != NULL) {
-               flock.l_pid = fl->fl_pid;
-               flock.l_start = fl->fl_start;
-               flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
-                       fl->fl_end - fl->fl_start + 1;
+       flock.l_type = file_lock.fl_type;
+       if (flock.l_type != F_UNLCK) {
+               flock.l_pid = file_lock.fl_pid;
+               flock.l_start = file_lock.fl_start;
+               flock.l_len = file_lock.fl_end == OFFSET_MAX ? 0 :
+                       file_lock.fl_end - file_lock.fl_start + 1;
               flock.l_whence = 0;
-               flock.l_type = fl->fl_type;
       }
       error = -EFAULT;
       if (!copy_to_user(l, &flock, sizeof(flock)))
@@ -1535,14 +1558,11 @@ out:
 */
int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 *l)
{
-       struct file_lock *file_lock = locks_alloc_lock(0);
+       struct file_lock file_lock;
       struct flock64 flock;
       struct inode *inode;
       int error;

-       if (file_lock == NULL)
-               return -ENOLCK;
-
       /*
        * This might block, so we do it before checking the inode.
        */
@@ -1565,57 +1585,16 @@ int fcntl_setlk64(struct file *filp, uns
               }
       }

-       error = flock64_to_posix_lock(filp, file_lock, &flock);
+       error = flock64_to_posix_lock(filp, &file_lock, &flock);
       if (error)
               goto out;
       if (cmd == F_SETLKW64) {
-               file_lock->fl_flags |= FL_SLEEP;
-       }
-
-       error = -EBADF;
-       switch (flock.l_type) {
-       case F_RDLCK:
-               if (!(filp->f_mode & FMODE_READ))
-                       goto out;
-               break;
-       case F_WRLCK:
-               if (!(filp->f_mode & FMODE_WRITE))
-                       goto out;
-               break;
-       case F_UNLCK:
-               break;
-       default:
-               error = -EINVAL;
-               goto out;
-       }
-
-       error = security_file_lock(filp, file_lock->fl_type);
-       if (error)
-               goto out;
-
-       if (filp->f_op && filp->f_op->lock != NULL) {
-               error = filp->f_op->lock(filp, cmd, file_lock);
-               if (error < 0)
-                       goto out;
+               file_lock.fl_flags |= FL_SLEEP;
       }

-       for (;;) {
-               error = posix_lock_file(filp, file_lock);
-               if ((error != -EAGAIN) || (cmd == F_SETLK64))
-                       break;
-               error = wait_event_interruptible(file_lock->fl_wait,
-                               !file_lock->fl_next);
-               if (!error)
-                       continue;
-
-               lock_kernel();
-               locks_delete_block(file_lock);
-               unlock_kernel();
-               break;
-       }
+       error = vfs_setlock_posix(filp, &file_lock);

-out:
-       locks_free_lock(file_lock);
+ out:
       return error;
}
#endif /* BITS_PER_LONG == 32 */
@@ -1627,30 +1606,34 @@ out:
 */
void locks_remove_posix(struct file *filp, fl_owner_t owner)
{
-       struct file_lock lock;
+       struct file_lock *fl, **before;
+       struct lock_operations *l_op = NULL;
+       struct inode *inode = filp->f_dentry->d_inode;

       /*
-        * If there are no locks held on this file, we don't need to call
-        * posix_lock_file().  Another process could be setting a lock on this
-        * file at the same time, but we wouldn't remove that lock anyway.
+        * If there are no locks held on this file, we don't need to do
+        * anything.  Another thread could be setting a lock on this
+        * file at the same time, but it's a race we just won.
        */
-       if (!filp->f_dentry->d_inode->i_flock)
+       if (!inode->i_flock)
               return;

-       lock.fl_type = F_UNLCK;
-       lock.fl_flags = FL_POSIX;
-       lock.fl_start = 0;
-       lock.fl_end = OFFSET_MAX;
-       lock.fl_owner = owner;
-       lock.fl_pid = current->tgid;
-       lock.fl_file = filp;
-
-       if (filp->f_op && filp->f_op->lock != NULL) {
-               filp->f_op->lock(filp, F_SETLK, &lock);
-               /* Ignore any error -- we must remove the locks anyway */
+       if (filp->f_op)
+               l_op = filp->f_op->lock;
+       if (l_op && l_op->remove_posix) {
+               l_op->remove_posix(filp, owner);
+       } else {
+               lock_kernel();
+               before = &inode->i_flock;
+               while ((fl = *before) != NULL) {
+                       if (IS_POSIX(fl) && fl->fl_owner == owner) {
+                               locks_delete_lock(before);
+                               continue;
+                       }
+                       before = &fl->fl_next;
+               }
+               unlock_kernel();
       }
-
-       posix_lock_file(filp, &lock);
}

/*
diff -urpNX dontdiff linux-2.5.52/fs/nfs/file.c linux-2.5.52-flock/fs/nfs/file.c
--- linux-2.5.52/fs/nfs/file.c  2002-11-17 23:29:49.000000000 -0500
+++ linux-2.5.52-flock/fs/nfs/file.c    2002-12-18 14:03:18.000000000 -0500
@@ -40,20 +40,6 @@ static ssize_t nfs_file_write(struct kio
static int  nfs_file_flush(struct file *);
static int  nfs_fsync(struct file *, struct dentry *dentry, int datasync);

-struct file_operations nfs_file_operations = {
-       .llseek         = remote_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read               = nfs_file_read,
-       .aio_write              = nfs_file_write,
-       .mmap           = nfs_file_mmap,
-       .open           = nfs_open,
-       .flush          = nfs_file_flush,
-       .release        = nfs_release,
-       .fsync          = nfs_fsync,
-       .lock           = nfs_lock,
-};
-
struct inode_operations nfs_file_inode_operations = {
       .permission     = nfs_permission,
       .getattr        = nfs_getattr,
@@ -239,10 +225,13 @@ nfs_lock(struct file *filp, int cmd, str
       if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
               return -ENOLCK;

-       /* Fake OK code if mounted without NLM support */
+       /* lock locally if mounted without NLM support */
       if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) {
-               if (IS_GETLK(cmd))
-                       status = LOCK_USE_CLNT;
+               if (IS_GETLK(cmd)) {
+                       vfs_testlock_posix(filp, fl);
+               } else {
+                       status = vfs_setlock_posix(filp, fl);
+               }
               goto out_ok;
       }

@@ -295,3 +284,52 @@ nfs_lock(struct file *filp, int cmd, str
       }
       return status;
}
+
+static int nfs_set_lock(struct file *filp, struct file_lock *fl)
+{
+       if (fl->fl_flags & FL_SLEEP) {
+               return nfs_lock(filp, F_SETLKW, fl);
+       } else {
+               return nfs_lock(filp, F_SETLK, fl);
+       }
+}
+
+static void nfs_get_lock(struct file *filp, struct file_lock *fl)
+{
+       int status = nfs_lock(filp, F_GETLK, fl);
+       if (status) {
+               fl->fl_type = F_UNLCK;
+       }
+}
+
+#if 0
+static int nfs_remove_posix(struct file *filp, fl_owner_t id)
+{
+       printk("remove posix support not yet implemented\n");
+}
+#endif
+
+extern void nlmclnt_insert_lock_callback(struct file_lock *fl);
+extern void nlmclnt_remove_lock_callback(struct file_lock *fl);
+
+static struct lock_operations nfs_client_lops = {
+       .set_lock =     nfs_set_lock,
+       .get_lock =     nfs_get_lock,
+/*     .remove_posix = nfs_remove_posix, */
+       .lock_insert =  nlmclnt_insert_lock_callback,
+       .lock_remove =  nlmclnt_remove_lock_callback,
+};
+
+struct file_operations nfs_file_operations = {
+       .llseek         = remote_llseek,
+       .read           = do_sync_read,
+       .write          = do_sync_write,
+       .aio_read       = nfs_file_read,
+       .aio_write      = nfs_file_write,
+       .mmap           = nfs_file_mmap,
+       .open           = nfs_open,
+       .flush          = nfs_file_flush,
+       .release        = nfs_release,
+       .fsync          = nfs_fsync,
+       .lock           = &nfs_client_lops,
+};
diff -urpNX dontdiff linux-2.5.52/include/linux/fs.h linux-2.5.52-flock/include/linux/fs.h
--- linux-2.5.52/include/linux/fs.h     2002-12-18 14:00:57.000000000 -0500
+++ linux-2.5.52-flock/include/linux/fs.h       2002-12-18 14:03:18.000000000 -0500
@@ -536,8 +536,6 @@ struct file_lock {
       loff_t fl_end;

       void (*fl_notify)(struct file_lock *);  /* unblock callback */
-       void (*fl_insert)(struct file_lock *);  /* lock insertion callback */
-       void (*fl_remove)(struct file_lock *);  /* lock removal callback */

       struct fasync_struct *  fl_fasync; /* for lease break notifications */
       unsigned long fl_break_time;    /* for nonblocking lease breaks */
@@ -567,13 +565,12 @@ extern int fcntl_setlk64(struct file *,
/* fs/locks.c */
extern void locks_init_lock(struct file_lock *);
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
+extern int vfs_setlock_posix(struct file *, struct file_lock *);
+extern void vfs_testlock_posix(struct file *, struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_flock(struct file *);
-extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
-extern int posix_lock_file(struct file *, struct file_lock *);
extern void posix_block_lock(struct file_lock *, struct file_lock *);
extern void posix_unblock_lock(struct file *, struct file_lock *);
-extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
extern int __break_lease(struct inode *inode, unsigned int flags);
extern void lease_get_mtime(struct inode *, struct timespec *time);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
@@ -731,6 +728,42 @@ typedef struct {

typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);

+/**
+ * struct lock_operations - filesystem hooks for file locking
+ *
+ * This struct is a work in progress.  It is intended to be per-filesystem;
+ * indeed it could be part of f_ops were it not pure bloat for non-network
+ * filesystems.  I suspect lock_insert and lock_remove are now unnecessary,
+ * but need feedback from FS maintainers.
+ *
+ * @set_lock:
+ *     Attempt to set a new lock.  BKL not held, may sleep.
+ * @get_lock:
+ *     Return any lock which would conflict with the incoming lock.
+ *     No locks held, may sleep.
+ * @remove_posix:
+ *     A process closed a file descriptor.  Any locks on this @filp owned
+ *     by @owner should be removed.  BKL not held, may sleep.
+ * @remove_flock:
+ *     This @filp has been closed.  All locks owned by this process should
+ *     be removed.  BKL not held, may sleep.
+ * @lock_insert:
+ *     Notification that @fl, which was previously blocked, is now being
+ *     inserted.  BKL might not be held.  Must not sleep.
+ * @lock_remove:
+ *     Notification that @fl, which was an active lock, is now being
+ *     removed from the @filp.  BKL might not be held.  Must not sleep.
+ */
+
+struct lock_operations {
+       int (*set_lock) (struct file *filp, struct file_lock *fl);
+       void (*get_lock) (struct file *filp, struct file_lock *fl);
+       void (*remove_posix) (struct file *filp, fl_owner_t owner);
+       void (*remove_flock) (struct file *filp);
+       void (*lock_insert) (struct file_lock *fl);
+       void (*lock_remove) (struct file_lock *fl);
+};
+
/*
 * NOTE:
 * read, write, poll, fsync, readv, writev can be called
@@ -754,7 +787,7 @@ struct file_operations {
       int (*fsync) (struct file *, struct dentry *, int datasync);
       int (*aio_fsync) (struct kiocb *, int datasync);
       int (*fasync) (int, struct file *, int);
-       int (*lock) (struct file *, int, struct file_lock *);
+       struct lock_operations *lock;
       ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
       ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
       ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
@@ -1002,11 +1035,6 @@ extern long do_mount(char *, char *, cha

extern int vfs_statfs(struct super_block *, struct statfs *);

-/* Return value for VFS lock functions - tells locks.c to lock conventionally
- * REALLY kosha for root NFS and nfs_lock
- */
-#define LOCK_USE_CLNT 1
-
#define FLOCK_VERIFY_READ  1
#define FLOCK_VERIFY_WRITE 2

diff -urpNX dontdiff linux-2.5.52/kernel/ksyms.c linux-2.5.52-flock/kernel/ksyms.c
--- linux-2.5.52/kernel/ksyms.c 2002-12-18 14:00:58.000000000 -0500
+++ linux-2.5.52-flock/kernel/ksyms.c   2002-12-18 14:03:18.000000000 -0500
@@ -232,11 +232,10 @@ EXPORT_SYMBOL(generic_ro_fops);
EXPORT_SYMBOL(file_lock_list);
EXPORT_SYMBOL(locks_init_lock);
EXPORT_SYMBOL(locks_copy_lock);
-EXPORT_SYMBOL(posix_lock_file);
-EXPORT_SYMBOL(posix_test_lock);
+EXPORT_SYMBOL(vfs_setlock_posix);
+EXPORT_SYMBOL(vfs_testlock_posix);
EXPORT_SYMBOL(posix_block_lock);
EXPORT_SYMBOL(posix_unblock_lock);
-EXPORT_SYMBOL(posix_locks_deadlock);
EXPORT_SYMBOL(locks_mandatory_area);
EXPORT_SYMBOL(dput);
EXPORT_SYMBOL(have_submounts);