diff mbox series

[RFC,2/3] nfsd: rework arguments to nfs4_set_delegation

Message ID 20220714152819.128276-3-jlayton@kernel.org (mailing list archive)
State New, archived
Headers show
Series nfsd: close potential race between open and setting delegation | expand

Commit Message

Jeff Layton July 14, 2022, 3:28 p.m. UTC
We'll need the nfs4_open to vet the filename. Change nfs4_set_delegation
to take the same arguments are nfs4_open_delegation.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/nfsd/nfs4state.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

Comments

Chuck Lever III July 14, 2022, 4:47 p.m. UTC | #1
> On Jul 14, 2022, at 11:28 AM, Jeff Layton <jlayton@kernel.org> wrote:
> 
> We'll need the nfs4_open to vet the filename. Change nfs4_set_delegation
> to take the same arguments are nfs4_open_delegation.

^are^as

Nit: Considering that in the next patch you change the synopsis of
nfs4_open_delegation again but not nfs4_set_delegation, this
description causes a little whiplash.


> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
> fs/nfsd/nfs4state.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 4f81c0bbd27b..347794028c98 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -5260,10 +5260,12 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
> }
> 
> static struct nfs4_delegation *
> -nfs4_set_delegation(struct nfs4_client *clp,
> -		    struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
> +nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
> {
> 	int status = 0;
> +	struct nfs4_client *clp = stp->st_stid.sc_client;
> +	struct nfs4_file *fp = stp->st_stid.sc_file;
> +	struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
> 	struct nfs4_delegation *dp;
> 	struct nfsd_file *nf;
> 	struct file_lock *fl;
> @@ -5405,7 +5407,7 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
> 		default:
> 			goto out_no_deleg;
> 	}
> -	dp = nfs4_set_delegation(clp, stp->st_stid.sc_file, stp->st_clnt_odstate);
> +	dp = nfs4_set_delegation(open, stp);
> 	if (IS_ERR(dp))
> 		goto out_no_deleg;
> 
> -- 
> 2.36.1
> 

--
Chuck Lever
Jeff Layton July 14, 2022, 5:12 p.m. UTC | #2
On Thu, 2022-07-14 at 16:47 +0000, Chuck Lever III wrote:
> 
> > On Jul 14, 2022, at 11:28 AM, Jeff Layton <jlayton@kernel.org> wrote:
> > 
> > We'll need the nfs4_open to vet the filename. Change nfs4_set_delegation
> > to take the same arguments are nfs4_open_delegation.
> 
> ^are^as
> 
> Nit: Considering that in the next patch you change the synopsis of
> nfs4_open_delegation again but not nfs4_set_delegation, this
> description causes a little whiplash.
> 
> 

Yeah, I should have squashed a couple of those together. I _did_ say it
was an RFC. I can resend a cleaned-up version later if you want to take
this in.

> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> > fs/nfsd/nfs4state.c | 8 +++++---
> > 1 file changed, 5 insertions(+), 3 deletions(-)
> > 
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index 4f81c0bbd27b..347794028c98 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -5260,10 +5260,12 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
> > }
> > 
> > static struct nfs4_delegation *
> > -nfs4_set_delegation(struct nfs4_client *clp,
> > -		    struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
> > +nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
> > {
> > 	int status = 0;
> > +	struct nfs4_client *clp = stp->st_stid.sc_client;
> > +	struct nfs4_file *fp = stp->st_stid.sc_file;
> > +	struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
> > 	struct nfs4_delegation *dp;
> > 	struct nfsd_file *nf;
> > 	struct file_lock *fl;
> > @@ -5405,7 +5407,7 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
> > 		default:
> > 			goto out_no_deleg;
> > 	}
> > -	dp = nfs4_set_delegation(clp, stp->st_stid.sc_file, stp->st_clnt_odstate);
> > +	dp = nfs4_set_delegation(open, stp);
> > 	if (IS_ERR(dp))
> > 		goto out_no_deleg;
> > 
> > -- 
> > 2.36.1
> > 
> 
> --
> Chuck Lever
> 
> 
>
Chuck Lever III July 14, 2022, 5:14 p.m. UTC | #3
> On Jul 14, 2022, at 1:12 PM, Jeff Layton <jlayton@kernel.org> wrote:
> 
> On Thu, 2022-07-14 at 16:47 +0000, Chuck Lever III wrote:
>> 
>>> On Jul 14, 2022, at 11:28 AM, Jeff Layton <jlayton@kernel.org> wrote:
>>> 
>>> We'll need the nfs4_open to vet the filename. Change nfs4_set_delegation
>>> to take the same arguments are nfs4_open_delegation.
>> 
>> ^are^as
>> 
>> Nit: Considering that in the next patch you change the synopsis of
>> nfs4_open_delegation again but not nfs4_set_delegation, this
>> description causes a little whiplash.
>> 
>> 
> 
> Yeah, I should have squashed a couple of those together. I _did_ say it
> was an RFC. I can resend a cleaned-up version later if you want to take
> this in.

I'm interested in Neil's thoughts about this approach, but I'm
willing to run with it unless test results show a regression.


>>> Signed-off-by: Jeff Layton <jlayton@kernel.org>
>>> ---
>>> fs/nfsd/nfs4state.c | 8 +++++---
>>> 1 file changed, 5 insertions(+), 3 deletions(-)
>>> 
>>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>>> index 4f81c0bbd27b..347794028c98 100644
>>> --- a/fs/nfsd/nfs4state.c
>>> +++ b/fs/nfsd/nfs4state.c
>>> @@ -5260,10 +5260,12 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
>>> }
>>> 
>>> static struct nfs4_delegation *
>>> -nfs4_set_delegation(struct nfs4_client *clp,
>>> -		 struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
>>> +nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
>>> {
>>> 	int status = 0;
>>> +	struct nfs4_client *clp = stp->st_stid.sc_client;
>>> +	struct nfs4_file *fp = stp->st_stid.sc_file;
>>> +	struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
>>> 	struct nfs4_delegation *dp;
>>> 	struct nfsd_file *nf;
>>> 	struct file_lock *fl;
>>> @@ -5405,7 +5407,7 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
>>> 		default:
>>> 			goto out_no_deleg;
>>> 	}
>>> -	dp = nfs4_set_delegation(clp, stp->st_stid.sc_file, stp->st_clnt_odstate);
>>> +	dp = nfs4_set_delegation(open, stp);
>>> 	if (IS_ERR(dp))
>>> 		goto out_no_deleg;
>>> 
>>> -- 
>>> 2.36.1
>>> 
>> 
>> --
>> Chuck Lever
>> 
>> 
>> 
> 
> -- 
> Jeff Layton <jlayton@kernel.org>

--
Chuck Lever
Jeff Layton July 14, 2022, 6:59 p.m. UTC | #4
On Thu, 2022-07-14 at 17:14 +0000, Chuck Lever III wrote:
>  
> 
> > On Jul 14, 2022, at 1:12 PM, Jeff Layton <jlayton@kernel.org> wrote:
> > 
> > On Thu, 2022-07-14 at 16:47 +0000, Chuck Lever III wrote:
> > > 
> > > > On Jul 14, 2022, at 11:28 AM, Jeff Layton <jlayton@kernel.org> wrote:
> > > > 
> > > > We'll need the nfs4_open to vet the filename. Change nfs4_set_delegation
> > > > to take the same arguments are nfs4_open_delegation.
> > > 
> > > ^are^as
> > > 
> > > Nit: Considering that in the next patch you change the synopsis of
> > > nfs4_open_delegation again but not nfs4_set_delegation, this
> > > description causes a little whiplash.
> > > 
> > > 
> > 
> > Yeah, I should have squashed a couple of those together. I _did_ say it
> > was an RFC. I can resend a cleaned-up version later if you want to take
> > this in.
> 
> I'm interested in Neil's thoughts about this approach, but I'm
> willing to run with it unless test results show a regression.
> 
> 

...and there is a regression. Partial lockdep pop here:

Jul 14 14:46:54 quad3 kernel: ============================================
Jul 14 14:46:54 quad3 kernel: WARNING: possible recursive locking detected
Jul 14 14:46:54 quad3 kernel: 5.19.0-rc5+ #316 Tainted: G           OE    
Jul 14 14:46:54 quad3 kernel: --------------------------------------------
Jul 14 14:46:54 quad3 kernel: nfsd/1148 is trying to acquire lock:
Jul 14 14:46:54 quad3 kernel: ffff88812a3a7388 (&inode->i_sb->s_type->i_mutex_dir_key/1){++++}-{3:3}, at: nfsd4_process_open2+0x1890/0x2710 [nfsd]
Jul 14 14:46:54 quad3 kernel: 
                              but task is already holding lock:
Jul 14 14:46:54 quad3 kernel: ffff88812a3a7388 (&inode->i_sb->s_type->i_mutex_dir_key/1){++++}-{3:3}, at: nfsd_lookup_dentry+0x16f/0x6a0 [nfsd]
Jul 14 14:46:54 quad3 kernel: 
                              other info that might help us debug this:
Jul 14 14:46:54 quad3 kernel:  Possible unsafe locking scenario:
Jul 14 14:46:54 quad3 kernel:        CPU0
Jul 14 14:46:54 quad3 kernel:        ----
Jul 14 14:46:54 quad3 kernel:   lock(&inode->i_sb->s_type->i_mutex_dir_key/1);
Jul 14 14:46:54 quad3 kernel:   lock(&inode->i_sb->s_type->i_mutex_dir_key/1);
Jul 14 14:46:54 quad3 kernel: 
                               *** DEADLOCK ***
Jul 14 14:46:54 quad3 kernel:  May be due to missing lock nesting notation
Jul 14 14:46:54 quad3 kernel: 1 lock held by nfsd/1148:
Jul 14 14:46:54 quad3 kernel:  #0: ffff88812a3a7388 (&inode->i_sb->s_type->i_mutex_dir_key/1){++++}-{3:3}, at: nfsd_lookup_dentry+0x16f/0x6a0 [nfsd]
Jul 14 14:46:54 quad3 kernel: 


The core problem is the unclear locking in nfsd_lookup_dentry. Sometimes
that returns with the i_rwsem held, but there's no clear indication of
whether that's the case when the function returns. I guess fh_unlock
just takes care of that (which is a little scary, tbqh).

Now that I've taken a stab at it, I don't see how we can fix this w/o
taking Neil's locking cleanups series first. I think I'll pull that in
and try to redo this series on top of it.

Cheers,
diff mbox series

Patch

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 4f81c0bbd27b..347794028c98 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5260,10 +5260,12 @@  static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
 }
 
 static struct nfs4_delegation *
-nfs4_set_delegation(struct nfs4_client *clp,
-		    struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
+nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
 {
 	int status = 0;
+	struct nfs4_client *clp = stp->st_stid.sc_client;
+	struct nfs4_file *fp = stp->st_stid.sc_file;
+	struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
 	struct nfs4_delegation *dp;
 	struct nfsd_file *nf;
 	struct file_lock *fl;
@@ -5405,7 +5407,7 @@  nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
 		default:
 			goto out_no_deleg;
 	}
-	dp = nfs4_set_delegation(clp, stp->st_stid.sc_file, stp->st_clnt_odstate);
+	dp = nfs4_set_delegation(open, stp);
 	if (IS_ERR(dp))
 		goto out_no_deleg;