From: Ken Preslan <kpreslan@redhat.com>

On Mon, Aug 30, 2004 at 07:05:29PM -0400, Trond Myklebust wrote:
> ...
> Firstly, it would be nice to throw out the existing wait loop in
> sys_flock(), and replace it with a call to this new
> flock_lock_file_wait(). I suppose that can be done in a separate cleanup
> patch, though...
> ... 
> One solution that I've already suggested to Ken & co is to use a
> separate f_op->flock() call. That would be my preference, since the
> filesystems have to treat flock and posix locks differently anyway.
> ...

Thanks for the suggestions.  Below is a patch that implements both of
them.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/locks.c         |   28 ++++++++--------------------
 25-akpm/include/linux/fs.h |    1 +
 2 files changed, 9 insertions(+), 20 deletions(-)

diff -puN fs/locks.c~allow-cluster-wide-flock-update fs/locks.c
--- 25/fs/locks.c~allow-cluster-wide-flock-update	2004-09-02 21:05:16.450700032 -0700
+++ 25-akpm/fs/locks.c	2004-09-02 21:05:16.457698968 -0700
@@ -1392,24 +1392,12 @@ asmlinkage long sys_flock(unsigned int f
 	if (error)
 		goto out_free;
 
-	if (filp->f_op && filp->f_op->lock) {
-		error = filp->f_op->lock(filp,
-					(can_sleep) ? F_SETLKW : F_SETLK,
-					lock);
-		goto out_free;
-	}
-
-	for (;;) {
-		error = flock_lock_file(filp, lock);
-		if ((error != -EAGAIN) || !can_sleep)
-			break;
-		error = wait_event_interruptible(lock->fl_wait, !lock->fl_next);
-		if (!error)
-			continue;
-
-		locks_delete_block(lock);
-		break;
-	}
+	if (filp->f_op && filp->f_op->flock)
+		error = filp->f_op->flock(filp,
+					  (can_sleep) ? F_SETLKW : F_SETLK,
+					  lock);
+	else
+		error = flock_lock_file_wait(filp, lock);
 
  out_free:
 	if (list_empty(&lock->fl_link)) {
@@ -1766,10 +1754,10 @@ void locks_remove_flock(struct file *fil
 	if (!inode->i_flock)
 		return;
 
-	if (filp->f_op && filp->f_op->lock) {
+	if (filp->f_op && filp->f_op->flock) {
 		struct file_lock fl = { .fl_flags = FL_FLOCK,
 					.fl_type = F_UNLCK };
-		filp->f_op->lock(filp, F_SETLKW, &fl);
+		filp->f_op->flock(filp, F_SETLKW, &fl);
 	}
 
 	lock_kernel();
diff -puN include/linux/fs.h~allow-cluster-wide-flock-update include/linux/fs.h
--- 25/include/linux/fs.h~allow-cluster-wide-flock-update	2004-09-02 21:05:16.452699728 -0700
+++ 25-akpm/include/linux/fs.h	2004-09-02 21:05:16.459698664 -0700
@@ -983,6 +983,7 @@ struct file_operations {
 	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 	int (*check_flags)(int);
 	int (*dir_notify)(struct file *filp, unsigned long arg);
+	int (*flock) (struct file *, int, struct file_lock *);
 };
 
 struct inode_operations {
_