static LIST_HEAD(file_lock_list);
static LIST_HEAD(blocked_list);
-static kmem_cache_t *filelock_cache __read_mostly;
+static struct kmem_cache *filelock_cache __read_mostly;
/* Allocate an empty lock structure. */
static struct file_lock *locks_alloc_lock(void)
{
- return kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
+ return kmem_cache_alloc(filelock_cache, GFP_KERNEL);
}
static void locks_release_private(struct file_lock *fl)
* Initialises the fields of the file lock which are invariant for
* free file_locks.
*/
-static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags)
+static void init_once(void *foo, struct kmem_cache *cache, unsigned long flags)
{
struct file_lock *lock = (struct file_lock *) foo;
off_t start, end;
switch (l->l_whence) {
- case 0: /*SEEK_SET*/
+ case SEEK_SET:
start = 0;
break;
- case 1: /*SEEK_CUR*/
+ case SEEK_CUR:
start = filp->f_pos;
break;
- case 2: /*SEEK_END*/
+ case SEEK_END:
start = i_size_read(filp->f_dentry->d_inode);
break;
default:
loff_t start;
switch (l->l_whence) {
- case 0: /*SEEK_SET*/
+ case SEEK_SET:
start = 0;
break;
- case 1: /*SEEK_CUR*/
+ case SEEK_CUR:
start = filp->f_pos;
break;
- case 2: /*SEEK_END*/
+ case SEEK_END:
start = i_size_read(filp->f_dentry->d_inode);
break;
default:
/* 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;
}
goto out_unlock;
}
- error = f_setown(filp, current->pid, 0);
+ error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
out_unlock:
unlock_kernel();
return error;