diff -urpNX dontdiff linux-2.5.48/fs/lockd/clntproc.c linux-2.5.48-flock/fs/lockd/clntproc.c
--- linux-2.5.48/fs/lockd/clntproc.c	2002-11-17 23:29:21.000000000 -0500
+++ linux-2.5.48-flock/fs/lockd/clntproc.c	2002-11-19 18:38:39.000000000 -0500
@@ -462,8 +462,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);
@@ -689,3 +687,30 @@ nlm_stat_to_errno(u32 status)
 	printk(KERN_NOTICE "lockd: unexpected server status %d\n", status);
 	return -ENOLCK;
 }
+
+static int nlmclnt_set_lock(struct file *filp, struct file_lock *fl)
+{
+	if (fl->fl_flags & FL_SLEEP) {
+		nfs_lock(filp, F_SETLKW, fl);
+	} else {
+		nfs_lock(filp, F_SETLK, fl);
+	}
+}
+
+static int nlmclnt_get_lock(struct file *filp, struct file_lock *fl)
+{
+	nfs_lock(filp, F_GETLK, fl);
+}
+
+static int nlmclnt_remove_posix(struct file *filp, fl_owner_t id)
+{
+	printk("remove posix support not yet implemented\n");
+}
+
+struct lock_operations nfs_client_lops = {
+	.set_lock =	nlmclnt_set_lock,
+	.get_lock =	nlmclnt_get_lock,
+	.remove_posix =	nlmclnt_remove_posix,
+	.lock_insert =	nlmclnt_insert_lock_callback,
+	.lock_remove =	nlmclnt_remove_lock_callback,
+};
diff -urpNX dontdiff linux-2.5.48/fs/locks.c linux-2.5.48-flock/fs/locks.c
--- linux-2.5.48/fs/locks.c	2002-11-17 23:29:56.000000000 -0500
+++ linux-2.5.48-flock/fs/locks.c	2002-11-19 19:31:23.000000000 -0500
@@ -187,8 +187,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;
 }
 
 /*
@@ -219,8 +217,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;
 }
 
@@ -312,8 +308,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);
 }
@@ -352,8 +346,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:
@@ -388,8 +380,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;
@@ -465,14 +455,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);
 }
 
 /*
@@ -484,6 +477,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;
@@ -495,8 +489,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);
@@ -1324,6 +1320,7 @@ asmlinkage long sys_flock(unsigned int f
 int fcntl_getlk(struct file *filp, struct flock *l)
 {
 	struct file_lock *fl, file_lock;
+	struct lock_operations *l_op = NULL;
 	struct flock flock;
 	int error;
 
@@ -1338,15 +1335,13 @@ int fcntl_getlk(struct file *filp, struc
 	if (error)
 		goto out;
 
-	if (filp->f_op && filp->f_op->lock) {
-		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
+	if (filp->f_op)
+		l_op = filp->f_op->lock;
+	if (l_op && l_op->get_lock) {
+		error = l_op->get_lock(filp, &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);
+		fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
 	} else {
 		fl = posix_test_lock(filp, &file_lock);
 	}
@@ -1380,19 +1375,48 @@ out:
 	return error;
 }
 
+int vfs_setlock_posix(struct file *filp, struct file_lock *fl)
+{
+	struct lock_operations *l_op = NULL;
+	int error;
+
+	error = security_ops->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)
+		return l_op->set_lock(filp, fl);
+
+	for (;;) {
+		error = posix_lock_file(filp, fl);
+		if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
+			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;
+}
+
 /* Apply the lock described by l to an open file descriptor.
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
 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.
 	 */
@@ -1417,11 +1441,12 @@ int fcntl_setlk(struct file *filp, unsig
 	}
 #endif
 
-	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;
@@ -1441,33 +1466,9 @@ int fcntl_setlk(struct file *filp, unsig
 		goto out;
 	}
 
-	error = security_ops->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;
 }
 
@@ -1478,6 +1479,7 @@ int fcntl_setlk(struct file *filp, unsig
 int fcntl_getlk64(struct file *filp, struct flock64 *l)
 {
 	struct file_lock *fl, file_lock;
+	struct lock_operations *l_op = NULL;
 	struct flock64 flock;
 	int error;
 
@@ -1492,15 +1494,13 @@ int fcntl_getlk64(struct file *filp, str
 	if (error)
 		goto out;
 
-	if (filp->f_op && filp->f_op->lock) {
-		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
+	if (filp->f_op)
+		l_op = filp->f_op->lock;
+	if (l_op && l_op->get_lock) {
+		error = l_op->get_lock(filp, &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);
+		fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
 	} else {
 		fl = posix_test_lock(filp, &file_lock);
 	}
@@ -1527,14 +1527,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.
 	 */
@@ -1544,6 +1541,7 @@ int fcntl_setlk64(struct file *filp, uns
 
 	inode = filp->f_dentry->d_inode;
 
+#ifdef CONFIG_MMU
 	/* Don't allow mandatory locks on files that may be memory mapped
 	 * and shared.
 	 */
@@ -1556,12 +1554,13 @@ int fcntl_setlk64(struct file *filp, uns
 			goto out;
 		}
 	}
+#endif
 
-	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;
+		file_lock.fl_flags |= FL_SLEEP;
 	}
 	
 	error = -EBADF;
@@ -1581,33 +1580,9 @@ int fcntl_setlk64(struct file *filp, uns
 		goto out;
 	}
 
-	error = security_ops->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_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 */
@@ -1619,30 +1594,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.48/include/linux/fs.h linux-2.5.48-flock/include/linux/fs.h
--- linux-2.5.48/include/linux/fs.h	2002-11-17 23:29:29.000000000 -0500
+++ linux-2.5.48-flock/include/linux/fs.h	2002-11-19 19:24:41.000000000 -0500
@@ -540,8 +540,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 */
@@ -734,6 +732,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);
+	int (*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
@@ -757,7 +791,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 *);
