* from a broken NFS client. But broken NFS clients have a lot more to
* worry about than proper deadlock detection anyway... --okir
*/
-int posix_locks_deadlock(struct file_lock *caller_fl,
+static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl)
{
struct list_head *tmp;
return 0;
}
-EXPORT_SYMBOL(posix_locks_deadlock);
-
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
* at the head of the list, but that's secret knowledge known only to
* flock_lock_file and posix_lock_file.
+ *
+ * Note that if called with an FL_EXISTS argument, the caller may determine
+ * whether or not a lock was successfully freed by testing the return
+ * value for -ENOENT.
*/
static int flock_lock_file(struct file *filp, struct file_lock *request)
{
int found = 0;
lock_kernel();
+ if (request->fl_flags & FL_ACCESS)
+ goto find_conflict;
for_each_lock(inode, before) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
break;
}
- if (request->fl_type == F_UNLCK)
+ if (request->fl_type == F_UNLCK) {
+ if ((request->fl_flags & FL_EXISTS) && !found)
+ error = -ENOENT;
goto out;
+ }
error = -ENOMEM;
new_fl = locks_alloc_lock();
if (found)
cond_resched();
+find_conflict:
for_each_lock(inode, before) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
locks_insert_block(fl, request);
goto out;
}
+ if (request->fl_flags & FL_ACCESS)
+ goto out;
locks_copy_lock(new_fl, request);
locks_insert_lock(&inode->i_flock, new_fl);
new_fl = NULL;
error = 0;
if (!added) {
- if (request->fl_type == F_UNLCK)
+ if (request->fl_type == F_UNLCK) {
+ if (request->fl_flags & FL_EXISTS)
+ error = -ENOENT;
goto out;
+ }
if (!new_fl) {
error = -ENOLCK;
* Add a POSIX style lock to a file.
* We merge adjacent & overlapping locks whenever possible.
* POSIX locks are sorted by owner task, then by starting address
+ *
+ * Note that if called with an FL_EXISTS argument, the caller may determine
+ * 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)
{
if (!leases_enable)
goto out;
- error = lease_alloc(filp, arg, &fl);
- if (error)
+ error = -ENOMEM;
+ fl = locks_alloc_lock();
+ if (fl == NULL)
goto out;
locks_copy_lock(fl, lease);
locks_insert_lock(before, fl);
*flp = fl;
+ error = 0;
out:
return error;
}