From: Trond Myklebust VFS: More extensive fix to locking code. Add file_lock_operations to deal with copy/release of private data in the file_lock->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 --- 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(&fl->fl_link)) panic("Attempting to free lock on active lock list"); + if (fl->fl_ops && fl->fl_ops->fl_release_private) { + fl->fl_ops->fl_release_private(fl); + fl->fl_ops = NULL; + } + kmem_cache_free(filelock_cache, fl); } @@ -186,6 +191,7 @@ void locks_init_lock(struct file_lock *f fl->fl_notify = NULL; fl->fl_insert = NULL; fl->fl_remove = NULL; + fl->fl_ops = NULL; } EXPORT_SYMBOL(locks_init_lock); @@ -220,7 +226,9 @@ void locks_copy_lock(struct file_lock *n new->fl_notify = fl->fl_notify; new->fl_insert = fl->fl_insert; new->fl_remove = fl->fl_remove; - new->fl_u = fl->fl_u; + new->fl_ops = fl->fl_ops; + if (fl->fl_ops && fl->fl_ops->fl_copy_lock) + fl->fl_ops->fl_copy_lock(new, fl); } EXPORT_SYMBOL(locks_copy_lock); @@ -324,6 +332,7 @@ static int flock_to_posix_lock(struct fi fl->fl_notify = NULL; fl->fl_insert = NULL; fl->fl_remove = NULL; + fl->fl_ops = NULL; return assign_type(fl, l->l_type); } @@ -364,6 +373,7 @@ static int flock64_to_posix_lock(struct fl->fl_notify = NULL; fl->fl_insert = NULL; fl->fl_remove = NULL; + fl->fl_ops = NULL; switch (l->l_type) { case F_RDLCK: @@ -400,6 +410,7 @@ static int lease_alloc(struct file *filp fl->fl_notify = NULL; fl->fl_insert = NULL; fl->fl_remove = NULL; + fl->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->fl_type | fl2->fl_type) & FL_LOCKD) - return fl1->fl_owner == fl2->fl_owner && - fl1->fl_pid == fl2->fl_pid; + if (fl1->fl_ops && fl1->fl_ops->fl_compare_owner) + return fl2->fl_ops == fl1->fl_ops && + fl1->fl_ops->fl_compare_owner(fl1, fl2); return fl1->fl_owner == fl2->fl_owner; } @@ -981,6 +991,8 @@ int locks_mandatory_area(int read_write, break; } + if (fl.fl_ops && fl.fl_ops->fl_release_private) + fl.fl_ops->fl_release_private(&fl); return error; } @@ -1415,7 +1427,6 @@ int fcntl_getlk(struct file *filp, struc error = -EFAULT; if (!copy_to_user(l, &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->tgid; lock.fl_file = filp; + lock.fl_ops = NULL; if (filp->f_op && filp->f_op->lock != NULL) { filp->f_op->lock(filp, F_SETLK, &lock); @@ -1684,6 +1696,8 @@ void locks_remove_posix(struct file *fil before = &fl->fl_next; } unlock_kernel(); + if (lock.fl_ops && lock.fl_ops->fl_release_private) + lock.fl_ops->fl_release_private(&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->f_dentry->d_inode; - struct file_lock *fl = inode->i_flock; + struct file_lock *fl; - while (fl) { - if (fl->fl_file == file && fl->fl_owner == from) +restart: + for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { + if (fl->fl_file == file && fl->fl_owner == from) { + if (fl->fl_ops && fl->fl_ops->fl_steal_locks) { + fl->fl_ops->fl_steal_locks(fl, from); + /* Some filesystems may just drop the lock */ + goto restart; + } fl->fl_owner = current->files; - fl = fl->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 @@ -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; _