Linux NFS development
 help / color / mirror / Atom feed
* question about code in delegation.c
@ 2014-12-19 15:11 Olga Kornievskaia
  2014-12-19 15:37 ` Trond Myklebust
  0 siblings, 1 reply; 18+ messages in thread
From: Olga Kornievskaia @ 2014-12-19 15:11 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

Hi Trond,

I have a question about a patch you committed 57bfa891 and
specifically about the comment that's in the code saying "deal with
the broken servers that hand out two delegations for the same file".
Why is this considered to be broken?

The situation I'm experiencing has the following flow:
1. client opens a file and gets a write delegation.
2. this file is then closed, it's subsequently locally opened for
write (no open on the wire). delegation stateid is also used for write
operations seen on the wire. all is good.
3. then client (on the wire) sends an open for read. first i'm not
sure why this is not local. but let's say the client is allowed to do
so.
4. the server knows this client has a write delegation for this file
so it replies to the open with the write delegation.
5. then code in "nfs_node_set_delegation" sees that it's the same
delegation and ends up returning "it". however from the server's point
of you, it considers the client returning the one delegation it gave
out.
6. the client proceeds to use the delegation stateid which causes the
server to send BAD_SESSIONID which leads the client to initiate state
recovery and mark it's locks lost and return EIO.

(a) it seems like the open for read shouldn't have gone on the wire to
begin with, but
(b) if there are cases when we do want to send an open even if we hold
a delegation, then shouldn't we just ignore if we receive the same
delegation that already hold?

Thank you.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: question about code in delegation.c
  2014-12-19 15:11 question about code in delegation.c Olga Kornievskaia
@ 2014-12-19 15:37 ` Trond Myklebust
  2014-12-19 16:01   ` Olga Kornievskaia
  0 siblings, 1 reply; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 15:37 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

Hi Olga

On Fri, Dec 19, 2014 at 10:11 AM, Olga Kornievskaia <aglo@umich.edu> wrote:
> Hi Trond,
>
> I have a question about a patch you committed 57bfa891 and
> specifically about the comment that's in the code saying "deal with
> the broken servers that hand out two delegations for the same file".
> Why is this considered to be broken?
>
> The situation I'm experiencing has the following flow:
> 1. client opens a file and gets a write delegation.
> 2. this file is then closed, it's subsequently locally opened for
> write (no open on the wire). delegation stateid is also used for write
> operations seen on the wire. all is good.
> 3. then client (on the wire) sends an open for read. first i'm not
> sure why this is not local. but let's say the client is allowed to do
> so.

Does the client know that this is the same file? i.e. is this a
situation where it is using the same directory filehandle + filename
in the open?

> 4. the server knows this client has a write delegation for this file
> so it replies to the open with the write delegation.
> 5. then code in "nfs_node_set_delegation" sees that it's the same
> delegation and ends up returning "it". however from the server's point
> of you, it considers the client returning the one delegation it gave
> out.

It won't return a delegation with a matching stateid and _type_ to the
one it already holds.

That said, the code should probably make a distinction here:

1) If the delegation stateid matches, we shouldn't delegreturn.
Instead, just check the delegation type and try to figure out if this
is an upgrade from a read delegation to a write delegation.
or
2) If the delegation stateid doesn't match, figure out whether or not
this is a delegation upgrade, and either discard the old stateid if it
is (good server) or discard the new stateid if it isn't (broken
server). Issue delegreturn for the stateid we're discarding.

> 6. the client proceeds to use the delegation stateid which causes the
> server to send BAD_SESSIONID which leads the client to initiate state
> recovery and mark it's locks lost and return EIO.

BAD_SESSIONID? That's just wrong...

> (a) it seems like the open for read shouldn't have gone on the wire to
> begin with, but
> (b) if there are cases when we do want to send an open even if we hold
> a delegation, then shouldn't we just ignore if we receive the same
> delegation that already hold?
>
> Thank you.



-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: question about code in delegation.c
  2014-12-19 15:37 ` Trond Myklebust
@ 2014-12-19 16:01   ` Olga Kornievskaia
  2014-12-19 18:10     ` [PATCH 1/2] NFSv4: Deal with atomic upgrades of an existing delegation Trond Myklebust
  2014-12-19 18:10     ` [PATCH " Trond Myklebust
  0 siblings, 2 replies; 18+ messages in thread
From: Olga Kornievskaia @ 2014-12-19 16:01 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Dec 19, 2014 at 10:37 AM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> Hi Olga
>
> On Fri, Dec 19, 2014 at 10:11 AM, Olga Kornievskaia <aglo@umich.edu> wrote:
>> Hi Trond,
>>
>> I have a question about a patch you committed 57bfa891 and
>> specifically about the comment that's in the code saying "deal with
>> the broken servers that hand out two delegations for the same file".
>> Why is this considered to be broken?
>>
>> The situation I'm experiencing has the following flow:
>> 1. client opens a file and gets a write delegation.
>> 2. this file is then closed, it's subsequently locally opened for
>> write (no open on the wire). delegation stateid is also used for write
>> operations seen on the wire. all is good.
>> 3. then client (on the wire) sends an open for read. first i'm not
>> sure why this is not local. but let's say the client is allowed to do
>> so.
>
> Does the client know that this is the same file? i.e. is this a
> situation where it is using the same directory filehandle + filename
> in the open?
>
>> 4. the server knows this client has a write delegation for this file
>> so it replies to the open with the write delegation.
>> 5. then code in "nfs_node_set_delegation" sees that it's the same
>> delegation and ends up returning "it". however from the server's point
>> of you, it considers the client returning the one delegation it gave
>> out.
>
> It won't return a delegation with a matching stateid and _type_ to the
> one it already holds.
>
> That said, the code should probably make a distinction here:
>
> 1) If the delegation stateid matches, we shouldn't delegreturn.
> Instead, just check the delegation type and try to figure out if this
> is an upgrade from a read delegation to a write delegation.
> or
> 2) If the delegation stateid doesn't match, figure out whether or not
> this is a delegation upgrade, and either discard the old stateid if it
> is (good server) or discard the new stateid if it isn't (broken
> server). Issue delegreturn for the stateid we're discarding.
>
>> 6. the client proceeds to use the delegation stateid which causes the
>> server to send BAD_SESSIONID which leads the client to initiate state
>> recovery and mark it's locks lost and return EIO.
>
> BAD_SESSIONID? That's just wrong...

Sorry that was suppose to be BAD_STATEID. I see what you mean about
the same type of delegation should not be returned. I was staring at
that code for too long and miss read it. That would have been an easy
explanation for the erroneous DELEG_RETURN I'm see on submitted
traces. It's hard to debug when I can't reproduce the behavior.. :-/

Thank you for the explanation. I'll keep digging where the real client
brokenness lies.

>> (a) it seems like the open for read shouldn't have gone on the wire to
>> begin with, but
>> (b) if there are cases when we do want to send an open even if we hold
>> a delegation, then shouldn't we just ignore if we receive the same
>> delegation that already hold?
>>
>> Thank you.
>
>
>
> --
> Trond Myklebust
>
> Linux NFS client maintainer, PrimaryData
>
> trond.myklebust@primarydata.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/2] NFSv4: Deal with atomic upgrades of an existing delegation
  2014-12-19 16:01   ` Olga Kornievskaia
@ 2014-12-19 18:10     ` Trond Myklebust
  2014-12-19 18:51       ` Trond Myklebust
  2014-12-19 18:10     ` [PATCH " Trond Myklebust
  1 sibling, 1 reply; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 18:10 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

Ensure that we deal correctly with the case where the server sends us a
newer instance of the same delegation. If the stateids match, but the
sequence numbers differ, then treat the new delegation as if it were
an atomic upgrade.

Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
---
 fs/nfs/delegation.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 7f3f60641344..90413cdbf254 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -301,6 +301,18 @@ nfs_inode_detach_delegation(struct inode *inode)
 	return nfs_detach_delegation(nfsi, delegation, server);
 }
 
+static void
+nfs_update_inplace_delegation(struct nfs_delegation *delegation,
+		struct nfs_delegation *update)
+{
+	if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid))
+		return;
+	delegation->stateid.seqid = update->stateid.seqid;
+	smp_wmb();
+	delegation->type == update->type;
+	nfsi->delegation_state = update->type;
+}
+
 /**
  * nfs_inode_set_delegation - set up a delegation on an inode
  * @inode: inode to which delegation applies
@@ -334,9 +346,11 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
 	old_delegation = rcu_dereference_protected(nfsi->delegation,
 					lockdep_is_held(&clp->cl_lock));
 	if (old_delegation != NULL) {
-		if (nfs4_stateid_match(&delegation->stateid,
-					&old_delegation->stateid) &&
-				delegation->type == old_delegation->type) {
+		/* Is this an update of the existing delegation? */
+		if (nfs4_stateid_match_other(&old_delegation->stateid,
+					&delegation->stateid)) {
+			nfs_update_inplace_delegation(old_delegation,
+					delegation);
 			goto out;
 		}
 		/*
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/2] NFSv4: Remove incorrect check in can_open_delegated()
  2014-12-19 16:01   ` Olga Kornievskaia
  2014-12-19 18:10     ` [PATCH 1/2] NFSv4: Deal with atomic upgrades of an existing delegation Trond Myklebust
@ 2014-12-19 18:10     ` Trond Myklebust
  1 sibling, 0 replies; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 18:10 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

Remove an incorrect check for NFS_DELEGATION_NEED_RECLAIM in
can_open_delegated(). We are allowed to cache opens even in
a situation where we're doing reboot recovery.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfs/nfs4proc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 8514b59a8c30..002c7dfedb08 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1119,8 +1119,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
 		return 0;
 	if ((delegation->type & fmode) != fmode)
 		return 0;
-	if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
-		return 0;
 	if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
 		return 0;
 	nfs_mark_delegation_referenced(delegation);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] NFSv4: Deal with atomic upgrades of an existing delegation
  2014-12-19 18:10     ` [PATCH 1/2] NFSv4: Deal with atomic upgrades of an existing delegation Trond Myklebust
@ 2014-12-19 18:51       ` Trond Myklebust
  2014-12-19 18:52         ` [PATCH v2 " Trond Myklebust
  2014-12-19 18:52         ` [PATCH v2 " Trond Myklebust
  0 siblings, 2 replies; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 18:51 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

On Fri, Dec 19, 2014 at 1:10 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> Ensure that we deal correctly with the case where the server sends us a
> newer instance of the same delegation. If the stateids match, but the
> sequence numbers differ, then treat the new delegation as if it were
> an atomic upgrade.
>
> Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
> ---
>  fs/nfs/delegation.c | 20 +++++++++++++++++---
>  1 file changed, 17 insertions(+), 3 deletions(-)
>
> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
> index 7f3f60641344..90413cdbf254 100644
> --- a/fs/nfs/delegation.c
> +++ b/fs/nfs/delegation.c
> @@ -301,6 +301,18 @@ nfs_inode_detach_delegation(struct inode *inode)
>         return nfs_detach_delegation(nfsi, delegation, server);
>  }
>
> +static void
> +nfs_update_inplace_delegation(struct nfs_delegation *delegation,
> +               struct nfs_delegation *update)
> +{
> +       if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid))
> +               return;
> +       delegation->stateid.seqid = update->stateid.seqid;
> +       smp_wmb();
> +       delegation->type == update->type;
> +       nfsi->delegation_state = update->type;

Oops... That wasn't intended. I'll resend an update that actually compiles...

> +}
> +
>  /**
>   * nfs_inode_set_delegation - set up a delegation on an inode
>   * @inode: inode to which delegation applies
> @@ -334,9 +346,11 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
>         old_delegation = rcu_dereference_protected(nfsi->delegation,
>                                         lockdep_is_held(&clp->cl_lock));
>         if (old_delegation != NULL) {
> -               if (nfs4_stateid_match(&delegation->stateid,
> -                                       &old_delegation->stateid) &&
> -                               delegation->type == old_delegation->type) {
> +               /* Is this an update of the existing delegation? */
> +               if (nfs4_stateid_match_other(&old_delegation->stateid,
> +                                       &delegation->stateid)) {
> +                       nfs_update_inplace_delegation(old_delegation,
> +                                       delegation);
>                         goto out;
>                 }
>                 /*
> --
> 2.1.0
>



-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 1/2] NFSv4: Deal with atomic upgrades of an existing delegation
  2014-12-19 18:51       ` Trond Myklebust
@ 2014-12-19 18:52         ` Trond Myklebust
  2014-12-19 20:16           ` Olga Kornievskaia
  2014-12-19 20:31           ` Trond Myklebust
  2014-12-19 18:52         ` [PATCH v2 " Trond Myklebust
  1 sibling, 2 replies; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 18:52 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

Ensure that we deal correctly with the case where the server sends us a
newer instance of the same delegation. If the stateids match, but the
sequence numbers differ, then treat the new delegation as if it were
an atomic upgrade.

Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
---
 fs/nfs/delegation.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 7f3f60641344..02b5b2a6d557 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -301,6 +301,19 @@ nfs_inode_detach_delegation(struct inode *inode)
 	return nfs_detach_delegation(nfsi, delegation, server);
 }
 
+static void
+nfs_update_inplace_delegation(struct nfs_inode *nfsi,
+		struct nfs_delegation *delegation,
+		struct nfs_delegation *update)
+{
+	if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid))
+		return;
+	delegation->stateid.seqid = update->stateid.seqid;
+	smp_wmb();
+	delegation->type = update->type;
+	nfsi->delegation_state = update->type;
+}
+
 /**
  * nfs_inode_set_delegation - set up a delegation on an inode
  * @inode: inode to which delegation applies
@@ -334,9 +347,11 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
 	old_delegation = rcu_dereference_protected(nfsi->delegation,
 					lockdep_is_held(&clp->cl_lock));
 	if (old_delegation != NULL) {
-		if (nfs4_stateid_match(&delegation->stateid,
-					&old_delegation->stateid) &&
-				delegation->type == old_delegation->type) {
+		/* Is this an update of the existing delegation? */
+		if (nfs4_stateid_match_other(&old_delegation->stateid,
+					&delegation->stateid)) {
+			nfs_update_inplace_delegation(nfsi, old_delegation,
+					delegation);
 			goto out;
 		}
 		/*
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 2/2] NFSv4: Remove incorrect check in can_open_delegated()
  2014-12-19 18:51       ` Trond Myklebust
  2014-12-19 18:52         ` [PATCH v2 " Trond Myklebust
@ 2014-12-19 18:52         ` Trond Myklebust
  1 sibling, 0 replies; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 18:52 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

Remove an incorrect check for NFS_DELEGATION_NEED_RECLAIM in
can_open_delegated(). We are allowed to cache opens even in
a situation where we're doing reboot recovery.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfs/nfs4proc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 8514b59a8c30..002c7dfedb08 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1119,8 +1119,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
 		return 0;
 	if ((delegation->type & fmode) != fmode)
 		return 0;
-	if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
-		return 0;
 	if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
 		return 0;
 	nfs_mark_delegation_referenced(delegation);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/2] NFSv4: Deal with atomic upgrades of an existing delegation
  2014-12-19 18:52         ` [PATCH v2 " Trond Myklebust
@ 2014-12-19 20:16           ` Olga Kornievskaia
  2014-12-19 20:31           ` Trond Myklebust
  1 sibling, 0 replies; 18+ messages in thread
From: Olga Kornievskaia @ 2014-12-19 20:16 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

Aha, yes yes yes, that would make sense how it is still returned if
seq ids are different. I'll have this tested asap.

On Fri, Dec 19, 2014 at 1:52 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> Ensure that we deal correctly with the case where the server sends us a
> newer instance of the same delegation. If the stateids match, but the
> sequence numbers differ, then treat the new delegation as if it were
> an atomic upgrade.
>
> Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
> ---
>  fs/nfs/delegation.c | 21 ++++++++++++++++++---
>  1 file changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
> index 7f3f60641344..02b5b2a6d557 100644
> --- a/fs/nfs/delegation.c
> +++ b/fs/nfs/delegation.c
> @@ -301,6 +301,19 @@ nfs_inode_detach_delegation(struct inode *inode)
>         return nfs_detach_delegation(nfsi, delegation, server);
>  }
>
> +static void
> +nfs_update_inplace_delegation(struct nfs_inode *nfsi,
> +               struct nfs_delegation *delegation,
> +               struct nfs_delegation *update)
> +{
> +       if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid))
> +               return;
> +       delegation->stateid.seqid = update->stateid.seqid;
> +       smp_wmb();
> +       delegation->type = update->type;
> +       nfsi->delegation_state = update->type;
> +}
> +
>  /**
>   * nfs_inode_set_delegation - set up a delegation on an inode
>   * @inode: inode to which delegation applies
> @@ -334,9 +347,11 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
>         old_delegation = rcu_dereference_protected(nfsi->delegation,
>                                         lockdep_is_held(&clp->cl_lock));
>         if (old_delegation != NULL) {
> -               if (nfs4_stateid_match(&delegation->stateid,
> -                                       &old_delegation->stateid) &&
> -                               delegation->type == old_delegation->type) {
> +               /* Is this an update of the existing delegation? */
> +               if (nfs4_stateid_match_other(&old_delegation->stateid,
> +                                       &delegation->stateid)) {
> +                       nfs_update_inplace_delegation(nfsi, old_delegation,
> +                                       delegation);
>                         goto out;
>                 }
>                 /*
> --
> 2.1.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/2] NFSv4: Deal with atomic upgrades of an existing delegation
  2014-12-19 18:52         ` [PATCH v2 " Trond Myklebust
  2014-12-19 20:16           ` Olga Kornievskaia
@ 2014-12-19 20:31           ` Trond Myklebust
  2014-12-19 20:39             ` Olga Kornievskaia
                               ` (2 more replies)
  1 sibling, 3 replies; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 20:31 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

On Fri, Dec 19, 2014 at 1:52 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> Ensure that we deal correctly with the case where the server sends us a
> newer instance of the same delegation. If the stateids match, but the
> sequence numbers differ, then treat the new delegation as if it were
> an atomic upgrade.
>
> Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
> ---
>  fs/nfs/delegation.c | 21 ++++++++++++++++++---
>  1 file changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
> index 7f3f60641344..02b5b2a6d557 100644
> --- a/fs/nfs/delegation.c
> +++ b/fs/nfs/delegation.c
> @@ -301,6 +301,19 @@ nfs_inode_detach_delegation(struct inode *inode)
>         return nfs_detach_delegation(nfsi, delegation, server);
>  }
>
> +static void
> +nfs_update_inplace_delegation(struct nfs_inode *nfsi,
> +               struct nfs_delegation *delegation,
> +               struct nfs_delegation *update)
> +{
> +       if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid))

...and the above comparison should be reversed.

> +               return;
> +       delegation->stateid.seqid = update->stateid.seqid;
> +       smp_wmb();
> +       delegation->type = update->type;
> +       nfsi->delegation_state = update->type;
> +}
> +
>  /**
>   * nfs_inode_set_delegation - set up a delegation on an inode
>   * @inode: inode to which delegation applies
> @@ -334,9 +347,11 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
>         old_delegation = rcu_dereference_protected(nfsi->delegation,
>                                         lockdep_is_held(&clp->cl_lock));
>         if (old_delegation != NULL) {
> -               if (nfs4_stateid_match(&delegation->stateid,
> -                                       &old_delegation->stateid) &&
> -                               delegation->type == old_delegation->type) {
> +               /* Is this an update of the existing delegation? */
> +               if (nfs4_stateid_match_other(&old_delegation->stateid,
> +                                       &delegation->stateid)) {
> +                       nfs_update_inplace_delegation(nfsi, old_delegation,
> +                                       delegation);
>                         goto out;
>                 }
>                 /*
> --
> 2.1.0
>



-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/2] NFSv4: Deal with atomic upgrades of an existing delegation
  2014-12-19 20:31           ` Trond Myklebust
@ 2014-12-19 20:39             ` Olga Kornievskaia
  2014-12-19 20:46               ` Trond Myklebust
  2014-12-19 20:44             ` [PATCH v3 " Trond Myklebust
  2014-12-19 20:44             ` [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated() Trond Myklebust
  2 siblings, 1 reply; 18+ messages in thread
From: Olga Kornievskaia @ 2014-12-19 20:39 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Dec 19, 2014 at 3:31 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> On Fri, Dec 19, 2014 at 1:52 PM, Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
>> Ensure that we deal correctly with the case where the server sends us a
>> newer instance of the same delegation. If the stateids match, but the
>> sequence numbers differ, then treat the new delegation as if it were
>> an atomic upgrade.
>>
>> Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
>> ---
>>  fs/nfs/delegation.c | 21 ++++++++++++++++++---
>>  1 file changed, 18 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
>> index 7f3f60641344..02b5b2a6d557 100644
>> --- a/fs/nfs/delegation.c
>> +++ b/fs/nfs/delegation.c
>> @@ -301,6 +301,19 @@ nfs_inode_detach_delegation(struct inode *inode)
>>         return nfs_detach_delegation(nfsi, delegation, server);
>>  }
>>
>> +static void
>> +nfs_update_inplace_delegation(struct nfs_inode *nfsi,
>> +               struct nfs_delegation *delegation,
>> +               struct nfs_delegation *update)
>> +{
>> +       if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid))
>
> ...and the above comparison should be reversed.

do you mean: if(!nfs4_stateid_is_newer())

but if we received a delegation stateid with sequence number lower
than what we have, shouldn't that be some kind of an error?

>
>> +               return;
>> +       delegation->stateid.seqid = update->stateid.seqid;
>> +       smp_wmb();
>> +       delegation->type = update->type;
>> +       nfsi->delegation_state = update->type;
>> +}
>> +
>>  /**
>>   * nfs_inode_set_delegation - set up a delegation on an inode
>>   * @inode: inode to which delegation applies
>> @@ -334,9 +347,11 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
>>         old_delegation = rcu_dereference_protected(nfsi->delegation,
>>                                         lockdep_is_held(&clp->cl_lock));
>>         if (old_delegation != NULL) {
>> -               if (nfs4_stateid_match(&delegation->stateid,
>> -                                       &old_delegation->stateid) &&
>> -                               delegation->type == old_delegation->type) {
>> +               /* Is this an update of the existing delegation? */
>> +               if (nfs4_stateid_match_other(&old_delegation->stateid,
>> +                                       &delegation->stateid)) {
>> +                       nfs_update_inplace_delegation(nfsi, old_delegation,
>> +                                       delegation);
>>                         goto out;
>>                 }
>>                 /*
>> --
>> 2.1.0
>>
>
>
>
> --
> Trond Myklebust
>
> Linux NFS client maintainer, PrimaryData
>
> trond.myklebust@primarydata.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3 1/2] NFSv4: Deal with atomic upgrades of an existing delegation
  2014-12-19 20:31           ` Trond Myklebust
  2014-12-19 20:39             ` Olga Kornievskaia
@ 2014-12-19 20:44             ` Trond Myklebust
  2014-12-19 20:44             ` [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated() Trond Myklebust
  2 siblings, 0 replies; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 20:44 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

Ensure that we deal correctly with the case where the server sends us a
newer instance of the same delegation. If the stateids match, but the
sequence numbers differ, then treat the new delegation as if it were
an atomic upgrade.

Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
---
 fs/nfs/delegation.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 7f3f60641344..16b754ee0d09 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -301,6 +301,17 @@ nfs_inode_detach_delegation(struct inode *inode)
 	return nfs_detach_delegation(nfsi, delegation, server);
 }
 
+static void
+nfs_update_inplace_delegation(struct nfs_delegation *delegation,
+		const struct nfs_delegation *update)
+{
+	if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
+		delegation->stateid.seqid = update->stateid.seqid;
+		smp_wmb();
+		delegation->type = update->type;
+	}
+}
+
 /**
  * nfs_inode_set_delegation - set up a delegation on an inode
  * @inode: inode to which delegation applies
@@ -334,9 +345,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
 	old_delegation = rcu_dereference_protected(nfsi->delegation,
 					lockdep_is_held(&clp->cl_lock));
 	if (old_delegation != NULL) {
-		if (nfs4_stateid_match(&delegation->stateid,
-					&old_delegation->stateid) &&
-				delegation->type == old_delegation->type) {
+		/* Is this an update of the existing delegation? */
+		if (nfs4_stateid_match_other(&old_delegation->stateid,
+					&delegation->stateid)) {
+			nfs_update_inplace_delegation(old_delegation,
+					delegation);
+			nfsi->delegation_state = old_delegation->type;
 			goto out;
 		}
 		/*
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated()
  2014-12-19 20:31           ` Trond Myklebust
  2014-12-19 20:39             ` Olga Kornievskaia
  2014-12-19 20:44             ` [PATCH v3 " Trond Myklebust
@ 2014-12-19 20:44             ` Trond Myklebust
  2015-08-18 20:38               ` Olga Kornievskaia
  2 siblings, 1 reply; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 20:44 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

Remove an incorrect check for NFS_DELEGATION_NEED_RECLAIM in
can_open_delegated(). We are allowed to cache opens even in
a situation where we're doing reboot recovery.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfs/nfs4proc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 8514b59a8c30..002c7dfedb08 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1119,8 +1119,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
 		return 0;
 	if ((delegation->type & fmode) != fmode)
 		return 0;
-	if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
-		return 0;
 	if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
 		return 0;
 	nfs_mark_delegation_referenced(delegation);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/2] NFSv4: Deal with atomic upgrades of an existing delegation
  2014-12-19 20:39             ` Olga Kornievskaia
@ 2014-12-19 20:46               ` Trond Myklebust
  0 siblings, 0 replies; 18+ messages in thread
From: Trond Myklebust @ 2014-12-19 20:46 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

On Fri, Dec 19, 2014 at 3:39 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
> On Fri, Dec 19, 2014 at 3:31 PM, Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
>> On Fri, Dec 19, 2014 at 1:52 PM, Trond Myklebust
>> <trond.myklebust@primarydata.com> wrote:
>>> Ensure that we deal correctly with the case where the server sends us a
>>> newer instance of the same delegation. If the stateids match, but the
>>> sequence numbers differ, then treat the new delegation as if it were
>>> an atomic upgrade.
>>>
>>> Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
>>> ---
>>>  fs/nfs/delegation.c | 21 ++++++++++++++++++---
>>>  1 file changed, 18 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
>>> index 7f3f60641344..02b5b2a6d557 100644
>>> --- a/fs/nfs/delegation.c
>>> +++ b/fs/nfs/delegation.c
>>> @@ -301,6 +301,19 @@ nfs_inode_detach_delegation(struct inode *inode)
>>>         return nfs_detach_delegation(nfsi, delegation, server);
>>>  }
>>>
>>> +static void
>>> +nfs_update_inplace_delegation(struct nfs_inode *nfsi,
>>> +               struct nfs_delegation *delegation,
>>> +               struct nfs_delegation *update)
>>> +{
>>> +       if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid))
>>
>> ...and the above comparison should be reversed.
>
> do you mean: if(!nfs4_stateid_is_newer())
>
> but if we received a delegation stateid with sequence number lower
> than what we have, shouldn't that be some kind of an error?

See the v3 patch. Yes, it would be a bug if the server sent us
something with a lower number, so we ignore that and don't update the
delegation. Ditto if it sends us something with the same sequence
number.

-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated()
  2014-12-19 20:44             ` [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated() Trond Myklebust
@ 2015-08-18 20:38               ` Olga Kornievskaia
  2015-08-18 21:07                 ` Trond Myklebust
  0 siblings, 1 reply; 18+ messages in thread
From: Olga Kornievskaia @ 2015-08-18 20:38 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

This is the patch that breaks recovery of opens upon server reboot.

I have a test that open a file and gets a write delegation and tried
to do a write. At this point, I reboot my server so that write fails
with bad_session and then stale_clientid. Upon completing the
exchange_id, create_session, and putrootfh, the client no longer sends
the open to be recovered and instead resends the failed write. It
would use all 0s stateid (this is 4.1) for the write and for the close
that follows it.

Reverting the patch fixes the problem.

On Fri, Dec 19, 2014 at 3:44 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> Remove an incorrect check for NFS_DELEGATION_NEED_RECLAIM in
> can_open_delegated(). We are allowed to cache opens even in
> a situation where we're doing reboot recovery.
>
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfs/nfs4proc.c | 2 --
>  1 file changed, 2 deletions(-)
>
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 8514b59a8c30..002c7dfedb08 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -1119,8 +1119,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
>                 return 0;
>         if ((delegation->type & fmode) != fmode)
>                 return 0;
> -       if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
> -               return 0;
>         if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
>                 return 0;
>         nfs_mark_delegation_referenced(delegation);
> --
> 2.1.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated()
  2015-08-18 20:38               ` Olga Kornievskaia
@ 2015-08-18 21:07                 ` Trond Myklebust
  2015-08-18 21:13                   ` Olga Kornievskaia
  0 siblings, 1 reply; 18+ messages in thread
From: Trond Myklebust @ 2015-08-18 21:07 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

On Tue, Aug 18, 2015 at 1:38 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>
> This is the patch that breaks recovery of opens upon server reboot.
>
> I have a test that open a file and gets a write delegation and tried
> to do a write. At this point, I reboot my server so that write fails
> with bad_session and then stale_clientid. Upon completing the
> exchange_id, create_session, and putrootfh, the client no longer sends
> the open to be recovered and instead resends the failed write. It
> would use all 0s stateid (this is 4.1) for the write and for the close
> that follows it.

Why is the client not attempting to recover the open? That's a bug,
whether or not this patch is correct.

> On Fri, Dec 19, 2014 at 3:44 PM, Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
> > Remove an incorrect check for NFS_DELEGATION_NEED_RECLAIM in
> > can_open_delegated(). We are allowed to cache opens even in
> > a situation where we're doing reboot recovery.
> >
> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > ---
> >  fs/nfs/nfs4proc.c | 2 --
> >  1 file changed, 2 deletions(-)
> >
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 8514b59a8c30..002c7dfedb08 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -1119,8 +1119,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
> >                 return 0;
> >         if ((delegation->type & fmode) != fmode)
> >                 return 0;
> > -       if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
> > -               return 0;
> >         if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
> >                 return 0;
> >         nfs_mark_delegation_referenced(delegation);
> > --
> > 2.1.0
> >

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated()
  2015-08-18 21:07                 ` Trond Myklebust
@ 2015-08-18 21:13                   ` Olga Kornievskaia
  2015-08-18 21:18                     ` Trond Myklebust
  0 siblings, 1 reply; 18+ messages in thread
From: Olga Kornievskaia @ 2015-08-18 21:13 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Tue, Aug 18, 2015 at 5:07 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> On Tue, Aug 18, 2015 at 1:38 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>
>> This is the patch that breaks recovery of opens upon server reboot.
>>
>> I have a test that open a file and gets a write delegation and tried
>> to do a write. At this point, I reboot my server so that write fails
>> with bad_session and then stale_clientid. Upon completing the
>> exchange_id, create_session, and putrootfh, the client no longer sends
>> the open to be recovered and instead resends the failed write. It
>> would use all 0s stateid (this is 4.1) for the write and for the close
>> that follows it.
>
> Why is the client not attempting to recover the open? That's a bug,
> whether or not this patch is correct.

I added printks in the path of nfs4_do_reclaim(). Client does
"attempt" to recover the open. OPEN never goes on the wire because
can_open_delegated() returned true and no action of adding an rpc task
gets done.

>
>> On Fri, Dec 19, 2014 at 3:44 PM, Trond Myklebust
>> <trond.myklebust@primarydata.com> wrote:
>> > Remove an incorrect check for NFS_DELEGATION_NEED_RECLAIM in
>> > can_open_delegated(). We are allowed to cache opens even in
>> > a situation where we're doing reboot recovery.
>> >
>> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
>> > ---
>> >  fs/nfs/nfs4proc.c | 2 --
>> >  1 file changed, 2 deletions(-)
>> >
>> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
>> > index 8514b59a8c30..002c7dfedb08 100644
>> > --- a/fs/nfs/nfs4proc.c
>> > +++ b/fs/nfs/nfs4proc.c
>> > @@ -1119,8 +1119,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
>> >                 return 0;
>> >         if ((delegation->type & fmode) != fmode)
>> >                 return 0;
>> > -       if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
>> > -               return 0;
>> >         if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
>> >                 return 0;
>> >         nfs_mark_delegation_referenced(delegation);
>> > --
>> > 2.1.0
>> >

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated()
  2015-08-18 21:13                   ` Olga Kornievskaia
@ 2015-08-18 21:18                     ` Trond Myklebust
  0 siblings, 0 replies; 18+ messages in thread
From: Trond Myklebust @ 2015-08-18 21:18 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs

On Tue, Aug 18, 2015 at 2:13 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
> On Tue, Aug 18, 2015 at 5:07 PM, Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
>> On Tue, Aug 18, 2015 at 1:38 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>>
>>> This is the patch that breaks recovery of opens upon server reboot.
>>>
>>> I have a test that open a file and gets a write delegation and tried
>>> to do a write. At this point, I reboot my server so that write fails
>>> with bad_session and then stale_clientid. Upon completing the
>>> exchange_id, create_session, and putrootfh, the client no longer sends
>>> the open to be recovered and instead resends the failed write. It
>>> would use all 0s stateid (this is 4.1) for the write and for the close
>>> that follows it.
>>
>> Why is the client not attempting to recover the open? That's a bug,
>> whether or not this patch is correct.
>
> I added printks in the path of nfs4_do_reclaim(). Client does
> "attempt" to recover the open. OPEN never goes on the wire because
> can_open_delegated() returned true and no action of adding an rpc task
> gets done.

Ahh... OK. I'll fix that.

Thanks Olga!

>>
>>> On Fri, Dec 19, 2014 at 3:44 PM, Trond Myklebust
>>> <trond.myklebust@primarydata.com> wrote:
>>> > Remove an incorrect check for NFS_DELEGATION_NEED_RECLAIM in
>>> > can_open_delegated(). We are allowed to cache opens even in
>>> > a situation where we're doing reboot recovery.
>>> >
>>> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
>>> > ---
>>> >  fs/nfs/nfs4proc.c | 2 --
>>> >  1 file changed, 2 deletions(-)
>>> >
>>> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
>>> > index 8514b59a8c30..002c7dfedb08 100644
>>> > --- a/fs/nfs/nfs4proc.c
>>> > +++ b/fs/nfs/nfs4proc.c
>>> > @@ -1119,8 +1119,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
>>> >                 return 0;
>>> >         if ((delegation->type & fmode) != fmode)
>>> >                 return 0;
>>> > -       if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
>>> > -               return 0;
>>> >         if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
>>> >                 return 0;
>>> >         nfs_mark_delegation_referenced(delegation);
>>> > --
>>> > 2.1.0
>>> >

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2015-08-18 21:18 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-19 15:11 question about code in delegation.c Olga Kornievskaia
2014-12-19 15:37 ` Trond Myklebust
2014-12-19 16:01   ` Olga Kornievskaia
2014-12-19 18:10     ` [PATCH 1/2] NFSv4: Deal with atomic upgrades of an existing delegation Trond Myklebust
2014-12-19 18:51       ` Trond Myklebust
2014-12-19 18:52         ` [PATCH v2 " Trond Myklebust
2014-12-19 20:16           ` Olga Kornievskaia
2014-12-19 20:31           ` Trond Myklebust
2014-12-19 20:39             ` Olga Kornievskaia
2014-12-19 20:46               ` Trond Myklebust
2014-12-19 20:44             ` [PATCH v3 " Trond Myklebust
2014-12-19 20:44             ` [PATCH v3 2/2] NFSv4: Remove incorrect check in can_open_delegated() Trond Myklebust
2015-08-18 20:38               ` Olga Kornievskaia
2015-08-18 21:07                 ` Trond Myklebust
2015-08-18 21:13                   ` Olga Kornievskaia
2015-08-18 21:18                     ` Trond Myklebust
2014-12-19 18:52         ` [PATCH v2 " Trond Myklebust
2014-12-19 18:10     ` [PATCH " Trond Myklebust

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox