Commit 5263e31e authored by Jeff Layton's avatar Jeff Layton Committed by Jeff Layton

locks: move flock locks to file_lock_context

Signed-off-by: default avatarJeff Layton <jlayton@primarydata.com>
Acked-by: default avatarChristoph Hellwig <hch@lst.de>
parent c362781c
...@@ -239,14 +239,16 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) ...@@ -239,14 +239,16 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
return err; return err;
} }
/** /*
* Must be called with lock_flocks() already held. Fills in the passed * Fills in the passed counter variables, so you can prepare pagelist metadata
* counter variables, so you can prepare pagelist metadata before calling * before calling ceph_encode_locks.
* ceph_encode_locks. *
* FIXME: add counters to struct file_lock_context so we don't need to do this?
*/ */
void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
{ {
struct file_lock *lock; struct file_lock *lock;
struct file_lock_context *ctx;
*fcntl_count = 0; *fcntl_count = 0;
*flock_count = 0; *flock_count = 0;
...@@ -255,7 +257,11 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) ...@@ -255,7 +257,11 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
if (lock->fl_flags & FL_POSIX) if (lock->fl_flags & FL_POSIX)
++(*fcntl_count); ++(*fcntl_count);
else if (lock->fl_flags & FL_FLOCK) }
ctx = inode->i_flctx;
if (ctx) {
list_for_each_entry(lock, &ctx->flc_flock, fl_list)
++(*flock_count); ++(*flock_count);
} }
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
...@@ -273,6 +279,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode, ...@@ -273,6 +279,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
int num_fcntl_locks, int num_flock_locks) int num_fcntl_locks, int num_flock_locks)
{ {
struct file_lock *lock; struct file_lock *lock;
struct file_lock_context *ctx;
int err = 0; int err = 0;
int seen_fcntl = 0; int seen_fcntl = 0;
int seen_flock = 0; int seen_flock = 0;
...@@ -295,8 +302,10 @@ int ceph_encode_locks_to_buffer(struct inode *inode, ...@@ -295,8 +302,10 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
++l; ++l;
} }
} }
for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
if (lock->fl_flags & FL_FLOCK) { ctx = inode->i_flctx;
if (ctx) {
list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
++seen_flock; ++seen_flock;
if (seen_flock > num_flock_locks) { if (seen_flock > num_flock_locks) {
err = -ENOSPC; err = -ENOSPC;
......
...@@ -694,6 +694,14 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) ...@@ -694,6 +694,14 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
locks_insert_global_locks(fl); locks_insert_global_locks(fl);
} }
static void
locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before)
{
fl->fl_nspid = get_pid(task_tgid(current));
list_add_tail(&fl->fl_list, before);
locks_insert_global_locks(fl);
}
/** /**
* locks_delete_lock - Delete a lock and then free it. * locks_delete_lock - Delete a lock and then free it.
* @thisfl_p: pointer that points to the fl_next field of the previous * @thisfl_p: pointer that points to the fl_next field of the previous
...@@ -739,6 +747,18 @@ static void locks_delete_lock(struct file_lock **thisfl_p, ...@@ -739,6 +747,18 @@ static void locks_delete_lock(struct file_lock **thisfl_p,
locks_free_lock(fl); locks_free_lock(fl);
} }
static void
locks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose)
{
locks_delete_global_locks(fl);
if (fl->fl_nspid) {
put_pid(fl->fl_nspid);
fl->fl_nspid = NULL;
}
locks_wake_up_blocks(fl);
list_move(&fl->fl_list, dispose);
}
/* Determine if lock sys_fl blocks lock caller_fl. Common functionality /* Determine if lock sys_fl blocks lock caller_fl. Common functionality
* checks for shared/exclusive status of overlapping locks. * checks for shared/exclusive status of overlapping locks.
*/ */
...@@ -888,12 +908,17 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, ...@@ -888,12 +908,17 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
static int flock_lock_file(struct file *filp, struct file_lock *request) static int flock_lock_file(struct file *filp, struct file_lock *request)
{ {
struct file_lock *new_fl = NULL; struct file_lock *new_fl = NULL;
struct file_lock **before; struct file_lock *fl;
struct inode * inode = file_inode(filp); struct file_lock_context *ctx;
struct inode *inode = file_inode(filp);
int error = 0; int error = 0;
int found = 0; bool found = false;
LIST_HEAD(dispose); LIST_HEAD(dispose);
ctx = locks_get_lock_context(inode);
if (!ctx)
return -ENOMEM;
if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
new_fl = locks_alloc_lock(); new_fl = locks_alloc_lock();
if (!new_fl) if (!new_fl)
...@@ -904,18 +929,13 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) ...@@ -904,18 +929,13 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
if (request->fl_flags & FL_ACCESS) if (request->fl_flags & FL_ACCESS)
goto find_conflict; goto find_conflict;
for_each_lock(inode, before) { list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
break;
if (IS_LEASE(fl))
continue;
if (filp != fl->fl_file) if (filp != fl->fl_file)
continue; continue;
if (request->fl_type == fl->fl_type) if (request->fl_type == fl->fl_type)
goto out; goto out;
found = 1; found = true;
locks_delete_lock(before, &dispose); locks_delete_lock_ctx(fl, &dispose);
break; break;
} }
...@@ -936,12 +956,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) ...@@ -936,12 +956,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
} }
find_conflict: find_conflict:
for_each_lock(inode, before) { list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
break;
if (IS_LEASE(fl))
continue;
if (!flock_locks_conflict(request, fl)) if (!flock_locks_conflict(request, fl))
continue; continue;
error = -EAGAIN; error = -EAGAIN;
...@@ -954,7 +969,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) ...@@ -954,7 +969,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
if (request->fl_flags & FL_ACCESS) if (request->fl_flags & FL_ACCESS)
goto out; goto out;
locks_copy_lock(new_fl, request); locks_copy_lock(new_fl, request);
locks_insert_lock(before, new_fl); locks_insert_lock_ctx(new_fl, &ctx->flc_flock);
new_fl = NULL; new_fl = NULL;
error = 0; error = 0;
...@@ -2412,8 +2427,9 @@ locks_remove_flock(struct file *filp) ...@@ -2412,8 +2427,9 @@ locks_remove_flock(struct file *filp)
.fl_type = F_UNLCK, .fl_type = F_UNLCK,
.fl_end = OFFSET_MAX, .fl_end = OFFSET_MAX,
}; };
struct file_lock_context *flctx = file_inode(filp)->i_flctx;
if (!file_inode(filp)->i_flock) if (!flctx || list_empty(&flctx->flc_flock))
return; return;
if (filp->f_op->flock) if (filp->f_op->flock)
......
...@@ -85,15 +85,16 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ ...@@ -85,15 +85,16 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct file_lock *fl; struct file_lock *fl;
struct file_lock_context *flctx;
int status = 0; int status = 0;
if (inode->i_flock == NULL) if (inode->i_flock == NULL && inode->i_flctx == NULL)
goto out; goto out;
/* Protect inode->i_flock using the i_lock */ /* Protect inode->i_flock using the i_lock */
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) if (!(fl->fl_flags & (FL_POSIX)))
continue; continue;
if (nfs_file_open_context(fl->fl_file) != ctx) if (nfs_file_open_context(fl->fl_file) != ctx)
continue; continue;
...@@ -103,6 +104,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ ...@@ -103,6 +104,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
goto out; goto out;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
} }
flctx = inode->i_flctx;
if (flctx) {
list_for_each_entry(fl, &flctx->flc_flock, fl_list) {
if (nfs_file_open_context(fl->fl_file) != ctx)
continue;
spin_unlock(&inode->i_lock);
status = nfs4_lock_delegation_recall(fl, state,
stateid);
if (status < 0)
goto out;
spin_lock(&inode->i_lock);
}
}
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
out: out:
return status; return status;
......
...@@ -1366,8 +1366,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ ...@@ -1366,8 +1366,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct file_lock *fl; struct file_lock *fl;
int status = 0; int status = 0;
struct file_lock_context *flctx = inode->i_flctx;
if (inode->i_flock == NULL) if (inode->i_flock == NULL && flctx == NULL)
return 0; return 0;
/* Guard against delegation returns and new lock/unlock calls */ /* Guard against delegation returns and new lock/unlock calls */
...@@ -1375,7 +1376,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ ...@@ -1375,7 +1376,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
/* Protect inode->i_flock using the BKL */ /* Protect inode->i_flock using the BKL */
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) if (!(fl->fl_flags & FL_POSIX))
continue; continue;
if (nfs_file_open_context(fl->fl_file)->state != state) if (nfs_file_open_context(fl->fl_file)->state != state)
continue; continue;
...@@ -1408,6 +1409,43 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ ...@@ -1408,6 +1409,43 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
} }
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
} }
if (!flctx)
goto out_unlock;
list_for_each_entry(fl, &flctx->flc_flock, fl_list) {
if (nfs_file_open_context(fl->fl_file)->state != state)
continue;
spin_unlock(&inode->i_lock);
status = ops->recover_lock(state, fl);
switch (status) {
case 0:
break;
case -ESTALE:
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_EXPIRED:
case -NFS4ERR_NO_GRACE:
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_BADSESSION:
case -NFS4ERR_BADSLOT:
case -NFS4ERR_BAD_HIGH_SLOT:
case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
goto out;
default:
pr_err("NFS: %s: unhandled error %d\n",
__func__, status);
case -ENOMEM:
case -NFS4ERR_DENIED:
case -NFS4ERR_RECLAIM_BAD:
case -NFS4ERR_RECLAIM_CONFLICT:
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
status = 0;
}
spin_lock(&inode->i_lock);
}
out_unlock:
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
out: out:
up_write(&nfsi->rwsem); up_write(&nfsi->rwsem);
......
...@@ -826,6 +826,7 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, ...@@ -826,6 +826,7 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
struct nfs_pageio_descriptor *pgio) struct nfs_pageio_descriptor *pgio)
{ {
size_t size; size_t size;
struct file_lock_context *flctx;
if (prev) { if (prev) {
if (!nfs_match_open_context(req->wb_context, prev->wb_context)) if (!nfs_match_open_context(req->wb_context, prev->wb_context))
...@@ -834,6 +835,11 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, ...@@ -834,6 +835,11 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
!nfs_match_lock_context(req->wb_lock_context, !nfs_match_lock_context(req->wb_lock_context,
prev->wb_lock_context)) prev->wb_lock_context))
return false; return false;
flctx = req->wb_context->dentry->d_inode->i_flctx;
if (flctx != NULL && !list_empty_careful(&flctx->flc_flock) &&
!nfs_match_lock_context(req->wb_lock_context,
prev->wb_lock_context))
return false;
if (req_offset(req) != req_offset(prev) + prev->wb_bytes) if (req_offset(req) != req_offset(prev) + prev->wb_bytes)
return false; return false;
if (req->wb_page == prev->wb_page) { if (req->wb_page == prev->wb_page) {
......
...@@ -1113,6 +1113,11 @@ int nfs_flush_incompatible(struct file *file, struct page *page) ...@@ -1113,6 +1113,11 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
do_flush |= l_ctx->lockowner.l_owner != current->files do_flush |= l_ctx->lockowner.l_owner != current->files
|| l_ctx->lockowner.l_pid != current->tgid; || l_ctx->lockowner.l_pid != current->tgid;
} }
if (l_ctx && ctx->dentry->d_inode->i_flctx &&
!list_empty_careful(&ctx->dentry->d_inode->i_flctx->flc_flock)) {
do_flush |= l_ctx->lockowner.l_owner != current->files
|| l_ctx->lockowner.l_pid != current->tgid;
}
nfs_release_request(req); nfs_release_request(req);
if (!do_flush) if (!do_flush)
return 0; return 0;
...@@ -1170,6 +1175,13 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode) ...@@ -1170,6 +1175,13 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode)
return PageUptodate(page) != 0; return PageUptodate(page) != 0;
} }
static bool
is_whole_file_wrlock(struct file_lock *fl)
{
return fl->fl_start == 0 && fl->fl_end == OFFSET_MAX &&
fl->fl_type == F_WRLCK;
}
/* If we know the page is up to date, and we're not using byte range locks (or /* If we know the page is up to date, and we're not using byte range locks (or
* if we have the whole file locked for writing), it may be more efficient to * if we have the whole file locked for writing), it may be more efficient to
* extend the write to cover the entire page in order to avoid fragmentation * extend the write to cover the entire page in order to avoid fragmentation
...@@ -1180,17 +1192,38 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode) ...@@ -1180,17 +1192,38 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode)
*/ */
static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode) static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode)
{ {
int ret;
struct file_lock_context *flctx = inode->i_flctx;
struct file_lock *fl;
if (file->f_flags & O_DSYNC) if (file->f_flags & O_DSYNC)
return 0; return 0;
if (!nfs_write_pageuptodate(page, inode)) if (!nfs_write_pageuptodate(page, inode))
return 0; return 0;
if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
return 1; return 1;
if (inode->i_flock == NULL || (inode->i_flock->fl_start == 0 && if (!inode->i_flock && !flctx)
inode->i_flock->fl_end == OFFSET_MAX && return 0;
inode->i_flock->fl_type != F_RDLCK))
return 1; /* Check to see if there are whole file write locks */
return 0; spin_lock(&inode->i_lock);
ret = 0;
fl = inode->i_flock;
if (fl && is_whole_file_wrlock(fl)) {
ret = 1;
goto out;
}
if (!list_empty(&flctx->flc_flock)) {
fl = list_first_entry(&flctx->flc_flock, struct file_lock,
fl_list);
if (fl->fl_type == F_WRLCK)
ret = 1;
}
out:
spin_unlock(&inode->i_lock);
return ret;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment