Skip to content

Commit f30cb75

Browse files
bcodding-rhtrondmypd
authored andcommitted
NFS: Always wait for I/O completion before unlock
NFS attempts to wait for read and write completion before unlocking in order to ensure that the data returned was protected by the lock. When this waiting is interrupted by a signal, the unlock may be skipped, and messages similar to the following are seen in the kernel ring buffer: [20.167876] Leaked locks on dev=0x0:0x2b ino=0x8dd4c3: [20.168286] POSIX: fl_owner=ffff880078b06940 fl_flags=0x1 fl_type=0x0 fl_pid=20183 [20.168727] POSIX: fl_owner=ffff880078b06680 fl_flags=0x1 fl_type=0x0 fl_pid=20185 For NFSv3, the missing unlock will cause the server to refuse conflicting locks indefinitely. For NFSv4, the leftover lock will be removed by the server after the lease timeout. This patch fixes this issue by skipping the usual wait in nfs_iocounter_wait if the FL_CLOSE flag is set when signaled. Instead, the wait happens in the unlock RPC task on the NFS UOC rpc_waitqueue. For NFSv3, use lockd's new nlmclnt_operations along with nfs_async_iocounter_wait to defer NLM's unlock task until the lock context's iocounter reaches zero. For NFSv4, call nfs_async_iocounter_wait() directly from unlock's current rpc_call_prepare. Signed-off-by: Benjamin Coddington <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent b1ece73 commit f30cb75

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

fs/nfs/file.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -697,14 +697,14 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
697697
if (!IS_ERR(l_ctx)) {
698698
status = nfs_iocounter_wait(l_ctx);
699699
nfs_put_lock_context(l_ctx);
700-
if (status < 0)
700+
/* NOTE: special case
701+
* If we're signalled while cleaning up locks on process exit, we
702+
* still need to complete the unlock.
703+
*/
704+
if (status < 0 && !(fl->fl_flags & FL_CLOSE))
701705
return status;
702706
}
703707

704-
/* NOTE: special case
705-
* If we're signalled while cleaning up locks on process exit, we
706-
* still need to complete the unlock.
707-
*/
708708
/*
709709
* Use local locking if mounted with "-onolock" or with appropriate
710710
* "-olocal_lock="

fs/nfs/nfs3proc.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,12 +865,63 @@ static void nfs3_proc_commit_setup(struct nfs_commit_data *data, struct rpc_mess
865865
msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT];
866866
}
867867

868+
void nfs3_nlm_alloc_call(void *data)
869+
{
870+
struct nfs_lock_context *l_ctx = data;
871+
if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags)) {
872+
get_nfs_open_context(l_ctx->open_context);
873+
nfs_get_lock_context(l_ctx->open_context);
874+
}
875+
}
876+
877+
bool nfs3_nlm_unlock_prepare(struct rpc_task *task, void *data)
878+
{
879+
struct nfs_lock_context *l_ctx = data;
880+
if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags))
881+
return nfs_async_iocounter_wait(task, l_ctx);
882+
return false;
883+
884+
}
885+
886+
void nfs3_nlm_release_call(void *data)
887+
{
888+
struct nfs_lock_context *l_ctx = data;
889+
struct nfs_open_context *ctx;
890+
if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags)) {
891+
ctx = l_ctx->open_context;
892+
nfs_put_lock_context(l_ctx);
893+
put_nfs_open_context(ctx);
894+
}
895+
}
896+
897+
const struct nlmclnt_operations nlmclnt_fl_close_lock_ops = {
898+
.nlmclnt_alloc_call = nfs3_nlm_alloc_call,
899+
.nlmclnt_unlock_prepare = nfs3_nlm_unlock_prepare,
900+
.nlmclnt_release_call = nfs3_nlm_release_call,
901+
};
902+
868903
static int
869904
nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
870905
{
871906
struct inode *inode = file_inode(filp);
907+
struct nfs_lock_context *l_ctx = NULL;
908+
struct nfs_open_context *ctx = nfs_file_open_context(filp);
909+
int status;
872910

873-
return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL);
911+
if (fl->fl_flags & FL_CLOSE) {
912+
l_ctx = nfs_get_lock_context(ctx);
913+
if (IS_ERR(l_ctx))
914+
l_ctx = NULL;
915+
else
916+
set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
917+
}
918+
919+
status = nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, l_ctx);
920+
921+
if (l_ctx)
922+
nfs_put_lock_context(l_ctx);
923+
924+
return status;
874925
}
875926

876927
static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
@@ -921,6 +972,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
921972
.dir_inode_ops = &nfs3_dir_inode_operations,
922973
.file_inode_ops = &nfs3_file_inode_operations,
923974
.file_ops = &nfs_file_operations,
975+
.nlmclnt_ops = &nlmclnt_fl_close_lock_ops,
924976
.getroot = nfs3_proc_get_root,
925977
.submount = nfs_submount,
926978
.try_mount = nfs_try_mount,

fs/nfs/nfs4proc.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5784,6 +5784,7 @@ struct nfs4_unlockdata {
57845784
struct nfs_locku_res res;
57855785
struct nfs4_lock_state *lsp;
57865786
struct nfs_open_context *ctx;
5787+
struct nfs_lock_context *l_ctx;
57875788
struct file_lock fl;
57885789
struct nfs_server *server;
57895790
unsigned long timestamp;
@@ -5808,6 +5809,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
58085809
atomic_inc(&lsp->ls_count);
58095810
/* Ensure we don't close file until we're done freeing locks! */
58105811
p->ctx = get_nfs_open_context(ctx);
5812+
p->l_ctx = nfs_get_lock_context(ctx);
58115813
memcpy(&p->fl, fl, sizeof(p->fl));
58125814
p->server = NFS_SERVER(inode);
58135815
return p;
@@ -5818,6 +5820,7 @@ static void nfs4_locku_release_calldata(void *data)
58185820
struct nfs4_unlockdata *calldata = data;
58195821
nfs_free_seqid(calldata->arg.seqid);
58205822
nfs4_put_lock_state(calldata->lsp);
5823+
nfs_put_lock_context(calldata->l_ctx);
58215824
put_nfs_open_context(calldata->ctx);
58225825
kfree(calldata);
58235826
}
@@ -5859,6 +5862,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
58595862
{
58605863
struct nfs4_unlockdata *calldata = data;
58615864

5865+
if (test_bit(NFS_CONTEXT_UNLOCK, &calldata->l_ctx->open_context->flags) &&
5866+
nfs_async_iocounter_wait(task, calldata->l_ctx))
5867+
return;
5868+
58625869
if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
58635870
goto out_wait;
58645871
nfs4_stateid_copy(&calldata->arg.stateid, &calldata->lsp->ls_stateid);
@@ -5910,6 +5917,8 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
59105917
* canceled lock is passed in, and it won't be an unlock.
59115918
*/
59125919
fl->fl_type = F_UNLCK;
5920+
if (fl->fl_flags & FL_CLOSE)
5921+
set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
59135922

59145923
data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
59155924
if (data == NULL) {

0 commit comments

Comments
 (0)