From: Trond Myklebust <Trond.Myklebust@netapp.com>

This makes for an interesting situation in which programs compiled to use
flock() and running on the server will not see the locks that are set by the
clients.  The clients will, however, see both POSIX and flock() locks set by
other clients.

It is the best you can do, given the limitations of the protocol.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/lockd/clntproc.c    |   26 ++++++++++++++---
 25-akpm/fs/nfs/file.c          |   61 +++++++++++++++++++++++++++++++++++------
 25-akpm/fs/nfs/nfs4proc.c      |   23 ++++++++++++++-
 25-akpm/include/linux/nfs_fs.h |    5 ---
 4 files changed, 95 insertions(+), 20 deletions(-)

diff -puN fs/lockd/clntproc.c~nfs-flock fs/lockd/clntproc.c
--- 25/fs/lockd/clntproc.c~nfs-flock	2005-01-23 01:19:54.282025296 -0800
+++ 25-akpm/fs/lockd/clntproc.c	2005-01-23 01:19:54.291023928 -0800
@@ -516,6 +516,24 @@ static void nlmclnt_locks_init_private(s
 	fl->fl_ops = &nlmclnt_lock_ops;
 }
 
+static void do_vfs_lock(struct file_lock *fl)
+{
+	int res = 0;
+	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+		case FL_POSIX:
+			res = posix_lock_file_wait(fl->fl_file, fl);
+			break;
+		case FL_FLOCK:
+			res = flock_lock_file_wait(fl->fl_file, fl);
+			break;
+		default:
+			BUG();
+	}
+	if (res < 0)
+		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+				__FUNCTION__);
+}
+
 /*
  * LOCK: Try to create a lock
  *
@@ -564,9 +582,7 @@ 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_flags |= FL_SLEEP;
-		if (posix_lock_file_wait(fl->fl_file, fl) < 0)
-				printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
-						__FUNCTION__);
+		do_vfs_lock(fl);
 	}
 	status = nlm_stat_to_errno(resp->status);
 out:
@@ -635,7 +651,7 @@ nlmclnt_unlock(struct nlm_rqst *req, str
 					nlmclnt_unlock_callback);
 		/* Hrmf... Do the unlock early since locks_remove_posix()
 		 * really expects us to free the lock synchronously */
-		posix_lock_file(fl->fl_file, fl);
+		do_vfs_lock(fl);
 		if (status < 0) {
 			nlmclnt_release_lockargs(req);
 			kfree(req);
@@ -648,7 +664,7 @@ nlmclnt_unlock(struct nlm_rqst *req, str
 	if (status < 0)
 		return status;
 
-	posix_lock_file(fl->fl_file, fl);
+	do_vfs_lock(fl);
 	if (resp->status == NLM_LCK_GRANTED)
 		return 0;
 
diff -puN fs/nfs/file.c~nfs-flock fs/nfs/file.c
--- 25/fs/nfs/file.c~nfs-flock	2005-01-23 01:19:54.283025144 -0800
+++ 25-akpm/fs/nfs/file.c	2005-01-23 01:19:54.292023776 -0800
@@ -44,6 +44,8 @@ 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);
 static int nfs_check_flags(int flags);
+static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
+static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
 
 struct file_operations nfs_file_operations = {
 	.llseek		= remote_llseek,
@@ -57,6 +59,7 @@ struct file_operations nfs_file_operatio
 	.release	= nfs_file_release,
 	.fsync		= nfs_fsync,
 	.lock		= nfs_lock,
+	.flock		= nfs_flock,
 	.sendfile	= nfs_file_sendfile,
 	.check_flags	= nfs_check_flags,
 };
@@ -312,6 +315,25 @@ static int do_getlk(struct file *filp, i
 	return status;
 }
 
+static int do_vfs_lock(struct file *file, struct file_lock *fl)
+{
+	int res = 0;
+	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+		case FL_POSIX:
+			res = posix_lock_file_wait(file, fl);
+			break;
+		case FL_FLOCK:
+			res = flock_lock_file_wait(file, fl);
+			break;
+		default:
+			BUG();
+	}
+	if (res < 0)
+		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+				__FUNCTION__);
+	return res;
+}
+
 static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
 {
 	struct inode *inode = filp->f_mapping->host;
@@ -338,7 +360,7 @@ static int do_unlk(struct file *filp, in
 	if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
 		status = NFS_PROTO(inode)->lock(filp, cmd, fl);
 	else
-		status = posix_lock_file_wait(filp, fl);
+		status = do_vfs_lock(filp, fl);
 	unlock_kernel();
 	rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);
 	return status;
@@ -377,9 +399,9 @@ static int do_setlk(struct file *filp, i
 		 * the process exits.
 		 */
 		if (status == -EINTR || status == -ERESTARTSYS)
-			posix_lock_file_wait(filp, fl);
+			do_vfs_lock(filp, fl);
 	} else
-		status = posix_lock_file_wait(filp, fl);
+		status = do_vfs_lock(filp, fl);
 	unlock_kernel();
 	if (status < 0)
 		goto out;
@@ -401,8 +423,7 @@ out:
 /*
  * Lock a (portion of) a file
  */
-int
-nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
+static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
 {
 	struct inode * inode = filp->f_mapping->host;
 
@@ -418,6 +439,27 @@ nfs_lock(struct file *filp, int cmd, str
 	if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
 		return -ENOLCK;
 
+	if (IS_GETLK(cmd))
+		return do_getlk(filp, cmd, fl);
+	if (fl->fl_type == F_UNLCK)
+		return do_unlk(filp, cmd, fl);
+	return do_setlk(filp, cmd, fl);
+}
+
+/*
+ * Lock a (portion of) a file
+ */
+static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
+{
+	struct inode * inode = filp->f_mapping->host;
+
+	dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n",
+			inode->i_sb->s_id, inode->i_ino,
+			fl->fl_type, fl->fl_flags);
+
+	if (!inode)
+		return -EINVAL;
+
 	/*
 	 * No BSD flocks over NFS allowed.
 	 * Note: we could try to fake a POSIX lock request here by
@@ -425,11 +467,14 @@ nfs_lock(struct file *filp, int cmd, str
 	 * Not sure whether that would be unique, though, or whether
 	 * that would break in other places.
 	 */
-	if (!fl->fl_owner || !(fl->fl_flags & FL_POSIX))
+	if (!(fl->fl_flags & FL_FLOCK))
 		return -ENOLCK;
 
-	if (IS_GETLK(cmd))
-		return do_getlk(filp, cmd, fl);
+	/* We're simulating flock() locks using posix locks on the server */
+	fl->fl_owner = (fl_owner_t)filp;
+	fl->fl_start = 0;
+	fl->fl_end = OFFSET_MAX;
+
 	if (fl->fl_type == F_UNLCK)
 		return do_unlk(filp, cmd, fl);
 	return do_setlk(filp, cmd, fl);
diff -puN fs/nfs/nfs4proc.c~nfs-flock fs/nfs/nfs4proc.c
--- 25/fs/nfs/nfs4proc.c~nfs-flock	2005-01-23 01:19:54.285024840 -0800
+++ 25-akpm/fs/nfs/nfs4proc.c	2005-01-23 01:19:54.295023320 -0800
@@ -2361,6 +2361,25 @@ static int nfs4_proc_getlk(struct nfs4_s
 	return err;
 }
 
+static int do_vfs_lock(struct file *file, struct file_lock *fl)
+{
+	int res = 0;
+	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+		case FL_POSIX:
+			res = posix_lock_file_wait(file, fl);
+			break;
+		case FL_FLOCK:
+			res = flock_lock_file_wait(file, fl);
+			break;
+		default:
+			BUG();
+	}
+	if (res < 0)
+		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+				__FUNCTION__);
+	return res;
+}
+
 static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
 	struct inode *inode = state->inode;
@@ -2408,7 +2427,7 @@ static int _nfs4_proc_unlck(struct nfs4_
 out:
 	up(&state->lock_sema);
 	if (status == 0)
-		posix_lock_file(request->fl_file, request);
+		do_vfs_lock(request->fl_file, request);
 	up_read(&clp->cl_sem);
 	return status;
 }
@@ -2517,7 +2536,7 @@ static int _nfs4_proc_setlk(struct nfs4_
 	if (status == 0) {
 		/* Note: we always want to sleep here! */
 		request->fl_flags |= FL_SLEEP;
-		if (posix_lock_file_wait(request->fl_file, request) < 0)
+		if (do_vfs_lock(request->fl_file, request) < 0)
 			printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
 	}
 	up_read(&clp->cl_sem);
diff -puN include/linux/nfs_fs.h~nfs-flock include/linux/nfs_fs.h
--- 25/include/linux/nfs_fs.h~nfs-flock	2005-01-23 01:19:54.287024536 -0800
+++ 25-akpm/include/linux/nfs_fs.h	2005-01-23 01:19:54.293023624 -0800
@@ -351,11 +351,6 @@ extern struct dentry_operations nfs_dent
 extern struct inode_operations nfs_symlink_inode_operations;
 
 /*
- * linux/fs/nfs/locks.c
- */
-extern int nfs_lock(struct file *, int, struct file_lock *);
-
-/*
  * linux/fs/nfs/unlink.c
  */
 extern int  nfs_async_unlink(struct dentry *);
_