locks: convert posix locks to file_lock_context
Signed-off-by: Jeff Layton <jlayton@primarydata.com> Acked-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
110
fs/locks.c
110
fs/locks.c
@@ -157,9 +157,6 @@ static int target_leasetype(struct file_lock *fl)
|
||||
int leases_enable = 1;
|
||||
int lease_break_time = 45;
|
||||
|
||||
#define for_each_lock(inode, lockp) \
|
||||
for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
|
||||
|
||||
/*
|
||||
* The global file_lock_list is only used for displaying /proc/locks, so we
|
||||
* keep a list on each CPU, with each list protected by its own spinlock via
|
||||
@@ -218,6 +215,7 @@ locks_get_lock_context(struct inode *inode)
|
||||
goto out;
|
||||
|
||||
INIT_LIST_HEAD(&new->flc_flock);
|
||||
INIT_LIST_HEAD(&new->flc_posix);
|
||||
|
||||
/*
|
||||
* Assign the pointer if it's not already assigned. If it is, then
|
||||
@@ -241,6 +239,7 @@ locks_free_lock_context(struct file_lock_context *ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
WARN_ON_ONCE(!list_empty(&ctx->flc_flock));
|
||||
WARN_ON_ONCE(!list_empty(&ctx->flc_posix));
|
||||
kmem_cache_free(flctx_cache, ctx);
|
||||
}
|
||||
}
|
||||
@@ -809,21 +808,26 @@ void
|
||||
posix_test_lock(struct file *filp, struct file_lock *fl)
|
||||
{
|
||||
struct file_lock *cfl;
|
||||
struct file_lock_context *ctx;
|
||||
struct inode *inode = file_inode(filp);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
for (cfl = file_inode(filp)->i_flock; cfl; cfl = cfl->fl_next) {
|
||||
if (!IS_POSIX(cfl))
|
||||
continue;
|
||||
if (posix_locks_conflict(fl, cfl))
|
||||
break;
|
||||
}
|
||||
if (cfl) {
|
||||
locks_copy_conflock(fl, cfl);
|
||||
if (cfl->fl_nspid)
|
||||
fl->fl_pid = pid_vnr(cfl->fl_nspid);
|
||||
} else
|
||||
ctx = inode->i_flctx;
|
||||
if (!ctx || list_empty_careful(&ctx->flc_posix)) {
|
||||
fl->fl_type = F_UNLCK;
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
list_for_each_entry(cfl, &ctx->flc_posix, fl_list) {
|
||||
if (posix_locks_conflict(fl, cfl)) {
|
||||
locks_copy_conflock(fl, cfl);
|
||||
if (cfl->fl_nspid)
|
||||
fl->fl_pid = pid_vnr(cfl->fl_nspid);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
fl->fl_type = F_UNLCK;
|
||||
out:
|
||||
spin_unlock(&inode->i_lock);
|
||||
return;
|
||||
}
|
||||
@@ -983,16 +987,20 @@ out:
|
||||
|
||||
static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
|
||||
{
|
||||
struct file_lock *fl;
|
||||
struct file_lock *fl, *tmp;
|
||||
struct file_lock *new_fl = NULL;
|
||||
struct file_lock *new_fl2 = NULL;
|
||||
struct file_lock *left = NULL;
|
||||
struct file_lock *right = NULL;
|
||||
struct file_lock **before;
|
||||
struct file_lock_context *ctx;
|
||||
int error;
|
||||
bool added = false;
|
||||
LIST_HEAD(dispose);
|
||||
|
||||
ctx = locks_get_lock_context(inode);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* We may need two file_lock structures for this operation,
|
||||
* so we get them in advance to avoid races.
|
||||
@@ -1013,8 +1021,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
|
||||
* blocker's list of waiters and the global blocked_hash.
|
||||
*/
|
||||
if (request->fl_type != F_UNLCK) {
|
||||
for_each_lock(inode, before) {
|
||||
fl = *before;
|
||||
list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
|
||||
if (!IS_POSIX(fl))
|
||||
continue;
|
||||
if (!posix_locks_conflict(request, fl))
|
||||
@@ -1044,29 +1051,25 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
|
||||
if (request->fl_flags & FL_ACCESS)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Find the first old lock with the same owner as the new lock.
|
||||
*/
|
||||
|
||||
before = &inode->i_flock;
|
||||
|
||||
/* First skip locks owned by other processes. */
|
||||
while ((fl = *before) && (!IS_POSIX(fl) ||
|
||||
!posix_same_owner(request, fl))) {
|
||||
before = &fl->fl_next;
|
||||
/* Find the first old lock with the same owner as the new lock */
|
||||
list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
|
||||
if (posix_same_owner(request, fl))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Process locks with this owner. */
|
||||
while ((fl = *before) && posix_same_owner(request, fl)) {
|
||||
/* Detect adjacent or overlapping regions (if same lock type)
|
||||
*/
|
||||
list_for_each_entry_safe_from(fl, tmp, &ctx->flc_posix, fl_list) {
|
||||
if (!posix_same_owner(request, fl))
|
||||
break;
|
||||
|
||||
/* Detect adjacent or overlapping regions (if same lock type) */
|
||||
if (request->fl_type == fl->fl_type) {
|
||||
/* In all comparisons of start vs end, use
|
||||
* "start - 1" rather than "end + 1". If end
|
||||
* is OFFSET_MAX, end + 1 will become negative.
|
||||
*/
|
||||
if (fl->fl_end < request->fl_start - 1)
|
||||
goto next_lock;
|
||||
continue;
|
||||
/* If the next lock in the list has entirely bigger
|
||||
* addresses than the new one, insert the lock here.
|
||||
*/
|
||||
@@ -1087,18 +1090,17 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
|
||||
else
|
||||
request->fl_end = fl->fl_end;
|
||||
if (added) {
|
||||
locks_delete_lock(before, &dispose);
|
||||
locks_delete_lock_ctx(fl, &dispose);
|
||||
continue;
|
||||
}
|
||||
request = fl;
|
||||
added = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* Processing for different lock types is a bit
|
||||
* more complex.
|
||||
*/
|
||||
if (fl->fl_end < request->fl_start)
|
||||
goto next_lock;
|
||||
continue;
|
||||
if (fl->fl_start > request->fl_end)
|
||||
break;
|
||||
if (request->fl_type == F_UNLCK)
|
||||
@@ -1117,7 +1119,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
|
||||
* one (This may happen several times).
|
||||
*/
|
||||
if (added) {
|
||||
locks_delete_lock(before, &dispose);
|
||||
locks_delete_lock_ctx(fl, &dispose);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
@@ -1133,15 +1135,11 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
|
||||
locks_copy_lock(new_fl, request);
|
||||
request = new_fl;
|
||||
new_fl = NULL;
|
||||
locks_delete_lock(before, &dispose);
|
||||
locks_insert_lock(before, request);
|
||||
locks_insert_lock_ctx(request, &fl->fl_list);
|
||||
locks_delete_lock_ctx(fl, &dispose);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
/* Go on to next lock.
|
||||
*/
|
||||
next_lock:
|
||||
before = &fl->fl_next;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1166,7 +1164,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
|
||||
goto out;
|
||||
}
|
||||
locks_copy_lock(new_fl, request);
|
||||
locks_insert_lock(before, new_fl);
|
||||
locks_insert_lock_ctx(new_fl, &fl->fl_list);
|
||||
new_fl = NULL;
|
||||
}
|
||||
if (right) {
|
||||
@@ -1177,7 +1175,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
|
||||
left = new_fl2;
|
||||
new_fl2 = NULL;
|
||||
locks_copy_lock(left, right);
|
||||
locks_insert_lock(before, left);
|
||||
locks_insert_lock_ctx(left, &fl->fl_list);
|
||||
}
|
||||
right->fl_start = request->fl_end + 1;
|
||||
locks_wake_up_blocks(right);
|
||||
@@ -1257,22 +1255,29 @@ EXPORT_SYMBOL(posix_lock_file_wait);
|
||||
*/
|
||||
int locks_mandatory_locked(struct file *file)
|
||||
{
|
||||
int ret;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct file_lock_context *ctx;
|
||||
struct file_lock *fl;
|
||||
|
||||
ctx = inode->i_flctx;
|
||||
if (!ctx || list_empty_careful(&ctx->flc_posix))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Search the lock list for this inode for any POSIX locks.
|
||||
*/
|
||||
spin_lock(&inode->i_lock);
|
||||
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
|
||||
if (!IS_POSIX(fl))
|
||||
continue;
|
||||
ret = 0;
|
||||
list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
|
||||
if (fl->fl_owner != current->files &&
|
||||
fl->fl_owner != file)
|
||||
fl->fl_owner != file) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
return fl ? -EAGAIN : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2389,13 +2394,14 @@ out:
|
||||
void locks_remove_posix(struct file *filp, fl_owner_t owner)
|
||||
{
|
||||
struct file_lock lock;
|
||||
struct file_lock_context *ctx = file_inode(filp)->i_flctx;
|
||||
|
||||
/*
|
||||
* If there are no locks held on this file, we don't need to call
|
||||
* posix_lock_file(). Another process could be setting a lock on this
|
||||
* file at the same time, but we wouldn't remove that lock anyway.
|
||||
*/
|
||||
if (!file_inode(filp)->i_flock)
|
||||
if (!ctx || list_empty(&ctx->flc_posix))
|
||||
return;
|
||||
|
||||
lock.fl_type = F_UNLCK;
|
||||
|
Reference in New Issue
Block a user