#define for_each_lock(inode, lockp) \
for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
-static LIST_HEAD(file_lock_list);
+LIST_HEAD(file_lock_list);
+
+EXPORT_SYMBOL(file_lock_list);
+
static LIST_HEAD(blocked_list);
-static kmem_cache_t *filelock_cache __read_mostly;
+static kmem_cache_t *filelock_cache;
/* Allocate an empty lock structure. */
static struct file_lock *locks_alloc_lock(void)
return kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
}
-static void locks_release_private(struct file_lock *fl)
+/* Free a lock which is not in use. */
+static void locks_free_lock(struct file_lock *fl)
{
+ if (fl == NULL) {
+ BUG();
+ return;
+ }
+
+ vx_locks_dec(fl);
+
+ if (waitqueue_active(&fl->fl_wait))
+ panic("Attempting to free lock with active wait queue");
+
+ if (!list_empty(&fl->fl_block))
+ panic("Attempting to free lock with active block list");
+
+ if (!list_empty(&fl->fl_link))
+ panic("Attempting to free lock on active lock list");
+
if (fl->fl_ops) {
if (fl->fl_ops->fl_release_private)
fl->fl_ops->fl_release_private(fl);
fl->fl_ops = NULL;
}
+
if (fl->fl_lmops) {
if (fl->fl_lmops->fl_release_private)
fl->fl_lmops->fl_release_private(fl);
fl->fl_lmops = NULL;
}
-}
-
-/* Free a lock which is not in use. */
-static void locks_free_lock(struct file_lock *fl)
-{
- BUG_ON(waitqueue_active(&fl->fl_wait));
- BUG_ON(!list_empty(&fl->fl_block));
- BUG_ON(!list_empty(&fl->fl_link));
-
- vx_locks_dec(fl);
- locks_release_private(fl);
kmem_cache_free(filelock_cache, fl);
}
locks_init_lock(lock);
}
-static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
-{
- if (fl->fl_ops) {
- if (fl->fl_ops->fl_copy_lock)
- fl->fl_ops->fl_copy_lock(new, fl);
- new->fl_ops = fl->fl_ops;
- }
- if (fl->fl_lmops) {
- if (fl->fl_lmops->fl_copy_lock)
- fl->fl_lmops->fl_copy_lock(new, fl);
- new->fl_lmops = fl->fl_lmops;
- }
-}
-
/*
* Initialize a new lock from an existing file_lock structure.
*/
-static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
+void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{
new->fl_owner = fl->fl_owner;
new->fl_pid = fl->fl_pid;
- new->fl_file = NULL;
+ new->fl_file = fl->fl_file;
new->fl_flags = fl->fl_flags;
new->fl_type = fl->fl_type;
new->fl_start = fl->fl_start;
new->fl_end = fl->fl_end;
- new->fl_ops = NULL;
- new->fl_lmops = NULL;
-}
-
-void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
-{
- locks_release_private(new);
-
- __locks_copy_lock(new, fl);
- new->fl_file = fl->fl_file;
new->fl_ops = fl->fl_ops;
new->fl_lmops = fl->fl_lmops;
- new->fl_xid = fl->fl_xid;
+ if (fl->fl_ops && fl->fl_ops->fl_copy_lock)
+ fl->fl_ops->fl_copy_lock(new, fl);
+ if (fl->fl_lmops && fl->fl_lmops->fl_copy_lock)
+ fl->fl_lmops->fl_copy_lock(new, fl);
- locks_copy_private(new, fl);
+ new->fl_xid = fl->fl_xid;
}
EXPORT_SYMBOL(locks_copy_lock);
static void locks_insert_block(struct file_lock *blocker,
struct file_lock *waiter)
{
- BUG_ON(!list_empty(&waiter->fl_block));
+ if (!list_empty(&waiter->fl_block)) {
+ printk(KERN_ERR "locks_insert_block: removing duplicated lock "
+ "(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid,
+ waiter->fl_start, waiter->fl_end, waiter->fl_type);
+ __locks_delete_block(waiter);
+ }
list_add_tail(&waiter->fl_block, &blocker->fl_block);
waiter->fl_next = blocker;
if (IS_POSIX(blocker))
return result;
}
-int
-posix_test_lock(struct file *filp, struct file_lock *fl,
- struct file_lock *conflock)
+struct file_lock *
+posix_test_lock(struct file *filp, struct file_lock *fl)
{
struct file_lock *cfl;
if (posix_locks_conflict(cfl, fl))
break;
}
- if (cfl) {
- __locks_copy_lock(conflock, cfl);
- unlock_kernel();
- return 1;
- }
unlock_kernel();
- return 0;
+
+ return (cfl);
}
EXPORT_SYMBOL(posix_test_lock);
if (request->fl_type == F_UNLCK)
goto out;
- error = -ENOMEM;
new_fl = locks_alloc_lock();
if (new_fl == NULL)
goto out;
vx_locks_inc(new_fl);
locks_insert_lock(&inode->i_flock, new_fl);
new_fl = NULL;
- error = 0;
out:
unlock_kernel();
return error;
}
-static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request,
- struct file_lock *conflock, xid_t xid)
+EXPORT_SYMBOL(posix_lock_file);
+
+static int __posix_lock_file(struct inode *inode, struct file_lock *request, xid_t xid)
{
struct file_lock *fl;
struct file_lock *new_fl, *new_fl2;
continue;
if (!posix_locks_conflict(request, fl))
continue;
- if (conflock)
- locks_copy_lock(conflock, fl);
error = -EAGAIN;
if (!(request->fl_flags & FL_SLEEP))
goto out;
fl->fl_start = request->fl_start;
fl->fl_end = request->fl_end;
fl->fl_type = request->fl_type;
- locks_release_private(fl);
- locks_copy_private(fl, request);
+ fl->fl_u = request->fl_u;
request = fl;
added = 1;
}
*/
int posix_lock_file(struct file *filp, struct file_lock *fl)
{
- return __posix_lock_file_conf(filp->f_dentry->d_inode,
- fl, NULL, filp->f_xid);
-}
-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,
- struct file_lock *conflock)
-{
- return __posix_lock_file_conf(filp->f_dentry->d_inode,
- fl, conflock, filp->f_xid);
+ return __posix_lock_file(filp->f_dentry->d_inode, fl, filp->f_xid);
}
-EXPORT_SYMBOL(posix_lock_file_conf);
/**
* posix_lock_file_wait - Apply a POSIX-style lock to a file
int error;
might_sleep ();
for (;;) {
- error = posix_lock_file(filp, fl);
+ error = __posix_lock_file(filp->f_dentry->d_inode,
+ fl, filp->f_xid);
if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
fl.fl_end = offset + count - 1;
for (;;) {
- error = __posix_lock_file_conf(inode, &fl, NULL, filp->f_xid);
+ error = __posix_lock_file(inode, &fl, filp->f_xid);
if (error != -EAGAIN)
break;
if (!(fl.fl_flags & FL_SLEEP))
*/
int fcntl_getlk(struct file *filp, struct flock __user *l)
{
- struct file_lock *fl, cfl, file_lock;
+ struct file_lock *fl, file_lock;
struct flock flock;
int error;
else
fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else {
- fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
+ fl = posix_test_lock(filp, &file_lock);
}
flock.l_type = F_UNLCK;
error = filp->f_op->lock(filp, cmd, file_lock);
else {
for (;;) {
- error = posix_lock_file(filp, file_lock);
+ error = __posix_lock_file(inode, file_lock,
+ filp->f_xid);
if ((error != -EAGAIN) || (cmd == F_SETLK))
break;
error = wait_event_interruptible(file_lock->fl_wait,
*/
int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
{
- struct file_lock *fl, cfl, file_lock;
+ struct file_lock *fl, file_lock;
struct flock64 flock;
int error;
else
fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else {
- fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
+ fl = posix_test_lock(filp, &file_lock);
}
flock.l_type = F_UNLCK;
error = filp->f_op->lock(filp, cmd, file_lock);
else {
for (;;) {
- error = posix_lock_file(filp, file_lock);
+ error = __posix_lock_file(inode, file_lock,
+ filp->f_xid);
if ((error != -EAGAIN) || (cmd == F_SETLK64))
break;
error = wait_event_interruptible(file_lock->fl_wait,
unlock_kernel();
}
+/**
+ * posix_block_lock - blocks waiting for a file lock
+ * @blocker: the lock which is blocking
+ * @waiter: the lock which conflicts and has to wait
+ *
+ * lockd needs to block waiting for locks.
+ */
+void
+posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
+{
+ locks_insert_block(blocker, waiter);
+}
+
+EXPORT_SYMBOL(posix_block_lock);
+
/**
* posix_unblock_lock - stop waiting for a file lock
* @filp: how the file was opened