diff mbox

[v2,1/2] NFSv4: Deal with atomic upgrades of an existing delegation

Message ID 1419015154-91037-1-git-send-email-trond.myklebust@primarydata.com (mailing list archive)
State New, archived
Headers show

Commit Message

Trond Myklebust Dec. 19, 2014, 6:52 p.m. UTC
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(-)

Comments

Olga Kornievskaia Dec. 19, 2014, 8:16 p.m. UTC | #1
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
>
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Trond Myklebust Dec. 19, 2014, 8:31 p.m. UTC | #2
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
>
Olga Kornievskaia Dec. 19, 2014, 8:39 p.m. UTC | #3
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
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Trond Myklebust Dec. 19, 2014, 8:46 p.m. UTC | #4
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.
diff mbox

Patch

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;
 		}
 		/*