linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeff Layton <jlayton@poochiereds.net>
To: Benjamin Coddington <bcodding@redhat.com>,
	Trond Myklebust <trond.myklebust@primarydata.com>,
	Anna Schumaker <anna.schumaker@netapp.com>,
	bfields@fieldses.org, Miklos Szeredi <miklos@szeredi.hu>,
	Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-nfs@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH 6/6] NFS: Always wait for I/O completion before unlock
Date: Fri, 07 Apr 2017 08:22:22 -0400	[thread overview]
Message-ID: <1491567742.2745.10.camel@poochiereds.net> (raw)
In-Reply-To: <0351835c423970c9171e446e918ac3d3d2fe854e.1491477181.git.bcodding@redhat.com>

On Thu, 2017-04-06 at 07:23 -0400, Benjamin Coddington wrote:
> 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.
> 

Dare I ask about v2? :)

Hmm actually, it looks like v2 could use the same operations as v3. I
don't see anything protocol-specific there.

> Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
> ---
>  fs/nfs/file.c     | 10 +++++-----
>  fs/nfs/nfs3proc.c | 38 +++++++++++++++++++++++++++++++++++++-
>  fs/nfs/nfs4proc.c | 10 +++++++---
>  3 files changed, 49 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/nfs/file.c b/fs/nfs/file.c
> index a490f45df4db..df695f52bb9d 100644
> --- a/fs/nfs/file.c
> +++ b/fs/nfs/file.c
> @@ -697,14 +697,14 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
>  	if (!IS_ERR(l_ctx)) {
>  		status = nfs_iocounter_wait(l_ctx);
>  		nfs_put_lock_context(l_ctx);
> -		if (status < 0)
> +		/*  NOTE: special case
> +		 * 	If we're signalled while cleaning up locks on process exit, we
> +		 * 	still need to complete the unlock.
> +		 */
> +		if (status < 0 && !(fl->fl_flags & FL_CLOSE))
>  			return status;
>  	}
>  
> -	/* NOTE: special case
> -	 * 	If we're signalled while cleaning up locks on process exit, we
> -	 * 	still need to complete the unlock.
> -	 */
>  	/*
>  	 * Use local locking if mounted with "-onolock" or with appropriate
>  	 * "-olocal_lock="
> diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
> index 086623ab07b1..0e21306bfed9 100644
> --- a/fs/nfs/nfs3proc.c
> +++ b/fs/nfs/nfs3proc.c
> @@ -865,12 +865,48 @@ static void nfs3_proc_commit_setup(struct nfs_commit_data *data, struct rpc_mess
>  	msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT];
>  }
>  
> +void nfs3_nlm_alloc_call(void *data)
> +{
> +	struct nfs_lock_context *l_ctx = data;
> +	nfs_get_lock_context(l_ctx->open_context);
> +}
> +
> +void nfs3_nlm_release_call(void *data)
> +{
> +	struct nfs_lock_context *l_ctx = data;
> +	nfs_put_lock_context(l_ctx);
> +}
> +
> +const struct nlmclnt_operations nlmclnt_fl_close_lock_ops = {
> +	.nlmclnt_alloc_call = nfs3_nlm_alloc_call,
> +	.nlmclnt_unlock_prepare = nfs_async_iocounter_wait,
> +	.nlmclnt_release_call = nfs3_nlm_release_call,
> +};
> +
>  static int
>  nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
>  {
>  	struct inode *inode = file_inode(filp);
> +	struct nfs_lock_context *l_ctx = NULL;
> +	const struct nlmclnt_operations *nlmclnt_ops = NULL;
> +	int status;
>  
> -	return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL, NULL);
> +	if (fl->fl_flags & FL_CLOSE) {
> +		l_ctx = nfs_get_lock_context(nfs_file_open_context(filp));
> +		if (IS_ERR(l_ctx)) {
> +			l_ctx = NULL;
> +		} else {
> +			set_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags);
> +			nlmclnt_ops = &nlmclnt_fl_close_lock_ops;

FWIW, I'm not a huge fan of using the pointer to indicate whether to run
the operations or not. IMO, it'd be cleaner to:

1) store the pointer to the operations struct in the nlm_host, pass it a
pointer to it in the nlmclnt_initdata.

2) make the decision to do the operations or not based on the setting of
NFS_CONTEXT_UNLOCK in the callbacks themselves. If it's not set, just
return quickly without doing anything.

> +		}
> +	}
> +
> +	status = nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl,
> +				nlmclnt_ops, l_ctx);
> +	if (l_ctx)
> +		nfs_put_lock_context(l_ctx);
> +
> +	return status;
>  }
>  
>  static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 91f88bfbbe79..e46cc2be60e2 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -5905,7 +5905,7 @@ struct nfs4_unlockdata {
>  	struct nfs_locku_args arg;
>  	struct nfs_locku_res res;
>  	struct nfs4_lock_state *lsp;
> -	struct nfs_open_context *ctx;
> +	struct nfs_lock_context *l_ctx;
>  	struct file_lock fl;
>  	struct nfs_server *server;
>  	unsigned long timestamp;
> @@ -5929,7 +5929,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
>  	p->lsp = lsp;
>  	atomic_inc(&lsp->ls_count);
>  	/* Ensure we don't close file until we're done freeing locks! */
> -	p->ctx = get_nfs_open_context(ctx);
> +	p->l_ctx = nfs_get_lock_context(ctx);
>  	memcpy(&p->fl, fl, sizeof(p->fl));
>  	p->server = NFS_SERVER(inode);
>  	return p;
> @@ -5940,7 +5940,7 @@ static void nfs4_locku_release_calldata(void *data)
>  	struct nfs4_unlockdata *calldata = data;
>  	nfs_free_seqid(calldata->arg.seqid);
>  	nfs4_put_lock_state(calldata->lsp);
> -	put_nfs_open_context(calldata->ctx);
> +	nfs_put_lock_context(calldata->l_ctx);
>  	kfree(calldata);
>  }
>  
> @@ -5981,6 +5981,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
>  {
>  	struct nfs4_unlockdata *calldata = data;
>  
> +	if (calldata->fl.fl_flags & FL_CLOSE &&
> +		nfs_async_iocounter_wait(task, calldata->l_ctx))
> +		return;
> +
>  	if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
>  		goto out_wait;
>  	nfs4_stateid_copy(&calldata->arg.stateid, &calldata->lsp->ls_stateid);

-- 
Jeff Layton <jlayton@poochiereds.net>

  reply	other threads:[~2017-04-07 12:22 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-06 11:23 [PATCH v5 0/6] Skipped unlocks Benjamin Coddington
2017-04-06 11:23 ` [PATCH 1/6] NFS4: remove a redundant lock range check Benjamin Coddington
2017-04-06 11:23 ` [PATCH 2/6] NFS: Move the flock open mode check into nfs_flock() Benjamin Coddington
2017-04-06 11:23 ` [PATCH 3/6] locks: Set FL_CLOSE when removing flock locks on close() Benjamin Coddington
2017-04-06 18:17   ` Jeff Layton
2017-04-08  5:34   ` kbuild test robot
2017-04-06 11:23 ` [PATCH 4/6] NFS: Add an iocounter wait function for async RPC tasks Benjamin Coddington
2017-04-07 10:44   ` Jeff Layton
2017-04-07 11:26     ` Benjamin Coddington
2017-04-06 11:23 ` [PATCH 5/6] lockd: Introduce nlmclnt_operations Benjamin Coddington
2017-04-07 12:10   ` Jeff Layton
2017-04-06 11:23 ` [PATCH 6/6] NFS: Always wait for I/O completion before unlock Benjamin Coddington
2017-04-07 12:22   ` Jeff Layton [this message]
2017-04-07 13:34     ` Benjamin Coddington
  -- strict thread matches above, loose matches on Subject: below --
2017-04-11 16:50 [PATCH v6 0/6] Skipped unlocks Benjamin Coddington
2017-04-11 16:50 ` [PATCH 6/6] NFS: Always wait for I/O completion before unlock Benjamin Coddington
2017-04-21 12:32   ` Jeff Layton
2017-04-01  3:15 [PATCH v4 0/6] Skipped unlocks Benjamin Coddington
2017-04-01  3:16 ` [PATCH 6/6] NFS: Always wait for I/O completion before unlock Benjamin Coddington

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1491567742.2745.10.camel@poochiereds.net \
    --to=jlayton@poochiereds.net \
    --cc=anna.schumaker@netapp.com \
    --cc=bcodding@redhat.com \
    --cc=bfields@fieldses.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=trond.myklebust@primarydata.com \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).