<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Trond Myklebust &lt;trond.myklebust@fys.uio.no&gt;

VFS: More extensive fix to locking code.  Add file_lock_operations to deal
with copy/release of private data in the file_lock-&gt;fl_u field.  Add
filesystem hooks for steal_locks(): changing the lockowner is hardly a
supported concept in most file locking protocols.

Signed-off-by: Andrew Morton &lt;akpm@osdl.org&gt;
---

 25-akpm/fs/locks.c         |   40 ++++++++++++++++++++++++++++++----------
 25-akpm/include/linux/fs.h |    8 ++++++++
 2 files changed, 38 insertions(+), 10 deletions(-)

diff -puN fs/locks.c~posix-locking-fix-to-locking-code fs/locks.c
--- 25/fs/locks.c~posix-locking-fix-to-locking-code	2004-07-05 16:08:45.517129704 -0700
+++ 25-akpm/fs/locks.c	2004-07-05 16:08:45.526128336 -0700
@@ -167,6 +167,11 @@ static inline void locks_free_lock(struc
 	if (!list_empty(&amp;fl-&gt;fl_link))
 		panic("Attempting to free lock on active lock list");
 
+	if (fl-&gt;fl_ops &amp;&amp; fl-&gt;fl_ops-&gt;fl_release_private) {
+		fl-&gt;fl_ops-&gt;fl_release_private(fl);
+		fl-&gt;fl_ops = NULL;
+	}
+
 	kmem_cache_free(filelock_cache, fl);
 }
 
@@ -186,6 +191,7 @@ void locks_init_lock(struct file_lock *f
 	fl-&gt;fl_notify = NULL;
 	fl-&gt;fl_insert = NULL;
 	fl-&gt;fl_remove = NULL;
+	fl-&gt;fl_ops = NULL;
 }
 
 EXPORT_SYMBOL(locks_init_lock);
@@ -220,7 +226,9 @@ void locks_copy_lock(struct file_lock *n
 	new-&gt;fl_notify = fl-&gt;fl_notify;
 	new-&gt;fl_insert = fl-&gt;fl_insert;
 	new-&gt;fl_remove = fl-&gt;fl_remove;
-	new-&gt;fl_u = fl-&gt;fl_u;
+	new-&gt;fl_ops = fl-&gt;fl_ops;
+	if (fl-&gt;fl_ops &amp;&amp; fl-&gt;fl_ops-&gt;fl_copy_lock)
+		fl-&gt;fl_ops-&gt;fl_copy_lock(new, fl);
 }
 
 EXPORT_SYMBOL(locks_copy_lock);
@@ -324,6 +332,7 @@ static int flock_to_posix_lock(struct fi
 	fl-&gt;fl_notify = NULL;
 	fl-&gt;fl_insert = NULL;
 	fl-&gt;fl_remove = NULL;
+	fl-&gt;fl_ops = NULL;
 
 	return assign_type(fl, l-&gt;l_type);
 }
@@ -364,6 +373,7 @@ static int flock64_to_posix_lock(struct 
 	fl-&gt;fl_notify = NULL;
 	fl-&gt;fl_insert = NULL;
 	fl-&gt;fl_remove = NULL;
+	fl-&gt;fl_ops = NULL;
 
 	switch (l-&gt;l_type) {
 	case F_RDLCK:
@@ -400,6 +410,7 @@ static int lease_alloc(struct file *filp
 	fl-&gt;fl_notify = NULL;
 	fl-&gt;fl_insert = NULL;
 	fl-&gt;fl_remove = NULL;
+	fl-&gt;fl_ops = NULL;
 
 	*flp = fl;
 	return 0;
@@ -419,10 +430,9 @@ static inline int locks_overlap(struct f
 static inline int
 posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
 {
-	/* FIXME: Replace this sort of thing with struct file_lock_operations */
-	if ((fl1-&gt;fl_type | fl2-&gt;fl_type) &amp; FL_LOCKD)
-		return fl1-&gt;fl_owner == fl2-&gt;fl_owner &amp;&amp;
-			fl1-&gt;fl_pid == fl2-&gt;fl_pid;
+	if (fl1-&gt;fl_ops &amp;&amp; fl1-&gt;fl_ops-&gt;fl_compare_owner)
+		return fl2-&gt;fl_ops == fl1-&gt;fl_ops &amp;&amp;
+			fl1-&gt;fl_ops-&gt;fl_compare_owner(fl1, fl2);
 	return fl1-&gt;fl_owner == fl2-&gt;fl_owner;
 }
 
@@ -981,6 +991,8 @@ int locks_mandatory_area(int read_write,
 		break;
 	}
 
+	if (fl.fl_ops &amp;&amp; fl.fl_ops-&gt;fl_release_private)
+		fl.fl_ops-&gt;fl_release_private(&amp;fl);
 	return error;
 }
 
@@ -1415,7 +1427,6 @@ int fcntl_getlk(struct file *filp, struc
 	error = -EFAULT;
 	if (!copy_to_user(l, &amp;flock, sizeof(flock)))
 		error = 0;
-  
 out:
 	return error;
 }
@@ -1665,6 +1676,7 @@ void locks_remove_posix(struct file *fil
 	lock.fl_owner = owner;
 	lock.fl_pid = current-&gt;tgid;
 	lock.fl_file = filp;
+	lock.fl_ops = NULL;
 
 	if (filp-&gt;f_op &amp;&amp; filp-&gt;f_op-&gt;lock != NULL) {
 		filp-&gt;f_op-&gt;lock(filp, F_SETLK, &amp;lock);
@@ -1684,6 +1696,8 @@ void locks_remove_posix(struct file *fil
 		before = &amp;fl-&gt;fl_next;
 	}
 	unlock_kernel();
+	if (lock.fl_ops &amp;&amp; lock.fl_ops-&gt;fl_release_private)
+		lock.fl_ops-&gt;fl_release_private(&amp;lock);
 }
 
 EXPORT_SYMBOL(locks_remove_posix);
@@ -1978,12 +1992,18 @@ EXPORT_SYMBOL(lock_may_write);
 static inline void __steal_locks(struct file *file, fl_owner_t from)
 {
 	struct inode *inode = file-&gt;f_dentry-&gt;d_inode;
-	struct file_lock *fl = inode-&gt;i_flock;
+	struct file_lock *fl;
 
-	while (fl) {
-		if (fl-&gt;fl_file == file &amp;&amp; fl-&gt;fl_owner == from)
+restart:
+	for (fl = inode-&gt;i_flock; fl != NULL; fl = fl-&gt;fl_next) {
+		if (fl-&gt;fl_file == file &amp;&amp; fl-&gt;fl_owner == from) {
+			if (fl-&gt;fl_ops &amp;&amp; fl-&gt;fl_ops-&gt;fl_steal_locks) {
+				fl-&gt;fl_ops-&gt;fl_steal_locks(fl, from);
+				/* Some filesystems may just drop the lock */
+				goto restart;
+			}
 			fl-&gt;fl_owner = current-&gt;files;
-		fl = fl-&gt;fl_next;
+		}
 	}
 }
 
diff -puN include/linux/fs.h~posix-locking-fix-to-locking-code include/linux/fs.h
--- 25/include/linux/fs.h~posix-locking-fix-to-locking-code	2004-07-05 16:08:45.519129400 -0700
+++ 25-akpm/include/linux/fs.h	2004-07-05 16:08:45.528128032 -0700
@@ -622,6 +622,13 @@ extern void close_private_file(struct fi
  */
 typedef struct files_struct *fl_owner_t;
 
+struct file_lock_operations {
+	int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
+	void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
+	void (*fl_release_private)(struct file_lock *);
+	void (*fl_steal_locks)(struct file_lock *, fl_owner_t);
+};
+
 /* that will die - we need it for nfs_lock_info */
 #include &lt;linux/nfs_fs_i.h&gt;
 
@@ -645,6 +652,7 @@ struct file_lock {
 	struct fasync_struct *	fl_fasync; /* for lease break notifications */
 	unsigned long fl_break_time;	/* for nonblocking lease breaks */
 
+	struct file_lock_operations *fl_ops;	/* Callbacks for lockmanagers */
 	union {
 		struct nfs_lock_info	nfs_fl;
 	} fl_u;
_
</pre></body></html>