All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/17] locks: trivial removal of unnecessary parentheses
       [not found] <117581646786-git-send-email->
@ 2007-04-05 23:40 ` J. Bruce Fields
       [not found] ` <11758164673642-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel, J. Bruce Fields

From: J. Bruce Fields <bfields@citi.umich.edu> - unquoted

Remove some unnecessary parentheses.

Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
---
 fs/locks.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index 52a8100..1a00b8b 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1738,7 +1738,7 @@ again:
 	else {
 		for (;;) {
 			error = posix_lock_file(filp, file_lock);
-			if ((error != -EAGAIN) || (cmd == F_SETLK))
+			if (error != -EAGAIN || cmd == F_SETLK)
 				break;
 			error = wait_event_interruptible(file_lock->fl_wait,
 					!file_lock->fl_next);
@@ -1881,7 +1881,7 @@ again:
 	else {
 		for (;;) {
 			error = posix_lock_file(filp, file_lock);
-			if ((error != -EAGAIN) || (cmd == F_SETLK64))
+			if (error != -EAGAIN || cmd == F_SETLK64)
 				break;
 			error = wait_event_interruptible(file_lock->fl_wait,
 					!file_lock->fl_next);
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 2/17] locks: create posix-to-flock helper functions
       [not found] ` <11758164673642-git-send-email->
@ 2007-04-05 23:40   ` J. Bruce Fields
       [not found]   ` <11758164671398-git-send-email->
  2007-04-06 10:30   ` [PATCH 1/17] locks: trivial removal of unnecessary parentheses Stephen Rothwell
  2 siblings, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel, J. Bruce Fields

From: J. Bruce Fields <bfields@citi.umich.edu> - unquoted

Factor out a bit of messy code by creating posix-to-flock counterparts
to the existing flock-to-posix helper functions.

Cc: Christoph Hellwig <hch@infradead.org>
Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
---
 fs/locks.c |   61 +++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 36 insertions(+), 25 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index 1a00b8b..957775b 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1611,6 +1611,38 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
 	return error;
 }
 
+static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
+{
+	flock->l_pid = fl->fl_pid;
+#if BITS_PER_LONG == 32
+	/*
+	 * Make sure we can represent the posix lock via
+	 * legacy 32bit flock.
+	 */
+	if (fl->fl_start > OFFT_OFFSET_MAX)
+		return -EOVERFLOW;
+	if (fl->fl_end != OFFSET_MAX && fl->fl_end > OFFT_OFFSET_MAX)
+		return -EOVERFLOW;
+#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_whence = 0;
+	return 0;
+}
+
+#if BITS_PER_LONG == 32
+static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
+{
+	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_whence = 0;
+	flock->l_type = fl->fl_type;
+}
+#endif
+
 /* Report the first existing lock that would conflict with l.
  * This implements the F_GETLK command of fcntl().
  */
@@ -1645,24 +1677,9 @@ int fcntl_getlk(struct file *filp, struct flock __user *l)
  
 	flock.l_type = F_UNLCK;
 	if (fl != NULL) {
-		flock.l_pid = fl->fl_pid;
-#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)
-			goto out;
-		if ((fl->fl_end != OFFSET_MAX)
-		    && (fl->fl_end > OFFT_OFFSET_MAX))
+		error = posix_lock_to_flock(&flock, fl);
+		if (error)
 			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_whence = 0;
-		flock.l_type = fl->fl_type;
 	}
 	error = -EFAULT;
 	if (!copy_to_user(l, &flock, sizeof(flock)))
@@ -1798,14 +1815,8 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
 	}
  
 	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_whence = 0;
-		flock.l_type = fl->fl_type;
-	}
+	if (fl != NULL)
+		posix_lock_to_flock64(&flock, fl);
 	error = -EFAULT;
 	if (!copy_to_user(l, &flock, sizeof(flock)))
 		error = 0;
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/17] locks: make ->lock release private data before returning in GETLK case
       [not found]   ` <11758164671398-git-send-email->
@ 2007-04-05 23:40     ` J. Bruce Fields
       [not found]     ` <11758164672114-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel, J. Bruce Fields

From: J. Bruce Fields <bfields@citi.umich.edu> - unquoted

The file_lock argument to ->lock is used to return the conflicting lock
when found.  There's no reason for the filesystem to return any private
information with this conflicting lock, but nfsv4 is.

Fix nfsv4 client, and modify locks.c to stop calling fl_release_private
for it in this case.

Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
---
 fs/locks.c        |    4 ----
 fs/nfs/nfs4proc.c |    2 ++
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index 957775b..b07e6e6 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1665,8 +1665,6 @@ int fcntl_getlk(struct file *filp, struct flock __user *l)
 
 	if (filp->f_op && filp->f_op->lock) {
 		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
-		if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
-			file_lock.fl_ops->fl_release_private(&file_lock);
 		if (error < 0)
 			goto out;
 		else
@@ -1804,8 +1802,6 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
 
 	if (filp->f_op && filp->f_op->lock) {
 		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
-		if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
-			file_lock.fl_ops->fl_release_private(&file_lock);
 		if (error < 0)
 			goto out;
 		else
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f52cf5c..d557a51 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3019,6 +3019,8 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
 			status = 0;
 	}
 out:
+	if (request->fl_ops)
+		request->fl_ops->fl_release_private(request);
 	up_read(&clp->cl_sem);
 	return status;
 }
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 4/17] locks: give posix_test_lock same interface as ->lock
       [not found]     ` <11758164672114-git-send-email->
@ 2007-04-05 23:40       ` J. Bruce Fields
       [not found]       ` <11758164672880-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel, J. Bruce Fields

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

posix_test_lock() and ->lock() do the same job but have gratuitously
different interfaces.  Modify posix_test_lock() so the two agree,
simplifying some code in the process.

Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
---
 fs/fuse/file.c                |    3 +--
 fs/gfs2/locking/nolock/main.c |    8 +-------
 fs/gfs2/ops_file.c            |    7 +------
 fs/lockd/svclock.c            |   13 ++++++++-----
 fs/locks.c                    |   37 ++++++++++++++++---------------------
 fs/nfs/file.c                 |    7 +------
 fs/nfsd/nfs4state.c           |    6 +++---
 include/linux/fs.h            |    2 +-
 8 files changed, 32 insertions(+), 51 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 2fd0692..acfad65 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -738,8 +738,7 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
 
 	if (cmd == F_GETLK) {
 		if (fc->no_lock) {
-			if (!posix_test_lock(file, fl, fl))
-				fl->fl_type = F_UNLCK;
+			posix_test_lock(file, fl);
 			err = 0;
 		} else
 			err = fuse_getlk(file, fl);
diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c
index acfbc94..5cc1dfa 100644
--- a/fs/gfs2/locking/nolock/main.c
+++ b/fs/gfs2/locking/nolock/main.c
@@ -164,13 +164,7 @@ static void nolock_unhold_lvb(void *lock, char *lvb)
 static int nolock_plock_get(void *lockspace, struct lm_lockname *name,
 			    struct file *file, struct file_lock *fl)
 {
-	struct file_lock tmp;
-	int ret;
-
-	ret = posix_test_lock(file, fl, &tmp);
-	fl->fl_type = F_UNLCK;
-	if (ret)
-		memcpy(fl, &tmp, sizeof(struct file_lock));
+	posix_test_lock(file, fl);
 
 	return 0;
 }
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index b50180e..48b248d 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -513,12 +513,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
 
 	if (sdp->sd_args.ar_localflocks) {
 		if (IS_GETLK(cmd)) {
-			struct file_lock tmp;
-			int ret;
-			ret = posix_test_lock(file, fl, &tmp);
-			fl->fl_type = F_UNLCK;
-			if (ret)
-				memcpy(fl, &tmp, sizeof(struct file_lock));
+			posix_test_lock(file, fl);
 			return 0;
 		} else {
 			return posix_lock_file_wait(file, fl);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index cf51f84..97b0160 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -426,15 +426,18 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
 				(long long)lock->fl.fl_start,
 				(long long)lock->fl.fl_end);
 
-	if (posix_test_lock(file->f_file, &lock->fl, &conflock->fl)) {
+	if (posix_test_lock(file->f_file, &lock->fl)) {
 		dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
-				conflock->fl.fl_type,
-				(long long)conflock->fl.fl_start,
-				(long long)conflock->fl.fl_end);
+				lock->fl.fl_type,
+				(long long)lock->fl.fl_start,
+				(long long)lock->fl.fl_end);
 		conflock->caller = "somehost";	/* FIXME */
 		conflock->len = strlen(conflock->caller);
 		conflock->oh.len = 0;		/* don't return OH info */
-		conflock->svid = conflock->fl.fl_pid;
+		conflock->svid = lock->fl.fl_pid;
+		conflock->fl.fl_type = lock->fl.fl_type;
+		conflock->fl.fl_start = lock->fl.fl_start;
+		conflock->fl.fl_end = lock->fl.fl_end;
 		return nlm_lck_denied;
 	}
 
diff --git a/fs/locks.c b/fs/locks.c
index b07e6e6..749a0dc 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -666,11 +666,11 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
 }
 
 int
-posix_test_lock(struct file *filp, struct file_lock *fl,
-		struct file_lock *conflock)
+posix_test_lock(struct file *filp, struct file_lock *fl)
 {
 	struct file_lock *cfl;
 
+	fl->fl_type = F_UNLCK;
 	lock_kernel();
 	for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
 		if (!IS_POSIX(cfl))
@@ -679,7 +679,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl,
 			break;
 	}
 	if (cfl) {
-		__locks_copy_lock(conflock, cfl);
+		__locks_copy_lock(fl, cfl);
 		unlock_kernel();
 		return 1;
 	}
@@ -1648,7 +1648,7 @@ static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
  */
 int fcntl_getlk(struct file *filp, struct flock __user *l)
 {
-	struct file_lock *fl, cfl, file_lock;
+	struct file_lock file_lock;
 	struct flock flock;
 	int error;
 
@@ -1667,15 +1667,12 @@ int fcntl_getlk(struct file *filp, struct flock __user *l)
 		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
 		if (error < 0)
 			goto out;
-		else
-		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
-	} else {
-		fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
-	}
+	} else
+		posix_test_lock(filp, &file_lock);
  
-	flock.l_type = F_UNLCK;
-	if (fl != NULL) {
-		error = posix_lock_to_flock(&flock, fl);
+	flock.l_type = file_lock.fl_type;
+	if (file_lock.fl_type != F_UNLCK) {
+		error = posix_lock_to_flock(&flock, &file_lock);
 		if (error)
 			goto out;
 	}
@@ -1785,7 +1782,7 @@ out:
  */
 int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
 {
-	struct file_lock *fl, cfl, file_lock;
+	struct file_lock file_lock;
 	struct flock64 flock;
 	int error;
 
@@ -1804,15 +1801,13 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
 		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
 		if (error < 0)
 			goto out;
-		else
-		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
-	} else {
-		fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
-	}
+	} else
+		posix_test_lock(filp, &file_lock);
  
-	flock.l_type = F_UNLCK;
-	if (fl != NULL)
-		posix_lock_to_flock64(&flock, fl);
+	flock.l_type = file_lock.fl_type;
+	if (file_lock.fl_type != F_UNLCK)
+		posix_lock_to_flock64(&flock, &file_lock);
+
 	error = -EFAULT;
 	if (!copy_to_user(l, &flock, sizeof(flock)))
 		error = 0;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 8e66b5a..5eaee6d 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -391,17 +391,12 @@ out_swapfile:
 
 static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
 {
-	struct file_lock cfl;
 	struct inode *inode = filp->f_mapping->host;
 	int status = 0;
 
 	lock_kernel();
 	/* Try local locking first */
-	if (posix_test_lock(filp, fl, &cfl)) {
-		fl->fl_start = cfl.fl_start;
-		fl->fl_end = cfl.fl_end;
-		fl->fl_type = cfl.fl_type;
-		fl->fl_pid = cfl.fl_pid;
+	if (posix_test_lock(filp, fl)) {
 		goto out;
 	}
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index af36070..e42c7a0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2813,7 +2813,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	struct inode *inode;
 	struct file file;
 	struct file_lock file_lock;
-	struct file_lock conflock;
 	__be32 status;
 
 	if (nfs4_in_grace())
@@ -2878,9 +2877,10 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	file.f_path.dentry = cstate->current_fh.fh_dentry;
 
 	status = nfs_ok;
-	if (posix_test_lock(&file, &file_lock, &conflock)) {
+	posix_test_lock(&file, &file_lock);
+	if (file_lock.fl_type != F_UNLCK) {
 		status = nfserr_denied;
-		nfs4_set_lock_denied(&conflock, &lockt->lt_denied);
+		nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
 	}
 out:
 	nfs4_unlock_state();
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 86ec3f4..9e1ddff 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -851,7 +851,7 @@ extern void locks_init_lock(struct file_lock *);
 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
 extern void locks_remove_posix(struct file *, fl_owner_t);
 extern void locks_remove_flock(struct file *);
-extern int posix_test_lock(struct file *, struct file_lock *, struct file_lock *);
+extern int posix_test_lock(struct file *, struct file_lock *);
 extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *);
 extern int posix_lock_file(struct file *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 5/17] locks: factor out generic/filesystem switch from test_lock
       [not found]       ` <11758164672880-git-send-email->
@ 2007-04-05 23:40         ` J. Bruce Fields
       [not found]         ` <1175816467294-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel, J. Bruce Fields

From: J. Bruce Fields <bfields@citi.umich.edu> - unquoted

Factor out the code that switches between generic and filesystem-specific lock
methods; eventually we want to call this from lock managers (lockd and nfsd)
too; currently they only call the generic methods.

This patch does that for test_lock.

Note that this hasn't been necessary until recently, because the few
filesystems that define ->lock() (nfs, cifs...) aren't exportable via NFS.
However GFS (and, in the future, other cluster filesystems) need to implement
their own locking to get cluster-coherent locking, and also want to be able to
export locking to NFS (lockd and NFSv4).

So we accomplish this by factoring out code such as this and exporting it for
the use of lockd and nfsd.

Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
---
 fs/locks.c         |   39 ++++++++++++++++++++++++++-------------
 include/linux/fs.h |    1 +
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index 749a0dc..dd279aa 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1611,6 +1611,25 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
 	return error;
 }
 
+/**
+ * vfs_test_lock - test file byte range lock
+ * @filp: The file to test lock for
+ * @fl: The lock to test
+ * @conf: Place to return a copy of the conflicting lock, if found
+ *
+ * Returns -ERRNO on failure.  Indicates presence of conflicting lock by
+ * setting conf->fl_type to something other than F_UNLCK.
+ */
+int vfs_test_lock(struct file *filp, struct file_lock *fl)
+{
+	fl->fl_type = F_UNLCK;
+	if (filp->f_op && filp->f_op->lock)
+		return filp->f_op->lock(filp, F_GETLK, fl);
+	posix_test_lock(filp, fl);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vfs_test_lock);
+
 static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
 {
 	flock->l_pid = fl->fl_pid;
@@ -1663,12 +1682,9 @@ int fcntl_getlk(struct file *filp, struct flock __user *l)
 	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
-		posix_test_lock(filp, &file_lock);
+	error = vfs_test_lock(filp, &file_lock);
+	if (error)
+		goto out;
  
 	flock.l_type = file_lock.fl_type;
 	if (file_lock.fl_type != F_UNLCK) {
@@ -1797,13 +1813,10 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
 	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
-		posix_test_lock(filp, &file_lock);
- 
+	error = vfs_test_lock(filp, &file_lock);
+	if (error)
+		goto out;
+
 	flock.l_type = file_lock.fl_type;
 	if (file_lock.fl_type != F_UNLCK)
 		posix_lock_to_flock64(&flock, &file_lock);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9e1ddff..2a2a439 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -856,6 +856,7 @@ extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_l
 extern int posix_lock_file(struct file *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern int posix_unblock_lock(struct file *, struct file_lock *);
+extern int vfs_test_lock(struct file *, struct file_lock *);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 6/17] locks: factor out generic/filesystem switch from setlock code
       [not found]         ` <1175816467294-git-send-email->
@ 2007-04-05 23:40           ` J. Bruce Fields
       [not found]           ` <11758164671240-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel, J. Bruce Fields

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Factor out the code that switches between generic and filesystem-specific lock
methods; eventually we want to call this from lock managers (lockd and nfsd)
too; currently they only call the generic methods.

This patch does that for all the setlk code.

Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
---
 fs/locks.c         |   68 +++++++++++++++++++++++++++------------------------
 include/linux/fs.h |    1 +
 2 files changed, 37 insertions(+), 32 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index dd279aa..f4f211e 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1699,6 +1699,21 @@ out:
 	return error;
 }
 
+/**
+ * vfs_lock_file - file byte range lock
+ * @filp: The file to apply the lock to
+ * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.)
+ * @fl: The lock to be applied
+ */
+int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl)
+{
+	if (filp->f_op && filp->f_op->lock)
+		return filp->f_op->lock(filp, cmd, fl);
+	else
+		return posix_lock_file(filp, fl);
+}
+EXPORT_SYMBOL_GPL(vfs_lock_file);
+
 /* Apply the lock described by l to an open file descriptor.
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
@@ -1761,21 +1776,17 @@ again:
 	if (error)
 		goto out;
 
-	if (filp->f_op && filp->f_op->lock != NULL)
-		error = filp->f_op->lock(filp, cmd, file_lock);
-	else {
-		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;
-
-			locks_delete_block(file_lock);
+	for (;;) {
+		error = vfs_lock_file(filp, cmd, file_lock);
+		if (error != -EAGAIN || cmd == F_SETLK)
 			break;
-		}
+		error = wait_event_interruptible(file_lock->fl_wait,
+				!file_lock->fl_next);
+		if (!error)
+			continue;
+
+		locks_delete_block(file_lock);
+		break;
 	}
 
 	/*
@@ -1891,21 +1902,17 @@ again:
 	if (error)
 		goto out;
 
-	if (filp->f_op && filp->f_op->lock != NULL)
-		error = filp->f_op->lock(filp, cmd, file_lock);
-	else {
-		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;
-
-			locks_delete_block(file_lock);
+	for (;;) {
+		error = vfs_lock_file(filp, cmd, file_lock);
+		if (error != -EAGAIN || cmd == F_SETLK64)
 			break;
-		}
+		error = wait_event_interruptible(file_lock->fl_wait,
+				!file_lock->fl_next);
+		if (!error)
+			continue;
+
+		locks_delete_block(file_lock);
+		break;
 	}
 
 	/*
@@ -1950,10 +1957,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
 	lock.fl_ops = NULL;
 	lock.fl_lmops = NULL;
 
-	if (filp->f_op && filp->f_op->lock != NULL)
-		filp->f_op->lock(filp, F_SETLK, &lock);
-	else
-		posix_lock_file(filp, &lock);
+	vfs_lock_file(filp, F_SETLK, &lock);
 
 	if (lock.fl_ops && lock.fl_ops->fl_release_private)
 		lock.fl_ops->fl_release_private(&lock);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2a2a439..1d5ccdd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -857,6 +857,7 @@ extern int posix_lock_file(struct file *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern int posix_unblock_lock(struct file *, struct file_lock *);
 extern int vfs_test_lock(struct file *, struct file_lock *);
+extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 7/17] locks: allow {vfs,posix}_lock_file to return conflicting lock
       [not found]           ` <11758164671240-git-send-email->
@ 2007-04-05 23:40             ` J. Bruce Fields
       [not found]             ` <11758164686-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel, J. Bruce Fields

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

The nfsv4 protocol's lock operation, in the case of a conflict, returns
information about the conflicting lock.

It's unclear how clients can use this, so for now we're not going so far as to
add a filesystem method that can return a conflicting lock, but we may as well
return something in the local case when it's easy to.

Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
---
 fs/lockd/svclock.c  |    6 +++---
 fs/lockd/svcsubs.c  |    2 +-
 fs/locks.c          |   38 +++++++++++++-------------------------
 fs/nfsd/nfs4state.c |   10 ++++++----
 include/linux/fs.h  |    5 ++---
 5 files changed, 25 insertions(+), 36 deletions(-)

diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 97b0160..3b0e7a4 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -363,7 +363,7 @@ again:
 	} else
 		lock = &block->b_call->a_args.lock;
 
-	error = posix_lock_file(file->f_file, &lock->fl);
+	error = posix_lock_file(file->f_file, &lock->fl, NULL);
 	lock->fl.fl_flags &= ~FL_SLEEP;
 
 	dprintk("lockd: posix_lock_file returned %d\n", error);
@@ -467,7 +467,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
 	nlmsvc_cancel_blocked(file, lock);
 
 	lock->fl.fl_type = F_UNLCK;
-	error = posix_lock_file(file->f_file, &lock->fl);
+	error = posix_lock_file(file->f_file, &lock->fl, NULL);
 
 	return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
 }
@@ -569,7 +569,7 @@ nlmsvc_grant_blocked(struct nlm_block *block)
 
 	/* Try the lock operation again */
 	lock->fl.fl_flags |= FL_SLEEP;
-	error = posix_lock_file(file->f_file, &lock->fl);
+	error = posix_lock_file(file->f_file, &lock->fl, NULL);
 	lock->fl.fl_flags &= ~FL_SLEEP;
 
 	switch (error) {
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index c0df00c..5095708 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -182,7 +182,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 (posix_lock_file(file->f_file, &lock, NULL) < 0) {
 				printk("lockd: unlock failure in %s:%d\n",
 						__FILE__, __LINE__);
 				return 1;
diff --git a/fs/locks.c b/fs/locks.c
index f4f211e..62aea08 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -801,7 +801,7 @@ out:
 	return error;
 }
 
-static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
+static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
 {
 	struct file_lock *fl;
 	struct file_lock *new_fl = NULL;
@@ -1007,6 +1007,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
  * posix_lock_file - Apply a POSIX-style lock to a file
  * @filp: The file to apply the lock to
  * @fl: The lock to be applied
+ * @conflock: Place to return a copy of the conflicting lock, if found.
  *
  * Add a POSIX style lock to a file.
  * We merge adjacent & overlapping locks whenever possible.
@@ -1016,26 +1017,12 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
  * whether or not a lock was successfully freed by testing the return
  * value for -ENOENT.
  */
-int posix_lock_file(struct file *filp, struct file_lock *fl)
-{
-	return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL);
-}
-EXPORT_SYMBOL(posix_lock_file);
-
-/**
- * posix_lock_file_conf - Apply a POSIX-style lock to a file
- * @filp: The file to apply the lock to
- * @fl: The lock to be applied
- * @conflock: Place to return a copy of the conflicting lock, if found.
- *
- * Except for the conflock parameter, acts just like posix_lock_file.
- */
-int posix_lock_file_conf(struct file *filp, struct file_lock *fl,
+int posix_lock_file(struct file *filp, struct file_lock *fl,
 			struct file_lock *conflock)
 {
-	return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock);
+	return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock);
 }
-EXPORT_SYMBOL(posix_lock_file_conf);
+EXPORT_SYMBOL(posix_lock_file);
 
 /**
  * posix_lock_file_wait - Apply a POSIX-style lock to a file
@@ -1051,7 +1038,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
 	int error;
 	might_sleep ();
 	for (;;) {
-		error = posix_lock_file(filp, fl);
+		error = posix_lock_file(filp, fl, NULL);
 		if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
 			break;
 		error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1123,7 +1110,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
 	fl.fl_end = offset + count - 1;
 
 	for (;;) {
-		error = __posix_lock_file_conf(inode, &fl, NULL);
+		error = __posix_lock_file(inode, &fl, NULL);
 		if (error != -EAGAIN)
 			break;
 		if (!(fl.fl_flags & FL_SLEEP))
@@ -1704,13 +1691,14 @@ out:
  * @filp: The file to apply the lock to
  * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.)
  * @fl: The lock to be applied
+ * @conf: Place to return a copy of the conflicting lock, if found.
  */
-int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl)
+int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
 {
 	if (filp->f_op && filp->f_op->lock)
 		return filp->f_op->lock(filp, cmd, fl);
 	else
-		return posix_lock_file(filp, fl);
+		return posix_lock_file(filp, fl, conf);
 }
 EXPORT_SYMBOL_GPL(vfs_lock_file);
 
@@ -1777,7 +1765,7 @@ again:
 		goto out;
 
 	for (;;) {
-		error = vfs_lock_file(filp, cmd, file_lock);
+		error = vfs_lock_file(filp, cmd, file_lock, NULL);
 		if (error != -EAGAIN || cmd == F_SETLK)
 			break;
 		error = wait_event_interruptible(file_lock->fl_wait,
@@ -1903,7 +1891,7 @@ again:
 		goto out;
 
 	for (;;) {
-		error = vfs_lock_file(filp, cmd, file_lock);
+		error = vfs_lock_file(filp, cmd, file_lock, NULL);
 		if (error != -EAGAIN || cmd == F_SETLK64)
 			break;
 		error = wait_event_interruptible(file_lock->fl_wait,
@@ -1957,7 +1945,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
 	lock.fl_ops = NULL;
 	lock.fl_lmops = NULL;
 
-	vfs_lock_file(filp, F_SETLK, &lock);
+	vfs_lock_file(filp, F_SETLK, &lock, NULL);
 
 	if (lock.fl_ops && lock.fl_ops->fl_release_private)
 		lock.fl_ops->fl_release_private(&lock);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e42c7a0..03b0578 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2657,6 +2657,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	struct file_lock conflock;
 	__be32 status = 0;
 	unsigned int strhashval;
+	unsigned int cmd;
 	int err;
 
 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
@@ -2739,10 +2740,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		case NFS4_READ_LT:
 		case NFS4_READW_LT:
 			file_lock.fl_type = F_RDLCK;
+			cmd = F_SETLK;
 		break;
 		case NFS4_WRITE_LT:
 		case NFS4_WRITEW_LT:
 			file_lock.fl_type = F_WRLCK;
+			cmd = F_SETLK;
 		break;
 		default:
 			status = nfserr_inval;
@@ -2769,9 +2772,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 	/* XXX?: Just to divert the locks_release_private at the start of
 	 * locks_copy_lock: */
-	conflock.fl_ops = NULL;
-	conflock.fl_lmops = NULL;
-	err = posix_lock_file_conf(filp, &file_lock, &conflock);
+	locks_init_lock(&conflock);
+	err = posix_lock_file(filp, &file_lock, &conflock);
 	switch (-err) {
 	case 0: /* success! */
 		update_stateid(&lock_stp->st_stateid);
@@ -2933,7 +2935,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	/*
 	*  Try to unlock the file in the VFS.
 	*/
-	err = posix_lock_file(filp, &file_lock);
+	err = posix_lock_file(filp, &file_lock, NULL);
 	if (err) {
 		dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
 		goto out_nfserr;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 1d5ccdd..c92d0bd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -852,12 +852,11 @@ extern void locks_copy_lock(struct file_lock *, struct file_lock *);
 extern void locks_remove_posix(struct file *, fl_owner_t);
 extern void locks_remove_flock(struct file *);
 extern int posix_test_lock(struct file *, struct file_lock *);
-extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *);
-extern int posix_lock_file(struct file *, struct file_lock *);
+extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern int posix_unblock_lock(struct file *, struct file_lock *);
 extern int vfs_test_lock(struct file *, struct file_lock *);
-extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *);
+extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 8/17] locks: add fl_notify arguments for asynchronous lock return
       [not found]             ` <11758164686-git-send-email->
@ 2007-04-05 23:40               ` J. Bruce Fields
       [not found]               ` <1175816468241-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Acquiring a lock on a cluster filesystem may require communication with remote
hosts, and to avoid blocking lockd or nfsd threads during such communication,
we allow the results to be returned asynchronously.

When a ->lock() call needs to block, the file system will return -EINPROGRESS,
and then later return the results with a call to the routine in the fl_notify
field of the lock_manager_operations struct.

Note that this is different from the ->lock() call discovering that there is a
conflict which would cause the caller to block; this is still handled in the
same way as before.  In fact, we don't currently handle "blocking" locks at
all; those are less urgent, because the filesystem can always just return an
immediate -EAGAIN without denying the lock.

So this asynchronous interface is only used in the case of a non-blocking lock,
where we must know whether to allow or deny the lock now.

We're using fl_notify to asynchronously return the result of a lock
request.  So we want fl_notify to be able to return a status and, if
appropriate, a conflicting lock.

This only current caller of fl_notify is in the blocked case, in which case
we don't use these extra arguments.

We also allow fl_notify to return an error.  (Also ignored for now.)

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/lockd/svclock.c |    7 ++++---
 fs/locks.c         |   21 ++++++++++++++++++++-
 include/linux/fs.h |    2 +-
 3 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 3b0e7a4..8c5c74f 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -509,12 +509,13 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
  * This function doesn't grant the blocked lock instantly, but rather moves
  * the block to the head of nlm_blocked where it can be picked up by lockd.
  */
-static void
-nlmsvc_notify_blocked(struct file_lock *fl)
+static int
+nlmsvc_notify_blocked(struct file_lock *fl, struct file_lock *conf, int result)
 {
 	struct nlm_block	*block;
 
-	dprintk("lockd: VFS unblock notification for block %p\n", fl);
+	dprintk("lockd: nlmsvc_notify_blocked lock %p conf %p result %d\n",
+							fl, conf, result);
 	list_for_each_entry(block, &nlm_blocked, b_list) {
 		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
 			nlmsvc_insert_block(block, 0);
diff --git a/fs/locks.c b/fs/locks.c
index 62aea08..485b38a 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -544,7 +544,7 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
 				struct file_lock, fl_block);
 		__locks_delete_block(waiter);
 		if (waiter->fl_lmops && waiter->fl_lmops->fl_notify)
-			waiter->fl_lmops->fl_notify(waiter);
+			waiter->fl_lmops->fl_notify(waiter, NULL, -EAGAIN);
 		else
 			wake_up(&waiter->fl_wait);
 	}
@@ -1692,6 +1692,25 @@ out:
  * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.)
  * @fl: The lock to be applied
  * @conf: Place to return a copy of the conflicting lock, if found.
+ *
+ * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX
+ * locks, the ->lock() interface may return asynchronously, before the lock has
+ * been granted or denied by the underlying filesystem, if (and only if)
+ * fl_notify is set. Callers expecting ->lock() to return asynchronously
+ * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if)
+ * the request is for a blocking lock. When ->lock() does return asynchronously,
+ * it must return -EINPROGRESS, and call ->fl_notify() when the lock
+ * request completes.
+ * If the request is for non-blocking lock the file system should return
+ * -EINPROGRESS then try to get the lock and call the callback routine with
+ * the result. If the request timed out the callback routine will return a
+ * nonzero return code and the file system should release the lock. The file
+ * system is also responsible to keep a corresponding posix lock when it
+ * grants a lock so the VFS can find out which locks are locally held and do
+ * the correct lock cleanup when required.
+ * The underlying filesystem must not drop the kernel lock or call
+ * ->fl_notify() before returning to the caller with a -EINPROGRESS
+ * return code.
  */
 int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
 {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c92d0bd..bec1dbe 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -784,7 +784,7 @@ struct file_lock_operations {
 
 struct lock_manager_operations {
 	int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
-	void (*fl_notify)(struct file_lock *);	/* unblock callback */
+	int (*fl_notify)(struct file_lock *, struct file_lock *, int);
 	void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
 	void (*fl_release_private)(struct file_lock *);
 	void (*fl_break)(struct file_lock *);
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 9/17] locks: add lock cancel command
       [not found]               ` <1175816468241-git-send-email->
@ 2007-04-05 23:40                 ` J. Bruce Fields
       [not found]                 ` <1175816468106-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:40 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel, J. Bruce Fields

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Lock managers need to be able to cancel pending lock requests.  In the case
where the exported filesystem manages its own locks, it's not sufficient just
to call posix_unblock_lock(); we need to let the filesystem know what's
happening too.

We do this by adding a new fcntl lock command: FL_CANCELLK.  Some day this
might also be made available to userspace applications that could benefit from
an asynchronous locking api.

Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
---
 fs/locks.c            |   17 +++++++++++++++++
 include/linux/fcntl.h |    4 ++++
 include/linux/fs.h    |    1 +
 3 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index 485b38a..68ae4d4 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2041,6 +2041,23 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter)
 
 EXPORT_SYMBOL(posix_unblock_lock);
 
+/**
+ * vfs_cancel_lock - file byte range unblock lock
+ * @filp: The file to apply the unblock to
+ * @fl: The lock to be unblocked
+ *
+ * Used by lock managers to cancel blocked requests
+ */
+int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
+{
+	if (filp->f_op && filp->f_op->lock)
+		return filp->f_op->lock(filp, F_CANCELLK, fl);
+	else
+		return posix_unblock_lock(filp, fl);
+}
+
+EXPORT_SYMBOL_GPL(vfs_cancel_lock);
+
 static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
 {
 	struct inode *inode = NULL;
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index 996f561..40b9326 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -3,6 +3,10 @@
 
 #include <asm/fcntl.h>
 
+/* Cancel a blocking posix lock; internal use only until we expose an
+ * asynchronous lock api to userspace: */
+#define F_CANCELLK	(F_LINUX_SPECIFIC_BASE+5)
+
 #define F_SETLEASE	(F_LINUX_SPECIFIC_BASE+0)
 #define F_GETLEASE	(F_LINUX_SPECIFIC_BASE+1)
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index bec1dbe..c58690d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -857,6 +857,7 @@ extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern int posix_unblock_lock(struct file *, struct file_lock *);
 extern int vfs_test_lock(struct file *, struct file_lock *);
 extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
+extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 10/17] nfsd4: Convert NFSv4 to new lock interface
       [not found]                 ` <1175816468106-git-send-email->
@ 2007-04-05 23:41                   ` J. Bruce Fields
       [not found]                   ` <11758164681548-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:41 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Convert NFSv4 to the new lock interface.  We don't define any callback for now,
so we're not taking advantage of the asynchronous feature--that's less critical
for the multi-threaded nfsd then it is for the single-threaded lockd.  But this
does allow a cluster filesystems to export cluster-coherent locking to NFS.

Note that it's cluster filesystems that are the issue--of the filesystems that
define lock methods (nfs, cifs, etc.), most are not exportable by nfsd.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/nfsd/nfs4state.c |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 03b0578..678f3be 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -50,6 +50,7 @@
 #include <linux/nfsd/xdr4.h>
 #include <linux/namei.h>
 #include <linux/mutex.h>
+#include <linux/lockd/bind.h>
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
@@ -2773,7 +2774,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	/* XXX?: Just to divert the locks_release_private at the start of
 	 * locks_copy_lock: */
 	locks_init_lock(&conflock);
-	err = posix_lock_file(filp, &file_lock, &conflock);
+	err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
 	switch (-err) {
 	case 0: /* success! */
 		update_stateid(&lock_stp->st_stateid);
@@ -2790,7 +2791,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		status = nfserr_deadlock;
 		break;
 	default:        
-		dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",err);
+		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
 		status = nfserr_resource;
 		break;
 	}
@@ -2815,6 +2816,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	struct inode *inode;
 	struct file file;
 	struct file_lock file_lock;
+	int error;
 	__be32 status;
 
 	if (nfs4_in_grace())
@@ -2870,16 +2872,20 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 	nfs4_transform_lock_offset(&file_lock);
 
-	/* posix_test_lock uses the struct file _only_ to resolve the inode.
+	/* vfs_test_lock uses the struct file _only_ to resolve the inode.
 	 * since LOCKT doesn't require an OPEN, and therefore a struct
-	 * file may not exist, pass posix_test_lock a struct file with
+	 * file may not exist, pass vfs_test_lock a struct file with
 	 * only the dentry:inode set.
 	 */
 	memset(&file, 0, sizeof (struct file));
 	file.f_path.dentry = cstate->current_fh.fh_dentry;
 
 	status = nfs_ok;
-	posix_test_lock(&file, &file_lock);
+	error = vfs_test_lock(&file, &file_lock);
+	if (error) {
+		status = nfserrno(error);
+		goto out;
+	}
 	if (file_lock.fl_type != F_UNLCK) {
 		status = nfserr_denied;
 		nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
@@ -2935,9 +2941,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	/*
 	*  Try to unlock the file in the VFS.
 	*/
-	err = posix_lock_file(filp, &file_lock, NULL);
+	err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
 	if (err) {
-		dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
+		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
 		goto out_nfserr;
 	}
 	/*
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 11/17] lockd: save lock state on deferral
       [not found]                   ` <11758164681548-git-send-email->
@ 2007-04-05 23:41                     ` J. Bruce Fields
       [not found]                     ` <11758164683313-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:41 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

We need to keep some state for a pending asynchronous lock request, so this
patch adds that state to struct nlm_block.

This also adds a function which defers the request, by calling
rqstp->rq_chandle.defer and storing the resulting deferred request in a
nlm_block structure which we insert into lockd's global block list.  That
new function isn't called yet, so it's dead code until a later patch.

Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/lockd/svclock.c          |   25 +++++++++++++++++++++++++
 include/linux/lockd/lockd.h |   10 ++++++++++
 2 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 8c5c74f..f8e2aeb 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -331,6 +331,31 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call)
 }
 
 /*
+ * Deferred lock request handling for non-blocking lock
+ */
+static u32
+nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
+{
+	u32 status = nlm_lck_denied_nolocks;
+
+	block->b_flags |= B_QUEUED;
+
+	nlmsvc_insert_block(block, NLM_TIMEOUT);
+
+	block->b_cache_req = &rqstp->rq_chandle;
+	if (rqstp->rq_chandle.defer) {
+		block->b_deferred_req =
+			rqstp->rq_chandle.defer(block->b_cache_req);
+		if (block->b_deferred_req != NULL)
+			status = nlm_drop_reply;
+	}
+	dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n",
+		block, block->b_flags, status);
+
+	return status;
+}
+
+/*
  * Attempt to establish a lock, and if it can't be granted, block it
  * if required.
  */
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index ac25b56..1df10d7 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -119,6 +119,9 @@ struct nlm_file {
  * couldn't be granted because of a conflicting lock).
  */
 #define NLM_NEVER		(~(unsigned long) 0)
+/* timeout on non-blocking call: */
+#define NLM_TIMEOUT		(7 * HZ)
+
 struct nlm_block {
 	struct kref		b_count;	/* Reference count */
 	struct list_head	b_list;		/* linked list of all blocks */
@@ -130,6 +133,13 @@ struct nlm_block {
 	unsigned int		b_id;		/* block id */
 	unsigned char		b_granted;	/* VFS granted lock */
 	struct nlm_file *	b_file;		/* file in question */
+	struct cache_req *	b_cache_req;	/* deferred request handling */
+	struct file_lock *	b_fl;		/* set for GETLK */
+	struct cache_deferred_req * b_deferred_req;
+	unsigned int		b_flags;	/* block flags */
+#define B_QUEUED		1	/* lock queued */
+#define B_GOT_CALLBACK		2	/* got lock or conflicting lock */
+#define B_TOO_LATE		4	/* too late for non-blocking lock */
 };
 
 /*
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 12/17] lockd: handle fl_notify callbacks
       [not found]                     ` <11758164683313-git-send-email->
@ 2007-04-05 23:41                       ` J. Bruce Fields
       [not found]                       ` <11758164681958-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:41 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Add code to handle file system callback when the lock is finally granted.

Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/lockd/svclock.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 74 insertions(+), 6 deletions(-)

diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index f8e2aeb..cd5b7d3 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -261,6 +261,8 @@ static void nlmsvc_free_block(struct kref *kref)
 	nlmsvc_freegrantargs(block->b_call);
 	nlm_release_call(block->b_call);
 	nlm_release_file(block->b_file);
+	if (block->b_fl)
+		kfree(block->b_fl);
 	kfree(block);
 }
 
@@ -528,6 +530,32 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
 }
 
 /*
+ * This is a callback from the filesystem for VFS file lock requests.
+ * It will be used if fl_notify is defined and the filesystem can not
+ * respond to the request immediately.
+ * For GETLK request it will copy the reply to the nlm_block.
+ * For SETLK or SETLKW request it will get the local posix lock.
+ * In all cases it will move the block to the head of nlm_blocked q where
+ * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
+ * deferred rpc for GETLK and SETLK.
+ */
+static void
+nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
+			     int result)
+{
+	block->b_flags |= B_GOT_CALLBACK;
+	if (result == 0)
+		block->b_granted = 1;
+	else
+		block->b_flags |= B_TOO_LATE;
+	if (conf) {
+		block->b_fl = kzalloc(sizeof(struct file_lock), GFP_KERNEL);
+		if (block->b_fl)
+			locks_copy_lock(block->b_fl, conf);
+	}
+}
+
+/*
  * Unblock a blocked lock request. This is a callback invoked from the
  * VFS layer when a lock on which we blocked is removed.
  *
@@ -538,18 +566,35 @@ static int
 nlmsvc_notify_blocked(struct file_lock *fl, struct file_lock *conf, int result)
 {
 	struct nlm_block	*block;
+	int rc = -ENOENT;
 
 	dprintk("lockd: nlmsvc_notify_blocked lock %p conf %p result %d\n",
 							fl, conf, result);
+	lock_kernel();
 	list_for_each_entry(block, &nlm_blocked, b_list) {
 		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
+			dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
+							block, block->b_flags);
+			if (block->b_flags & B_QUEUED) {
+				if (block->b_flags & B_TOO_LATE) {
+					rc = -ENOLCK;
+					break;
+				}
+				nlmsvc_update_deferred_block(block, conf, result);
+			} else if (result == 0)
+				block->b_granted = 1;
+
 			nlmsvc_insert_block(block, 0);
 			svc_wake_up(block->b_daemon);
-			return;
+			rc = 0;
+			break;
 		}
 	}
+	unlock_kernel();
 
-	printk(KERN_WARNING "lockd: notification for unknown block!\n");
+	if (rc == -ENOENT)
+		printk(KERN_WARNING "lockd: notification for unknown block!\n");
+	return rc;
 }
 
 static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
@@ -582,6 +627,8 @@ nlmsvc_grant_blocked(struct nlm_block *block)
 
 	dprintk("lockd: grant blocked lock %p\n", block);
 
+	kref_get(&block->b_count);
+
 	/* Unlink block request from list */
 	nlmsvc_unlink_block(block);
 
@@ -604,11 +651,13 @@ nlmsvc_grant_blocked(struct nlm_block *block)
 	case -EAGAIN:
 		dprintk("lockd: lock still blocked\n");
 		nlmsvc_insert_block(block, NLM_NEVER);
+		nlmsvc_release_block(block);
 		return;
 	default:
 		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
 				-error, __FUNCTION__);
 		nlmsvc_insert_block(block, 10 * HZ);
+		nlmsvc_release_block(block);
 		return;
 	}
 
@@ -621,7 +670,6 @@ callback:
 	nlmsvc_insert_block(block, 30 * HZ);
 
 	/* Call the client */
-	kref_get(&block->b_count);
 	nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops);
 }
 
@@ -694,6 +742,23 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
 	nlmsvc_release_block(block);
 }
 
+/* Helper function to handle retry of a deferred block.
+ * If it is a blocking lock, call grant_blocked.
+ * For a non-blocking lock or test lock, revisit the request.
+ */
+static void
+retry_deferred_block(struct nlm_block *block)
+{
+	if (!(block->b_flags & B_GOT_CALLBACK))
+		block->b_flags |= B_TOO_LATE;
+	nlmsvc_insert_block(block, NLM_TIMEOUT);
+	dprintk("revisit block %p flags %d\n",	block, block->b_flags);
+	if (block->b_deferred_req) {
+		block->b_deferred_req->revisit(block->b_deferred_req, 0);
+		block->b_deferred_req = NULL;
+	}
+}
+
 /*
  * Retry all blocked locks that have been notified. This is where lockd
  * picks up locks that can be granted, or grant notifications that must
@@ -717,9 +782,12 @@ nlmsvc_retry_blocked(void)
 
 		dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
 			block, block->b_when);
-		kref_get(&block->b_count);
-		nlmsvc_grant_blocked(block);
-		nlmsvc_release_block(block);
+		if (block->b_flags & B_QUEUED) {
+			dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n",
+				block, block->b_granted, block->b_flags);
+			retry_deferred_block(block);
+		} else
+			nlmsvc_grant_blocked(block);
 	}
 
 	return timeout;
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 13/17] lockd: pass cookie in nlmsvc_testlock
       [not found]                       ` <11758164681958-git-send-email->
@ 2007-04-05 23:41                         ` J. Bruce Fields
       [not found]                         ` <117581646812-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:41 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Change NLM internal interface to pass more information for test lock; we
need this to make sure the cookie information is pushed down to the place
where we do request deferral, which is handled for testlock by the
following patch.

Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/lockd/svc4proc.c         |    2 +-
 fs/lockd/svclock.c          |    5 +++--
 fs/lockd/svcproc.c          |    2 +-
 include/linux/lockd/lockd.h |    4 ++--
 4 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 47a66aa..a1bccad 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -99,7 +99,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
 	/* Now check for conflicting locks */
-	resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+	resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
 
 	dprintk("lockd: TEST4          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index cd5b7d3..d76e40b 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -443,8 +443,9 @@ out:
  * Test for presence of a conflicting lock.
  */
 __be32
-nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
-				       struct nlm_lock *conflock)
+nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
+		struct nlm_lock *lock, struct nlm_lock *conflock,
+		struct nlm_cookie *cookie)
 {
 	dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
 				file->f_file->f_path.dentry->d_inode->i_sb->s_id,
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 31cb484..d13b827 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -127,7 +127,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
 	/* Now check for conflicting locks */
-	resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
+	resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie));
 
 	dprintk("lockd: TEST          status %d vers %d\n",
 		ntohl(resp->status), rqstp->rq_vers);
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 1df10d7..f79ac52 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -195,8 +195,8 @@ typedef int	  (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref)
 __be32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
 					struct nlm_lock *, int, struct nlm_cookie *);
 __be32		  nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
-__be32		  nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
-					struct nlm_lock *);
+__be32		  nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
+			struct nlm_lock *, struct nlm_lock *, struct nlm_cookie *);
 __be32		  nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
 unsigned long	  nlmsvc_retry_blocked(void);
 void		  nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 14/17] lockd: handle test_lock deferrals
       [not found]                         ` <117581646812-git-send-email->
@ 2007-04-05 23:41                           ` J. Bruce Fields
       [not found]                           ` <11758164681424-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:41 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Rewrite nlmsvc_testlock() to use the new asynchronous interface: instead of
immediately doing a posix_test_lock(), we first look for a matching block.
If the subsequent test_lock returns anything other than -EINPROGRESS, we
then remove the block we've found and return the results.

If it returns -EINPROGRESS, then we defer the lock request.

In the case where the block we find in the first step has B_QUEUED set,
we bypass the vfs_test_lock entirely, instead using the block to decide how
to respond:
	with nlm_lck_denied if B_TOO_LATE is set.
	with nlm_granted if B_GOT_CALLBACK is set.
	by dropping if neither B_TOO_LATE nor B_GOT_CALLBACK is set

Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/lockd/svc4proc.c |    2 +
 fs/lockd/svclock.c  |   83 ++++++++++++++++++++++++++++++++++++++++----------
 fs/lockd/svcproc.c  |    3 ++
 3 files changed, 71 insertions(+), 17 deletions(-)

diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index a1bccad..205d8be 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -100,6 +100,8 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 
 	/* Now check for conflicting locks */
 	resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
+	if (resp->status == nlm_drop_reply)
+		return rpc_drop_reply;
 
 	dprintk("lockd: TEST4          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index d76e40b..e7db46a 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -173,7 +173,7 @@ found:
  */
 static inline struct nlm_block *
 nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
-				struct nlm_lock *lock, struct nlm_cookie *cookie)
+		struct nlm_lock *lock, struct nlm_cookie *cookie, int conf)
 {
 	struct nlm_block	*block;
 	struct nlm_host		*host;
@@ -206,6 +206,11 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
 
 	dprintk("lockd: created block %p...\n", block);
 
+	if (conf) {
+		block->b_fl = kzalloc(sizeof(struct file_lock), GFP_KERNEL);
+		if (!block->b_fl)
+			goto failed_free;
+	}
 	/* Create and initialize the block */
 	block->b_daemon = rqstp->rq_server;
 	block->b_host   = host;
@@ -424,7 +429,7 @@ again:
 	if (newblock == NULL) {
 		mutex_unlock(&file->f_mutex);
 		dprintk("lockd: blocking on this lock (allocating).\n");
-		if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
+		if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie, 0)))
 			return nlm_lck_denied_nolocks;
 		goto again;
 	}
@@ -447,6 +452,10 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
 		struct nlm_lock *lock, struct nlm_lock *conflock,
 		struct nlm_cookie *cookie)
 {
+	struct nlm_block 	*block = NULL;
+	int			error;
+	__be32			ret;
+
 	dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
 				file->f_file->f_path.dentry->d_inode->i_sb->s_id,
 				file->f_file->f_path.dentry->d_inode->i_ino,
@@ -454,22 +463,63 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
 				(long long)lock->fl.fl_start,
 				(long long)lock->fl.fl_end);
 
-	if (posix_test_lock(file->f_file, &lock->fl)) {
-		dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
-				lock->fl.fl_type,
-				(long long)lock->fl.fl_start,
-				(long long)lock->fl.fl_end);
-		conflock->caller = "somehost";	/* FIXME */
-		conflock->len = strlen(conflock->caller);
-		conflock->oh.len = 0;		/* don't return OH info */
-		conflock->svid = lock->fl.fl_pid;
-		conflock->fl.fl_type = lock->fl.fl_type;
-		conflock->fl.fl_start = lock->fl.fl_start;
-		conflock->fl.fl_end = lock->fl.fl_end;
-		return nlm_lck_denied;
+	/* Get existing block (in case client is busy-waiting) */
+	block = nlmsvc_lookup_block(file, lock);
+
+	if (block == NULL) {
+		block = nlmsvc_create_block(rqstp, file, lock, cookie, 1);
+		if (block == NULL)
+			return nlm_granted;
+	}
+	if (block->b_flags & B_QUEUED) {
+		dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n",
+			block, block->b_flags, block->b_fl);
+		if (block->b_flags & B_TOO_LATE) {
+			nlmsvc_unlink_block(block);
+			return nlm_lck_denied;
+		}
+		if (block->b_flags & B_GOT_CALLBACK) {
+			if (block->b_fl != NULL
+					&& block->b_fl->fl_type != F_UNLCK) {
+				lock->fl = *block->b_fl;
+				goto conf_lock;
+			}
+			else {
+				nlmsvc_unlink_block(block);
+				return nlm_granted;
+			}
+		}
+		return nlm_drop_reply;
 	}
 
-	return nlm_granted;
+	error = vfs_test_lock(file->f_file, &lock->fl);
+	if (error == -EINPROGRESS)
+		return nlmsvc_defer_lock_rqst(rqstp, block);
+	if (error) {
+		ret = nlm_lck_denied_nolocks;
+		goto out;
+	}
+	if (lock->fl.fl_type == F_UNLCK) {
+		ret = nlm_granted;
+		goto out;
+	}
+
+conf_lock:
+	dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
+		lock->fl.fl_type, (long long)lock->fl.fl_start,
+		(long long)lock->fl.fl_end);
+	conflock->caller = "somehost";	/* FIXME */
+	conflock->len = strlen(conflock->caller);
+	conflock->oh.len = 0;		/* don't return OH info */
+	conflock->svid = lock->fl.fl_pid;
+	conflock->fl.fl_type = lock->fl.fl_type;
+	conflock->fl.fl_start = lock->fl.fl_start;
+	conflock->fl.fl_end = lock->fl.fl_end;
+	ret = nlm_lck_denied;
+out:
+	if (block)
+		nlmsvc_release_block(block);
+	return ret;
 }
 
 /*
@@ -550,7 +600,6 @@ nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
 	else
 		block->b_flags |= B_TOO_LATE;
 	if (conf) {
-		block->b_fl = kzalloc(sizeof(struct file_lock), GFP_KERNEL);
 		if (block->b_fl)
 			locks_copy_lock(block->b_fl, conf);
 	}
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index d13b827..40b5cf4 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -33,6 +33,7 @@ cast_to_nlm(__be32 status, u32 vers)
 		case nlm_lck_denied_nolocks:
 		case nlm_lck_blocked:
 		case nlm_lck_denied_grace_period:
+		case nlm_drop_reply:
 			break;
 		case nlm4_deadlock:
 			status = nlm_lck_denied;
@@ -128,6 +129,8 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 
 	/* Now check for conflicting locks */
 	resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie));
+	if (resp->status == nlm_drop_reply)
+		return rpc_drop_reply;
 
 	dprintk("lockd: TEST          status %d vers %d\n",
 		ntohl(resp->status), rqstp->rq_vers);
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 15/17] lockd: always preallocate block in nlmsvc_lock()
       [not found]                           ` <11758164681424-git-send-email->
@ 2007-04-05 23:41                             ` J. Bruce Fields
       [not found]                             ` <11758164682315-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:41 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Normally we could skip ever having to allocate a block in the case where
the client asks for a non-blocking lock, or asks for a blocking lock that
succeeds immediately.

However we're going to want to always look up a block first in order to
check whether we're revisiting a deferred lock call, and to be prepared to
handle the case where the filesystem returns -EINPROGRESS--in that case we
want to make sure the lock we've given the filesystem is the one embedded
in the block that we'll use to track the deferred request.

Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/lockd/svclock.c |   34 +++++++++++-----------------------
 1 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index e7db46a..d2c8d53 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -370,7 +370,7 @@ __be32
 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
 			struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
 {
-	struct nlm_block	*block, *newblock = NULL;
+	struct nlm_block	*block = NULL;
 	int			error;
 	__be32			ret;
 
@@ -383,17 +383,20 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
 				wait);
 
 
-	lock->fl.fl_flags &= ~FL_SLEEP;
-again:
 	/* Lock file against concurrent access */
 	mutex_lock(&file->f_mutex);
-	/* Get existing block (in case client is busy-waiting) */
+	/* Get existing block (in case client is busy-waiting)
+	 * or create new block
+	 */
 	block = nlmsvc_lookup_block(file, lock);
 	if (block == NULL) {
-		if (newblock != NULL)
-			lock = &newblock->b_call->a_args.lock;
-	} else
+		block = nlmsvc_create_block(rqstp, file, lock, cookie, 0);
+		ret = nlm_lck_denied_nolocks;
+		if (block == NULL)
+			goto out;
 		lock = &block->b_call->a_args.lock;
+	} else
+		lock->fl.fl_flags &= ~FL_SLEEP;
 
 	error = posix_lock_file(file->f_file, &lock->fl, NULL);
 	lock->fl.fl_flags &= ~FL_SLEEP;
@@ -419,26 +422,11 @@ again:
 		goto out;
 
 	ret = nlm_lck_blocked;
-	if (block != NULL)
-		goto out;
-
-	/* If we don't have a block, create and initialize it. Then
-	 * retry because we may have slept in kmalloc. */
-	/* We have to release f_mutex as nlmsvc_create_block may try to
-	 * to claim it while doing host garbage collection */
-	if (newblock == NULL) {
-		mutex_unlock(&file->f_mutex);
-		dprintk("lockd: blocking on this lock (allocating).\n");
-		if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie, 0)))
-			return nlm_lck_denied_nolocks;
-		goto again;
-	}
 
 	/* Append to list of blocked */
-	nlmsvc_insert_block(newblock, NLM_NEVER);
+	nlmsvc_insert_block(block, NLM_NEVER);
 out:
 	mutex_unlock(&file->f_mutex);
-	nlmsvc_release_block(newblock);
 	nlmsvc_release_block(block);
 	dprintk("lockd: nlmsvc_lock returned %u\n", ret);
 	return ret;
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 16/17] lockd: add code to handle deferred lock requests
       [not found]                             ` <11758164682315-git-send-email->
@ 2007-04-05 23:41                               ` J. Bruce Fields
       [not found]                               ` <11758164693717-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:41 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Rewrite nlmsvc_lock() to use the asynchronous interface.

As with testlock, we answer nlm requests in nlmsvc_lock by first looking up
the block and then using the results we find in the block if B_QUEUED is
set, and calling vfs_lock_file() otherwise.

If this a new lock request and we get -EINPROGRESS return on a non-blocking
request then we defer the request.

Also modify nlmsvc_unlock() to call the filesystem method if appropriate.

Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/lockd/svc4proc.c |    2 ++
 fs/lockd/svclock.c  |   39 +++++++++++++++++++++++++++++++++------
 fs/lockd/svcproc.c  |    2 ++
 fs/lockd/svcsubs.c  |    2 +-
 4 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 205d8be..bf27b6c 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -145,6 +145,8 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 	/* Now try to lock the file */
 	resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
 					argp->block, &argp->cookie);
+	if (resp->status == nlm_drop_reply)
+		return rpc_drop_reply;
 
 	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index d2c8d53..a4828f2 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -398,17 +398,43 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
 	} else
 		lock->fl.fl_flags &= ~FL_SLEEP;
 
-	error = posix_lock_file(file->f_file, &lock->fl, NULL);
-	lock->fl.fl_flags &= ~FL_SLEEP;
+	if (block->b_flags & B_QUEUED) {
+		dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
+							block, block->b_flags);
+		if (block->b_granted) {
+			nlmsvc_unlink_block(block);
+			ret = nlm_granted;
+			goto out;
+		}
+		if (block->b_flags & B_TOO_LATE) {
+			nlmsvc_unlink_block(block);
+			ret = nlm_lck_denied;
+			goto out;
+		}
+		ret = nlm_drop_reply;
+		goto out;
+	}
 
-	dprintk("lockd: posix_lock_file returned %d\n", error);
+	if (!wait)
+		lock->fl.fl_flags &= ~FL_SLEEP;
+	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
+	lock->fl.fl_flags &= ~FL_SLEEP;
 
+	dprintk("lockd: vfs_lock_file returned %d\n", error);
 	switch(error) {
 		case 0:
 			ret = nlm_granted;
 			goto out;
 		case -EAGAIN:
+			ret = nlm_lck_denied;
 			break;
+		case -EINPROGRESS:
+			if (wait)
+				break;
+			/* Filesystem lock operation is in progress
+			   Add it to the queue waiting for callback */
+			ret = nlmsvc_defer_lock_rqst(rqstp, block);
+			goto out;
 		case -EDEADLK:
 			ret = nlm_deadlock;
 			goto out;
@@ -533,7 +559,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
 	nlmsvc_cancel_blocked(file, lock);
 
 	lock->fl.fl_type = F_UNLCK;
-	error = posix_lock_file(file->f_file, &lock->fl, NULL);
+	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
 
 	return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
 }
@@ -680,14 +706,15 @@ nlmsvc_grant_blocked(struct nlm_block *block)
 
 	/* Try the lock operation again */
 	lock->fl.fl_flags |= FL_SLEEP;
-	error = posix_lock_file(file->f_file, &lock->fl, NULL);
+	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
 	lock->fl.fl_flags &= ~FL_SLEEP;
 
 	switch (error) {
 	case 0:
 		break;
 	case -EAGAIN:
-		dprintk("lockd: lock still blocked\n");
+	case -EINPROGRESS:
+		dprintk("lockd: lock still blocked error %d\n", error);
 		nlmsvc_insert_block(block, NLM_NEVER);
 		nlmsvc_release_block(block);
 		return;
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 40b5cf4..9cd5c8b 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -175,6 +175,8 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 	/* Now try to lock the file */
 	resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
 					       argp->block, &argp->cookie));
+	if (resp->status == nlm_drop_reply)
+		return rpc_drop_reply;
 
 	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 5095708..84ebba3 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -182,7 +182,7 @@ again:
 			lock.fl_type  = F_UNLCK;
 			lock.fl_start = 0;
 			lock.fl_end   = OFFSET_MAX;
-			if (posix_lock_file(file->f_file, &lock, NULL) < 0) {
+			if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) {
 				printk("lockd: unlock failure in %s:%d\n",
 						__FILE__, __LINE__);
 				return 1;
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 17/17] gfs2: nfs lock support for gfs2
       [not found]                               ` <11758164693717-git-send-email->
@ 2007-04-05 23:41                                 ` J. Bruce Fields
       [not found]                                 ` <11758164694159-git-send-email->
  1 sibling, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-05 23:41 UTC (permalink / raw)
  To: akpm; +Cc: Trond Myklebust, Marc Eshel, linux-fsdevel

From: Marc Eshel <eshel@almaden.ibm.com> - unquoted

Add NFS lock support to GFS2.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
 fs/gfs2/locking/dlm/plock.c |  104 ++++++++++++++++++++++++++++++++++++++----
 fs/gfs2/ops_file.c          |    5 ++
 2 files changed, 99 insertions(+), 10 deletions(-)

diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
index 1dd4215..1160cde 100644
--- a/fs/gfs2/locking/dlm/plock.c
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -25,6 +25,14 @@ struct plock_op {
 	struct gdlm_plock_info info;
 };
 
+struct plock_xop {
+	struct plock_op xop;
+	void *callback;
+	void *fl;
+	void *file;
+};
+
+
 static inline void set_version(struct gdlm_plock_info *info)
 {
 	info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
@@ -64,12 +72,14 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
 {
 	struct gdlm_ls *ls = lockspace;
 	struct plock_op *op;
+	struct plock_xop *xop;
 	int rv;
 
-	op = kzalloc(sizeof(*op), GFP_KERNEL);
-	if (!op)
+	xop = kzalloc(sizeof(*xop), GFP_KERNEL);
+	if (!xop)
 		return -ENOMEM;
 
+	op = &xop->xop;
 	op->info.optype		= GDLM_PLOCK_OP_LOCK;
 	op->info.pid		= fl->fl_pid;
 	op->info.ex		= (fl->fl_type == F_WRLCK);
@@ -79,9 +89,20 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
 	op->info.start		= fl->fl_start;
 	op->info.end		= fl->fl_end;
 	op->info.owner		= (__u64)(long) fl->fl_owner;
+	if (fl->fl_lmops && fl->fl_lmops->fl_notify) {
+		xop->callback	= fl->fl_lmops->fl_notify;
+		/* might need to make a copy */
+		xop->fl		= fl;
+		xop->file	= file;
+	} else
+		xop->callback	= NULL;
 
 	send_op(op);
-	wait_event(recv_wq, (op->done != 0));
+
+	if (xop->callback == NULL)
+		wait_event(recv_wq, (op->done != 0));
+	else
+		return -EINPROGRESS;
 
 	spin_lock(&ops_lock);
 	if (!list_empty(&op->list)) {
@@ -99,7 +120,60 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
 				  (unsigned long long)name->ln_number);
 	}
 
-	kfree(op);
+	kfree(xop);
+	return rv;
+}
+
+/* Returns failure iff a succesful lock operation should be canceled */
+static int gdlm_plock_callback(struct plock_op *op)
+{
+	struct file *file;
+	struct file_lock *fl;
+	int (*notify)(void *, void *, int) = NULL;
+	struct plock_xop *xop = (struct plock_xop *)op;
+	int rv = 0;
+
+	spin_lock(&ops_lock);
+	if (!list_empty(&op->list)) {
+		printk(KERN_INFO "plock op on list\n");
+		list_del(&op->list);
+	}
+	spin_unlock(&ops_lock);
+
+	/* check if the following 2 are still valid or make a copy */
+	file = xop->file;
+	fl = xop->fl;
+	notify = xop->callback;
+
+	if (op->info.rv) {
+		notify(fl, NULL, op->info.rv);
+		goto out;
+	}
+
+	/* got fs lock; bookkeep locally as well: */
+	if (posix_lock_file(file, fl, NULL)) {
+		/*
+		 * This can only happen in the case of kmalloc() failure.
+		 * The filesystem's own lock is the authoritative lock,
+		 * so a failure to get the lock locally is not a disaster.
+		 * As long as GFS cannot reliably cancel locks (especially
+		 * in a low-memory situation), we're better off ignoring
+		 * this failure than trying to recover.
+		 */
+		log_error("gdlm_plock: vfs lock error file %p fl %p",
+				file, fl);
+	}
+
+	rv = notify(fl, NULL, 0);
+	if (rv) {
+		/* XXX: We need to cancel the fs lock here: */
+		printk("gfs2 lock granted after lock request failed;"
+						" dangling lock!\n");
+		goto out;
+	}
+
+out:
+	kfree(xop);
 	return rv;
 }
 
@@ -138,6 +212,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
 
 	rv = op->info.rv;
 
+	if (rv == -ENOENT)
+		rv = 0;
+
 	kfree(op);
 	return rv;
 }
@@ -161,6 +238,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
 	op->info.start		= fl->fl_start;
 	op->info.end		= fl->fl_end;
 
+
 	send_op(op);
 	wait_event(recv_wq, (op->done != 0));
 
@@ -173,9 +251,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
 
 	rv = op->info.rv;
 
-	if (rv == 0)
-		fl->fl_type = F_UNLCK;
-	else if (rv > 0) {
+	fl->fl_type = F_UNLCK;
+	if (rv == -ENOENT)
+		rv = 0;
+	else if (rv == 0 && op->info.pid != fl->fl_pid) {
 		fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
 		fl->fl_pid = op->info.pid;
 		fl->fl_start = op->info.start;
@@ -243,9 +322,14 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
 	}
 	spin_unlock(&ops_lock);
 
-	if (found)
-		wake_up(&recv_wq);
-	else
+	if (found) {
+		struct plock_xop *xop;
+		xop = (struct plock_xop *)op;
+		if (xop->callback)
+			count = gdlm_plock_callback(op);
+		else
+			wake_up(&recv_wq);
+	} else
 		printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
 			(unsigned long long)info.number);
 	return count;
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index 48b248d..329c4dc 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -520,6 +520,11 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
 		}
 	}
 
+	if (cmd == F_CANCELLK) {
+		/* Hack: */
+		cmd = F_SETLK;
+		fl->fl_type = F_UNLCK;
+	}
 	if (IS_GETLK(cmd))
 		return gfs2_lm_plock_get(sdp, &name, file, fl);
 	else if (fl->fl_type == F_UNLCK)
-- 
1.5.0.rc1.gf4b6c


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/17] locks: trivial removal of unnecessary parentheses
       [not found] ` <11758164673642-git-send-email->
  2007-04-05 23:40   ` [PATCH 2/17] locks: create posix-to-flock helper functions J. Bruce Fields
       [not found]   ` <11758164671398-git-send-email->
@ 2007-04-06 10:30   ` Stephen Rothwell
  2007-04-08 18:37     ` J. Bruce Fields
  2 siblings, 1 reply; 21+ messages in thread
From: Stephen Rothwell @ 2007-04-06 10:30 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: akpm, Trond Myklebust, Marc Eshel, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 354 bytes --]

On Thu,  5 Apr 2007 19:40:51 -0400 "J. Bruce Fields" <bfields@citi.umich.edu> wrote:
>
> From: J. Bruce Fields <bfields@citi.umich.edu> - unquoted
>
> Remove some unnecessary parentheses.

Please don't do this.  It is unnecessary churn for zero gain.

--
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/17] locks: trivial removal of unnecessary parentheses
  2007-04-06 10:30   ` [PATCH 1/17] locks: trivial removal of unnecessary parentheses Stephen Rothwell
@ 2007-04-08 18:37     ` J. Bruce Fields
  0 siblings, 0 replies; 21+ messages in thread
From: J. Bruce Fields @ 2007-04-08 18:37 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: akpm, Trond Myklebust, Marc Eshel, linux-fsdevel

On Fri, Apr 06, 2007 at 08:30:04PM +1000, Stephen Rothwell wrote:
> On Thu,  5 Apr 2007 19:40:51 -0400 "J. Bruce Fields" <bfields@citi.umich.edu> wrote:
> >
> > From: J. Bruce Fields <bfields@citi.umich.edu> - unquoted
> >
> > Remove some unnecessary parentheses.
> 
> Please don't do this.  It is unnecessary churn for zero gain.

The gain is certainly very close to zero, but still seems positive
(removing some visual clutter), and the churn doesn't seem likely to
cause problems as long as we're touching the same lines in later patches
anyway.  I've no intention of launching any broad assault against
unnecessary parentheses.

--b.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 17/17] gfs2: nfs lock support for gfs2
       [not found]                                 ` <11758164694159-git-send-email->
@ 2007-04-17 13:34                                   ` Steven Whitehouse
  0 siblings, 0 replies; 21+ messages in thread
From: Steven Whitehouse @ 2007-04-17 13:34 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: akpm, Trond Myklebust, Marc Eshel, linux-fsdevel

Hi,

Sorry for the delay,

On Thu, 2007-04-05 at 19:41 -0400, J. Bruce Fields wrote:
> From: Marc Eshel <eshel@almaden.ibm.com> - unquoted
> 
> Add NFS lock support to GFS2.
> 
> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Acked-by: Steven Whitehouse <swhiteho@redhat.com>

Steve.

> ---
>  fs/gfs2/locking/dlm/plock.c |  104 ++++++++++++++++++++++++++++++++++++++----
>  fs/gfs2/ops_file.c          |    5 ++
>  2 files changed, 99 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
> index 1dd4215..1160cde 100644
> --- a/fs/gfs2/locking/dlm/plock.c
> +++ b/fs/gfs2/locking/dlm/plock.c
> @@ -25,6 +25,14 @@ struct plock_op {
>  	struct gdlm_plock_info info;
>  };
>  
> +struct plock_xop {
> +	struct plock_op xop;
> +	void *callback;
> +	void *fl;
> +	void *file;
> +};
> +
> +
>  static inline void set_version(struct gdlm_plock_info *info)
>  {
>  	info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
> @@ -64,12 +72,14 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
>  {
>  	struct gdlm_ls *ls = lockspace;
>  	struct plock_op *op;
> +	struct plock_xop *xop;
>  	int rv;
>  
> -	op = kzalloc(sizeof(*op), GFP_KERNEL);
> -	if (!op)
> +	xop = kzalloc(sizeof(*xop), GFP_KERNEL);
> +	if (!xop)
>  		return -ENOMEM;
>  
> +	op = &xop->xop;
>  	op->info.optype		= GDLM_PLOCK_OP_LOCK;
>  	op->info.pid		= fl->fl_pid;
>  	op->info.ex		= (fl->fl_type == F_WRLCK);
> @@ -79,9 +89,20 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
>  	op->info.start		= fl->fl_start;
>  	op->info.end		= fl->fl_end;
>  	op->info.owner		= (__u64)(long) fl->fl_owner;
> +	if (fl->fl_lmops && fl->fl_lmops->fl_notify) {
> +		xop->callback	= fl->fl_lmops->fl_notify;
> +		/* might need to make a copy */
> +		xop->fl		= fl;
> +		xop->file	= file;
> +	} else
> +		xop->callback	= NULL;
>  
>  	send_op(op);
> -	wait_event(recv_wq, (op->done != 0));
> +
> +	if (xop->callback == NULL)
> +		wait_event(recv_wq, (op->done != 0));
> +	else
> +		return -EINPROGRESS;
>  
>  	spin_lock(&ops_lock);
>  	if (!list_empty(&op->list)) {
> @@ -99,7 +120,60 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
>  				  (unsigned long long)name->ln_number);
>  	}
>  
> -	kfree(op);
> +	kfree(xop);
> +	return rv;
> +}
> +
> +/* Returns failure iff a succesful lock operation should be canceled */
> +static int gdlm_plock_callback(struct plock_op *op)
> +{
> +	struct file *file;
> +	struct file_lock *fl;
> +	int (*notify)(void *, void *, int) = NULL;
> +	struct plock_xop *xop = (struct plock_xop *)op;
> +	int rv = 0;
> +
> +	spin_lock(&ops_lock);
> +	if (!list_empty(&op->list)) {
> +		printk(KERN_INFO "plock op on list\n");
> +		list_del(&op->list);
> +	}
> +	spin_unlock(&ops_lock);
> +
> +	/* check if the following 2 are still valid or make a copy */
> +	file = xop->file;
> +	fl = xop->fl;
> +	notify = xop->callback;
> +
> +	if (op->info.rv) {
> +		notify(fl, NULL, op->info.rv);
> +		goto out;
> +	}
> +
> +	/* got fs lock; bookkeep locally as well: */
> +	if (posix_lock_file(file, fl, NULL)) {
> +		/*
> +		 * This can only happen in the case of kmalloc() failure.
> +		 * The filesystem's own lock is the authoritative lock,
> +		 * so a failure to get the lock locally is not a disaster.
> +		 * As long as GFS cannot reliably cancel locks (especially
> +		 * in a low-memory situation), we're better off ignoring
> +		 * this failure than trying to recover.
> +		 */
> +		log_error("gdlm_plock: vfs lock error file %p fl %p",
> +				file, fl);
> +	}
> +
> +	rv = notify(fl, NULL, 0);
> +	if (rv) {
> +		/* XXX: We need to cancel the fs lock here: */
> +		printk("gfs2 lock granted after lock request failed;"
> +						" dangling lock!\n");
> +		goto out;
> +	}
> +
> +out:
> +	kfree(xop);
>  	return rv;
>  }
>  
> @@ -138,6 +212,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
>  
>  	rv = op->info.rv;
>  
> +	if (rv == -ENOENT)
> +		rv = 0;
> +
>  	kfree(op);
>  	return rv;
>  }
> @@ -161,6 +238,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
>  	op->info.start		= fl->fl_start;
>  	op->info.end		= fl->fl_end;
>  
> +
>  	send_op(op);
>  	wait_event(recv_wq, (op->done != 0));
>  
> @@ -173,9 +251,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
>  
>  	rv = op->info.rv;
>  
> -	if (rv == 0)
> -		fl->fl_type = F_UNLCK;
> -	else if (rv > 0) {
> +	fl->fl_type = F_UNLCK;
> +	if (rv == -ENOENT)
> +		rv = 0;
> +	else if (rv == 0 && op->info.pid != fl->fl_pid) {
>  		fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
>  		fl->fl_pid = op->info.pid;
>  		fl->fl_start = op->info.start;
> @@ -243,9 +322,14 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
>  	}
>  	spin_unlock(&ops_lock);
>  
> -	if (found)
> -		wake_up(&recv_wq);
> -	else
> +	if (found) {
> +		struct plock_xop *xop;
> +		xop = (struct plock_xop *)op;
> +		if (xop->callback)
> +			count = gdlm_plock_callback(op);
> +		else
> +			wake_up(&recv_wq);
> +	} else
>  		printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
>  			(unsigned long long)info.number);
>  	return count;
> diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
> index 48b248d..329c4dc 100644
> --- a/fs/gfs2/ops_file.c
> +++ b/fs/gfs2/ops_file.c
> @@ -520,6 +520,11 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
>  		}
>  	}
>  
> +	if (cmd == F_CANCELLK) {
> +		/* Hack: */
> +		cmd = F_SETLK;
> +		fl->fl_type = F_UNLCK;
> +	}
>  	if (IS_GETLK(cmd))
>  		return gfs2_lm_plock_get(sdp, &name, file, fl);
>  	else if (fl->fl_type == F_UNLCK)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/17] locks: trivial removal of unnecessary parentheses
@ 2007-04-06 17:44 Christoph Hellwig
  0 siblings, 0 replies; 21+ messages in thread
From: Christoph Hellwig @ 2007-04-06 17:44 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: akpm, Trond Myklebust, Marc Eshel, linux-fsdevel

On Thu, Apr 05, 2007 at 07:40:51PM -0400, J. Bruce Fields wrote:
> From: J. Bruce Fields <bfields@citi.umich.edu> - unquoted
> 
> Remove some unnecessary parentheses.

Looks good.


^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2007-04-17 14:42 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <117581646786-git-send-email->
2007-04-05 23:40 ` [PATCH 1/17] locks: trivial removal of unnecessary parentheses J. Bruce Fields
     [not found] ` <11758164673642-git-send-email->
2007-04-05 23:40   ` [PATCH 2/17] locks: create posix-to-flock helper functions J. Bruce Fields
     [not found]   ` <11758164671398-git-send-email->
2007-04-05 23:40     ` [PATCH 3/17] locks: make ->lock release private data before returning in GETLK case J. Bruce Fields
     [not found]     ` <11758164672114-git-send-email->
2007-04-05 23:40       ` [PATCH 4/17] locks: give posix_test_lock same interface as ->lock J. Bruce Fields
     [not found]       ` <11758164672880-git-send-email->
2007-04-05 23:40         ` [PATCH 5/17] locks: factor out generic/filesystem switch from test_lock J. Bruce Fields
     [not found]         ` <1175816467294-git-send-email->
2007-04-05 23:40           ` [PATCH 6/17] locks: factor out generic/filesystem switch from setlock code J. Bruce Fields
     [not found]           ` <11758164671240-git-send-email->
2007-04-05 23:40             ` [PATCH 7/17] locks: allow {vfs,posix}_lock_file to return conflicting lock J. Bruce Fields
     [not found]             ` <11758164686-git-send-email->
2007-04-05 23:40               ` [PATCH 8/17] locks: add fl_notify arguments for asynchronous lock return J. Bruce Fields
     [not found]               ` <1175816468241-git-send-email->
2007-04-05 23:40                 ` [PATCH 9/17] locks: add lock cancel command J. Bruce Fields
     [not found]                 ` <1175816468106-git-send-email->
2007-04-05 23:41                   ` [PATCH 10/17] nfsd4: Convert NFSv4 to new lock interface J. Bruce Fields
     [not found]                   ` <11758164681548-git-send-email->
2007-04-05 23:41                     ` [PATCH 11/17] lockd: save lock state on deferral J. Bruce Fields
     [not found]                     ` <11758164683313-git-send-email->
2007-04-05 23:41                       ` [PATCH 12/17] lockd: handle fl_notify callbacks J. Bruce Fields
     [not found]                       ` <11758164681958-git-send-email->
2007-04-05 23:41                         ` [PATCH 13/17] lockd: pass cookie in nlmsvc_testlock J. Bruce Fields
     [not found]                         ` <117581646812-git-send-email->
2007-04-05 23:41                           ` [PATCH 14/17] lockd: handle test_lock deferrals J. Bruce Fields
     [not found]                           ` <11758164681424-git-send-email->
2007-04-05 23:41                             ` [PATCH 15/17] lockd: always preallocate block in nlmsvc_lock() J. Bruce Fields
     [not found]                             ` <11758164682315-git-send-email->
2007-04-05 23:41                               ` [PATCH 16/17] lockd: add code to handle deferred lock requests J. Bruce Fields
     [not found]                               ` <11758164693717-git-send-email->
2007-04-05 23:41                                 ` [PATCH 17/17] gfs2: nfs lock support for gfs2 J. Bruce Fields
     [not found]                                 ` <11758164694159-git-send-email->
2007-04-17 13:34                                   ` Steven Whitehouse
2007-04-06 10:30   ` [PATCH 1/17] locks: trivial removal of unnecessary parentheses Stephen Rothwell
2007-04-08 18:37     ` J. Bruce Fields
2007-04-06 17:44 Christoph Hellwig

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.