diff mbox

how to properly handle failures during delegation recall process

Message ID CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Olga Kornievskaia Oct. 13, 2014, 6:51 p.m. UTC
I'd like to hear community's thought about how to properly handle
failures during delegation recall process and/or thoughts about a
proposed fixed listed at the end.

There are two problems seen during the following situation:
A client get a cb_call for a delegation it currently holds. Consider
the case where the client has a delegated lock for this open. Callback
thread will send an open with delegation_cur, followed by a lock
operation, and finally delegreturn.

Problem#1: the client will send a lock operation regardless of whether
or not the open succeeded. This is a new_owner lock and in nfs4xdr.c,
the lock operation will choose to use the open_stateid. However, when
the open failed, the stateid is 0. Thus, we send an erroneous stateid
of 0.

Problem#2: if the open fails with admin_revoked, bad_stateid errors,
it leads to an infinite loop of sending an open with deleg_cur and
getting a bad_stateid error back.

It seems to me that we shouldn't even be trying to recover if we get a
bad_stateid-type of errors on open with deleg_cur because they are
unrecoverable.

Furthermore, I propose that if we get an error in
nfs4_open_delegation_recall() then we mark any delegation locks as
lost and in nfs4_lock_delegation_recall() don't attempt to recover
lost lock.

I have tested to following code as a fix:

        return nfs4_handle_delegation_recall_error(server, state, stateid, err);
 }

@@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
file_lock *fl, struct nfs4_state *state,
        err = nfs4_set_lock_state(state, fl);
        if (err != 0)
                return err;
+       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
+               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
__func__);
+               return -EIO;
+       }
        err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
        return nfs4_handle_delegation_recall_error(server, state, stateid, err);
 }
--
1.7.1
--
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

Comments

Trond Myklebust Oct. 13, 2014, 7:53 p.m. UTC | #1
Hi Olga,

On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
> I'd like to hear community's thought about how to properly handle
> failures during delegation recall process and/or thoughts about a
> proposed fixed listed at the end.
>
> There are two problems seen during the following situation:
> A client get a cb_call for a delegation it currently holds. Consider
> the case where the client has a delegated lock for this open. Callback
> thread will send an open with delegation_cur, followed by a lock
> operation, and finally delegreturn.
>
> Problem#1: the client will send a lock operation regardless of whether
> or not the open succeeded. This is a new_owner lock and in nfs4xdr.c,
> the lock operation will choose to use the open_stateid. However, when
> the open failed, the stateid is 0. Thus, we send an erroneous stateid
> of 0.
>
> Problem#2: if the open fails with admin_revoked, bad_stateid errors,
> it leads to an infinite loop of sending an open with deleg_cur and
> getting a bad_stateid error back.
>
> It seems to me that we shouldn't even be trying to recover if we get a
> bad_stateid-type of errors on open with deleg_cur because they are
> unrecoverable.
>
> Furthermore, I propose that if we get an error in
> nfs4_open_delegation_recall() then we mark any delegation locks as
> lost and in nfs4_lock_delegation_recall() don't attempt to recover
> lost lock.
>
> I have tested to following code as a fix:
>
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 5aa55c1..523fae0 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -1682,6 +1682,22 @@ int nfs4_open_delegation_recall(struct
> nfs_open_context *ctx, struct nfs4_state
>         nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
>         err = nfs4_open_recover(opendata, state);
>         nfs4_opendata_put(opendata);
> +       switch(err) {
> +               case -NFS4ERR_DELEG_REVOKED:
> +               case -NFS4ERR_ADMIN_REVOKED:
> +               case -NFS4ERR_BAD_STATEID:
> +               case -NFS4ERR_OPENMODE: {
> +                       struct nfs4_lock_state *lock;
> +                       /* go through open locks and mark them lost */
> +                       spin_lock(&state->state_lock);
> +                       list_for_each_entry(lock, &state->lock_states,
> ls_locks) {
> +                               if (!test_bit(NFS_LOCK_INITIALIZED,
> &lock->ls_flags))
> +                                       set_bit(NFS_LOCK_LOST, &lock->ls_flags);
> +                       }
> +                       spin_unlock(&state->state_lock);
> +                       return 0;

If the open stated is marked for "nograce" recovery by
nfs4_handle_delegation_recall_errror(), then nfs4_lock_expired()
should do the above for you automatically. Are you reproducing this
bug with a 3.17 kernel?

> +               }
> +       }
>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>  }
>
> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
> file_lock *fl, struct nfs4_state *state,
>         err = nfs4_set_lock_state(state, fl);
>         if (err != 0)
>                 return err;
> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
> __func__);
> +               return -EIO;
> +       }
>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);

Note that there is a potential race here if the server is playing with
NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
present the delegation as part of the LOCK request, we have no way of
knowing if the delegation is still in effect. I guess we can check the
return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
LOCK is safe.

>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>  }
> --
> 1.7.1
> --
> 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
Olga Kornievskaia Oct. 13, 2014, 8:23 p.m. UTC | #2
On Mon, Oct 13, 2014 at 3:53 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> Hi Olga,
>
> On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>> I'd like to hear community's thought about how to properly handle
>> failures during delegation recall process and/or thoughts about a
>> proposed fixed listed at the end.
>>
>> There are two problems seen during the following situation:
>> A client get a cb_call for a delegation it currently holds. Consider
>> the case where the client has a delegated lock for this open. Callback
>> thread will send an open with delegation_cur, followed by a lock
>> operation, and finally delegreturn.
>>
>> Problem#1: the client will send a lock operation regardless of whether
>> or not the open succeeded. This is a new_owner lock and in nfs4xdr.c,
>> the lock operation will choose to use the open_stateid. However, when
>> the open failed, the stateid is 0. Thus, we send an erroneous stateid
>> of 0.
>>
>> Problem#2: if the open fails with admin_revoked, bad_stateid errors,
>> it leads to an infinite loop of sending an open with deleg_cur and
>> getting a bad_stateid error back.
>>
>> It seems to me that we shouldn't even be trying to recover if we get a
>> bad_stateid-type of errors on open with deleg_cur because they are
>> unrecoverable.
>>
>> Furthermore, I propose that if we get an error in
>> nfs4_open_delegation_recall() then we mark any delegation locks as
>> lost and in nfs4_lock_delegation_recall() don't attempt to recover
>> lost lock.
>>
>> I have tested to following code as a fix:
>>
>> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
>> index 5aa55c1..523fae0 100644
>> --- a/fs/nfs/nfs4proc.c
>> +++ b/fs/nfs/nfs4proc.c
>> @@ -1682,6 +1682,22 @@ int nfs4_open_delegation_recall(struct
>> nfs_open_context *ctx, struct nfs4_state
>>         nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
>>         err = nfs4_open_recover(opendata, state);
>>         nfs4_opendata_put(opendata);
>> +       switch(err) {
>> +               case -NFS4ERR_DELEG_REVOKED:
>> +               case -NFS4ERR_ADMIN_REVOKED:
>> +               case -NFS4ERR_BAD_STATEID:
>> +               case -NFS4ERR_OPENMODE: {
>> +                       struct nfs4_lock_state *lock;
>> +                       /* go through open locks and mark them lost */
>> +                       spin_lock(&state->state_lock);
>> +                       list_for_each_entry(lock, &state->lock_states,
>> ls_locks) {
>> +                               if (!test_bit(NFS_LOCK_INITIALIZED,
>> &lock->ls_flags))
>> +                                       set_bit(NFS_LOCK_LOST, &lock->ls_flags);
>> +                       }
>> +                       spin_unlock(&state->state_lock);
>> +                       return 0;
>
> If the open stated is marked for "nograce" recovery by
> nfs4_handle_delegation_recall_errror(), then nfs4_lock_expired()
> should do the above for you automatically. Are you reproducing this
> bug with a 3.17 kernel?

Yes, the bug is with the 3.17 kernel.

Yes, the nfs4_lock_expired() will mark it. However, the state_manager
thread (most frequently) doesn't get to run to do that before
nfs4_open_delegation_recall() returns 0 and calls the
nfs_delegation_claim_locks(). Therefore, I found the code needed
before returning from nfs4_open_delegation_recall().

>
>> +               }
>> +       }
>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>>  }
>>
>> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
>> file_lock *fl, struct nfs4_state *state,
>>         err = nfs4_set_lock_state(state, fl);
>>         if (err != 0)
>>                 return err;
>> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
>> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
>> __func__);
>> +               return -EIO;
>> +       }
>>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
>
> Note that there is a potential race here if the server is playing with
> NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
> present the delegation as part of the LOCK request, we have no way of
> knowing if the delegation is still in effect. I guess we can check the
> return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
> or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
> LOCK is safe.

I'm not following you. We send LOCK before we send DELEGRETURN? Also,
we normally send in LOCK the open_stateid returned by the open with
cur so do we know that delegation is still in effect.

>
>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>>  }
>> --
>> 1.7.1
>> --
>> 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
>
> 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 Oct. 13, 2014, 9:12 p.m. UTC | #3
On Mon, Oct 13, 2014 at 4:23 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
> On Mon, Oct 13, 2014 at 3:53 PM, Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
>> Hi Olga,
>>
>> On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>> I'd like to hear community's thought about how to properly handle
>>> failures during delegation recall process and/or thoughts about a
>>> proposed fixed listed at the end.
>>>
>>> There are two problems seen during the following situation:
>>> A client get a cb_call for a delegation it currently holds. Consider
>>> the case where the client has a delegated lock for this open. Callback
>>> thread will send an open with delegation_cur, followed by a lock
>>> operation, and finally delegreturn.
>>>
>>> Problem#1: the client will send a lock operation regardless of whether
>>> or not the open succeeded. This is a new_owner lock and in nfs4xdr.c,
>>> the lock operation will choose to use the open_stateid. However, when
>>> the open failed, the stateid is 0. Thus, we send an erroneous stateid
>>> of 0.
>>>
>>> Problem#2: if the open fails with admin_revoked, bad_stateid errors,
>>> it leads to an infinite loop of sending an open with deleg_cur and
>>> getting a bad_stateid error back.
>>>
>>> It seems to me that we shouldn't even be trying to recover if we get a
>>> bad_stateid-type of errors on open with deleg_cur because they are
>>> unrecoverable.
>>>
>>> Furthermore, I propose that if we get an error in
>>> nfs4_open_delegation_recall() then we mark any delegation locks as
>>> lost and in nfs4_lock_delegation_recall() don't attempt to recover
>>> lost lock.
>>>
>>> I have tested to following code as a fix:
>>>
>>> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
>>> index 5aa55c1..523fae0 100644
>>> --- a/fs/nfs/nfs4proc.c
>>> +++ b/fs/nfs/nfs4proc.c
>>> @@ -1682,6 +1682,22 @@ int nfs4_open_delegation_recall(struct
>>> nfs_open_context *ctx, struct nfs4_state
>>>         nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
>>>         err = nfs4_open_recover(opendata, state);
>>>         nfs4_opendata_put(opendata);
>>> +       switch(err) {
>>> +               case -NFS4ERR_DELEG_REVOKED:
>>> +               case -NFS4ERR_ADMIN_REVOKED:
>>> +               case -NFS4ERR_BAD_STATEID:
>>> +               case -NFS4ERR_OPENMODE: {
>>> +                       struct nfs4_lock_state *lock;
>>> +                       /* go through open locks and mark them lost */
>>> +                       spin_lock(&state->state_lock);
>>> +                       list_for_each_entry(lock, &state->lock_states,
>>> ls_locks) {
>>> +                               if (!test_bit(NFS_LOCK_INITIALIZED,
>>> &lock->ls_flags))
>>> +                                       set_bit(NFS_LOCK_LOST, &lock->ls_flags);
>>> +                       }
>>> +                       spin_unlock(&state->state_lock);
>>> +                       return 0;
>>
>> If the open stated is marked for "nograce" recovery by
>> nfs4_handle_delegation_recall_errror(), then nfs4_lock_expired()
>> should do the above for you automatically. Are you reproducing this
>> bug with a 3.17 kernel?
>
> Yes, the bug is with the 3.17 kernel.
>
> Yes, the nfs4_lock_expired() will mark it. However, the state_manager
> thread (most frequently) doesn't get to run to do that before
> nfs4_open_delegation_recall() returns 0 and calls the
> nfs_delegation_claim_locks(). Therefore, I found the code needed
> before returning from nfs4_open_delegation_recall().

Right. We probably should not be returning a value of 0 in that case.
If the delegation has been revoked, then we want
nfs4_open_delegation_recall() to just return immediately, and then we
want nfs_end_delegation_return() to detach the delegation and free it
without calling delegreturn.

>>> +               }
>>> +       }
>>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>>>  }
>>>
>>> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
>>> file_lock *fl, struct nfs4_state *state,
>>>         err = nfs4_set_lock_state(state, fl);
>>>         if (err != 0)
>>>                 return err;
>>> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
>>> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
>>> __func__);
>>> +               return -EIO;
>>> +       }
>>>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
>>
>> Note that there is a potential race here if the server is playing with
>> NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
>> present the delegation as part of the LOCK request, we have no way of
>> knowing if the delegation is still in effect. I guess we can check the
>> return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
>> or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
>> LOCK is safe.
>
> I'm not following you. We send LOCK before we send DELEGRETURN? Also,
> we normally send in LOCK the open_stateid returned by the open with
> cur so do we know that delegation is still in effect.

How so? The open stateid doesn't tell you that the delegation is still
in effect. If the DELEGRETURN returns NFS4ERR_DELEG_REVOKED, how can
you tell if the delegation was revoked before or after the LOCK
request was handled?

>
>>
>>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>>>  }
>>> --
>>> 1.7.1
>>> --
>>> 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
>>
>> Linux NFS client maintainer, PrimaryData
>>
>> trond.myklebust@primarydata.com
Trond Myklebust Oct. 13, 2014, 9:29 p.m. UTC | #4
On Mon, Oct 13, 2014 at 5:12 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> On Mon, Oct 13, 2014 at 4:23 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>> On Mon, Oct 13, 2014 at 3:53 PM, Trond Myklebust
>> <trond.myklebust@primarydata.com> wrote:
>>> On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>>> +               }
>>>> +       }
>>>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>>>>  }
>>>>
>>>> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
>>>> file_lock *fl, struct nfs4_state *state,
>>>>         err = nfs4_set_lock_state(state, fl);
>>>>         if (err != 0)
>>>>                 return err;
>>>> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
>>>> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
>>>> __func__);
>>>> +               return -EIO;
>>>> +       }
>>>>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
>>>
>>> Note that there is a potential race here if the server is playing with
>>> NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
>>> present the delegation as part of the LOCK request, we have no way of
>>> knowing if the delegation is still in effect. I guess we can check the
>>> return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
>>> or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
>>> LOCK is safe.
>>
>> I'm not following you. We send LOCK before we send DELEGRETURN? Also,
>> we normally send in LOCK the open_stateid returned by the open with
>> cur so do we know that delegation is still in effect.
>
> How so? The open stateid doesn't tell you that the delegation is still
> in effect. If the DELEGRETURN returns NFS4ERR_DELEG_REVOKED, how can
> you tell if the delegation was revoked before or after the LOCK
> request was handled?

Actually, let me answer that myself. You can sort of figure things out
in NFSv4.1 if you look at the SEQ4_STATUS_RECALLABLE_STATE_REVOKED
flag. If it is set, you should probably distrust the lock stateid that
you just attempted to recover, since you now know that at least one
delegation was just revoked.

In that case, we probably also have to do a TEST_STATEID+FREE_STATEID
on the delegation stateid.
Olga Kornievskaia Oct. 13, 2014, 10:13 p.m. UTC | #5
On Mon, Oct 13, 2014 at 5:29 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> On Mon, Oct 13, 2014 at 5:12 PM, Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
>> On Mon, Oct 13, 2014 at 4:23 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>> On Mon, Oct 13, 2014 at 3:53 PM, Trond Myklebust
>>> <trond.myklebust@primarydata.com> wrote:
>>>> On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>>>> +               }
>>>>> +       }
>>>>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>>>>>  }
>>>>>
>>>>> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
>>>>> file_lock *fl, struct nfs4_state *state,
>>>>>         err = nfs4_set_lock_state(state, fl);
>>>>>         if (err != 0)
>>>>>                 return err;
>>>>> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
>>>>> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
>>>>> __func__);
>>>>> +               return -EIO;
>>>>> +       }
>>>>>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
>>>>
>>>> Note that there is a potential race here if the server is playing with
>>>> NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
>>>> present the delegation as part of the LOCK request, we have no way of
>>>> knowing if the delegation is still in effect. I guess we can check the
>>>> return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
>>>> or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
>>>> LOCK is safe.
>>>
>>> I'm not following you. We send LOCK before we send DELEGRETURN? Also,
>>> we normally send in LOCK the open_stateid returned by the open with
>>> cur so do we know that delegation is still in effect.
>>
>> How so? The open stateid doesn't tell you that the delegation is still
>> in effect. If the DELEGRETURN returns NFS4ERR_DELEG_REVOKED, how can
>> you tell if the delegation was revoked before or after the LOCK
>> request was handled?
>
> Actually, let me answer that myself. You can sort of figure things out
> in NFSv4.1 if you look at the SEQ4_STATUS_RECALLABLE_STATE_REVOKED
> flag. If it is set, you should probably distrust the lock stateid that
> you just attempted to recover, since you now know that at least one
> delegation was just revoked.
>
> In that case, we probably also have to do a TEST_STATEID+FREE_STATEID
> on the delegation stateid.

I think we are mis-communicating here by talking about different
nuances. I agree with you that when an operation is sent there is no
way of knowing if in the mean while the server has decided to revoke
the delegation. However, this is not what I'm confused about regarding
your comment. I'm noticing that in the flow of operations, we send (1)
open with cur, then (2) lock, then (3) delegreturn. So I was confused
about how can we check return of delegreturn, step 3, if we are in
step 2.

I think the LOCK is safe if the reply to the LOCK is successful.

Let me just step back from this to note that your solution to "lost
locks during delegation" is to recognize the open with cure failure
and skip locking and delegreturn. I can work on a patch for that.

Do you agree that the state recovery should not be initiated in case
we get those errors?

>
> --
> 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 Oct. 13, 2014, 10:24 p.m. UTC | #6
On Mon, Oct 13, 2014 at 6:13 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
> On Mon, Oct 13, 2014 at 5:29 PM, Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
>> On Mon, Oct 13, 2014 at 5:12 PM, Trond Myklebust
>> <trond.myklebust@primarydata.com> wrote:
>>> On Mon, Oct 13, 2014 at 4:23 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>>> On Mon, Oct 13, 2014 at 3:53 PM, Trond Myklebust
>>>> <trond.myklebust@primarydata.com> wrote:
>>>>> On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>>>>> +               }
>>>>>> +       }
>>>>>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>>>>>>  }
>>>>>>
>>>>>> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
>>>>>> file_lock *fl, struct nfs4_state *state,
>>>>>>         err = nfs4_set_lock_state(state, fl);
>>>>>>         if (err != 0)
>>>>>>                 return err;
>>>>>> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
>>>>>> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
>>>>>> __func__);
>>>>>> +               return -EIO;
>>>>>> +       }
>>>>>>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
>>>>>
>>>>> Note that there is a potential race here if the server is playing with
>>>>> NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
>>>>> present the delegation as part of the LOCK request, we have no way of
>>>>> knowing if the delegation is still in effect. I guess we can check the
>>>>> return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
>>>>> or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
>>>>> LOCK is safe.
>>>>
>>>> I'm not following you. We send LOCK before we send DELEGRETURN? Also,
>>>> we normally send in LOCK the open_stateid returned by the open with
>>>> cur so do we know that delegation is still in effect.
>>>
>>> How so? The open stateid doesn't tell you that the delegation is still
>>> in effect. If the DELEGRETURN returns NFS4ERR_DELEG_REVOKED, how can
>>> you tell if the delegation was revoked before or after the LOCK
>>> request was handled?
>>
>> Actually, let me answer that myself. You can sort of figure things out
>> in NFSv4.1 if you look at the SEQ4_STATUS_RECALLABLE_STATE_REVOKED
>> flag. If it is set, you should probably distrust the lock stateid that
>> you just attempted to recover, since you now know that at least one
>> delegation was just revoked.
>>
>> In that case, we probably also have to do a TEST_STATEID+FREE_STATEID
>> on the delegation stateid.
>
> I think we are mis-communicating here by talking about different
> nuances. I agree with you that when an operation is sent there is no
> way of knowing if in the mean while the server has decided to revoke
> the delegation. However, this is not what I'm confused about regarding
> your comment. I'm noticing that in the flow of operations, we send (1)
> open with cur, then (2) lock, then (3) delegreturn. So I was confused
> about how can we check return of delegreturn, step 3, if we are in
> step 2.
>
> I think the LOCK is safe if the reply to the LOCK is successful.

It needs to be concurrent with the delegation as well, otherwise
general lock atomicity is broken.

> Let me just step back from this to note that your solution to "lost
> locks during delegation" is to recognize the open with cure failure
> and skip locking and delegreturn. I can work on a patch for that.
>
> Do you agree that the state recovery should not be initiated in case
> we get those errors?

State recovery _should_ be initiated so that we do reclaim opens (I
don't care about share lock atomicity on Linux). However
nfs_delegation_claim_locks() _should_not_ be called.

I'll give some more thought as to how we can ensure the missing lock atomicity.
Olga Kornievskaia Oct. 14, 2014, 3:48 p.m. UTC | #7
On Mon, Oct 13, 2014 at 6:24 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> On Mon, Oct 13, 2014 at 6:13 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>> On Mon, Oct 13, 2014 at 5:29 PM, Trond Myklebust
>> <trond.myklebust@primarydata.com> wrote:
>>> On Mon, Oct 13, 2014 at 5:12 PM, Trond Myklebust
>>> <trond.myklebust@primarydata.com> wrote:
>>>> On Mon, Oct 13, 2014 at 4:23 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>>>> On Mon, Oct 13, 2014 at 3:53 PM, Trond Myklebust
>>>>> <trond.myklebust@primarydata.com> wrote:
>>>>>> On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>>>>>>> +               }
>>>>>>> +       }
>>>>>>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
>>>>>>> file_lock *fl, struct nfs4_state *state,
>>>>>>>         err = nfs4_set_lock_state(state, fl);
>>>>>>>         if (err != 0)
>>>>>>>                 return err;
>>>>>>> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
>>>>>>> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
>>>>>>> __func__);
>>>>>>> +               return -EIO;
>>>>>>> +       }
>>>>>>>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
>>>>>>
>>>>>> Note that there is a potential race here if the server is playing with
>>>>>> NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
>>>>>> present the delegation as part of the LOCK request, we have no way of
>>>>>> knowing if the delegation is still in effect. I guess we can check the
>>>>>> return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
>>>>>> or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
>>>>>> LOCK is safe.
>>>>>
>>>>> I'm not following you. We send LOCK before we send DELEGRETURN? Also,
>>>>> we normally send in LOCK the open_stateid returned by the open with
>>>>> cur so do we know that delegation is still in effect.
>>>>
>>>> How so? The open stateid doesn't tell you that the delegation is still
>>>> in effect. If the DELEGRETURN returns NFS4ERR_DELEG_REVOKED, how can
>>>> you tell if the delegation was revoked before or after the LOCK
>>>> request was handled?
>>>
>>> Actually, let me answer that myself. You can sort of figure things out
>>> in NFSv4.1 if you look at the SEQ4_STATUS_RECALLABLE_STATE_REVOKED
>>> flag. If it is set, you should probably distrust the lock stateid that
>>> you just attempted to recover, since you now know that at least one
>>> delegation was just revoked.
>>>
>>> In that case, we probably also have to do a TEST_STATEID+FREE_STATEID
>>> on the delegation stateid.
>>
>> I think we are mis-communicating here by talking about different
>> nuances. I agree with you that when an operation is sent there is no
>> way of knowing if in the mean while the server has decided to revoke
>> the delegation. However, this is not what I'm confused about regarding
>> your comment. I'm noticing that in the flow of operations, we send (1)
>> open with cur, then (2) lock, then (3) delegreturn. So I was confused
>> about how can we check return of delegreturn, step 3, if we are in
>> step 2.
>>
>> I think the LOCK is safe if the reply to the LOCK is successful.
>
> It needs to be concurrent with the delegation as well, otherwise
> general lock atomicity is broken.
>
>> Let me just step back from this to note that your solution to "lost
>> locks during delegation" is to recognize the open with cure failure
>> and skip locking and delegreturn. I can work on a patch for that.
>>
>> Do you agree that the state recovery should not be initiated in case
>> we get those errors?
>
> State recovery _should_ be initiated so that we do reclaim opens (I
> don't care about share lock atomicity on Linux). However
> nfs_delegation_claim_locks() _should_not_ be called.
>
> I'll give some more thought as to how we can ensure the missing lock atomicity.

If state recover is initiated, it will go into an infinite loop. There
is no way to stop it once it's initiated. A "recovery" open will get a
BAD_STATEID which will again initiated state recovery.

Are proposing to add smarts to the state manager when it should not
recover from a BAD_STATEID?

>
> --
> 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
Jeff Layton Nov. 5, 2014, 11:57 a.m. UTC | #8
On Mon, 13 Oct 2014 18:24:21 -0400
Trond Myklebust <trond.myklebust@primarydata.com> wrote:

> On Mon, Oct 13, 2014 at 6:13 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
> > On Mon, Oct 13, 2014 at 5:29 PM, Trond Myklebust
> > <trond.myklebust@primarydata.com> wrote:
> >> On Mon, Oct 13, 2014 at 5:12 PM, Trond Myklebust
> >> <trond.myklebust@primarydata.com> wrote:
> >>> On Mon, Oct 13, 2014 at 4:23 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
> >>>> On Mon, Oct 13, 2014 at 3:53 PM, Trond Myklebust
> >>>> <trond.myklebust@primarydata.com> wrote:
> >>>>> On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
> >>>>>> +               }
> >>>>>> +       }
> >>>>>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
> >>>>>>  }
> >>>>>>
> >>>>>> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
> >>>>>> file_lock *fl, struct nfs4_state *state,
> >>>>>>         err = nfs4_set_lock_state(state, fl);
> >>>>>>         if (err != 0)
> >>>>>>                 return err;
> >>>>>> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
> >>>>>> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
> >>>>>> __func__);
> >>>>>> +               return -EIO;
> >>>>>> +       }
> >>>>>>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
> >>>>>
> >>>>> Note that there is a potential race here if the server is playing with
> >>>>> NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
> >>>>> present the delegation as part of the LOCK request, we have no way of
> >>>>> knowing if the delegation is still in effect. I guess we can check the
> >>>>> return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
> >>>>> or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
> >>>>> LOCK is safe.
> >>>>
> >>>> I'm not following you. We send LOCK before we send DELEGRETURN? Also,
> >>>> we normally send in LOCK the open_stateid returned by the open with
> >>>> cur so do we know that delegation is still in effect.
> >>>
> >>> How so? The open stateid doesn't tell you that the delegation is still
> >>> in effect. If the DELEGRETURN returns NFS4ERR_DELEG_REVOKED, how can
> >>> you tell if the delegation was revoked before or after the LOCK
> >>> request was handled?
> >>
> >> Actually, let me answer that myself. You can sort of figure things out
> >> in NFSv4.1 if you look at the SEQ4_STATUS_RECALLABLE_STATE_REVOKED
> >> flag. If it is set, you should probably distrust the lock stateid that
> >> you just attempted to recover, since you now know that at least one
> >> delegation was just revoked.
> >>
> >> In that case, we probably also have to do a TEST_STATEID+FREE_STATEID
> >> on the delegation stateid.
> >
> > I think we are mis-communicating here by talking about different
> > nuances. I agree with you that when an operation is sent there is no
> > way of knowing if in the mean while the server has decided to revoke
> > the delegation. However, this is not what I'm confused about regarding
> > your comment. I'm noticing that in the flow of operations, we send (1)
> > open with cur, then (2) lock, then (3) delegreturn. So I was confused
> > about how can we check return of delegreturn, step 3, if we are in
> > step 2.
> >
> > I think the LOCK is safe if the reply to the LOCK is successful.
> 
> It needs to be concurrent with the delegation as well, otherwise
> general lock atomicity is broken.
> 
> > Let me just step back from this to note that your solution to "lost
> > locks during delegation" is to recognize the open with cure failure
> > and skip locking and delegreturn. I can work on a patch for that.
> >
> > Do you agree that the state recovery should not be initiated in case
> > we get those errors?
> 
> State recovery _should_ be initiated so that we do reclaim opens (I
> don't care about share lock atomicity on Linux). However
> nfs_delegation_claim_locks() _should_not_ be called.
> 
> I'll give some more thought as to how we can ensure the missing lock atomicity.
> 


(cc'ing Tom here since we may want to consider providing guidance in
 the spec for this situation)

Ok, I think both of you are right here :). Here's my interpretation:

Olga is correct that the LOCK operation itself is safe since LOCK
doesn't actually modify the contents of the file. What it's not safe to
do is to trust that LOCK unless and until the DELEGRETURN is also
successful.

First, let's clarify the potential race that Trond pointed out:

Suppose we have a delegation and delegated locks. That delegation is
recalled and we do something like this:

OPEN with DELEGATE_CUR: NFS4_OK
LOCK:                   NFS4_OK
LOCK:                   NFS4_OK
...(maybe more successful locks here)...
DELEGRETURN:            NFS4ERR_ADMIN_REVOKED

...at that point, we're screwed.

The delegation was obviously revoked after we did the OPEN but before
the DELEGRETURN. None of those LOCK requests can be trusted since
another client may have opened the file at any point in there, acquired
any one of those locks and then released it.

For v4.1+ the client can do what Trond suggests. Check for
SEQ4_STATUS_RECALLABLE_STATE_REVOKED in each LOCK response. If it's set
then we can do the TEST_STATEID/FREE_STATEID dance. If the TEST_STATEID
fails, then we must consider the most recently acquired lock lost.
LOCKU it and give up trying to reclaim the rest of them.

For v4.0, I'm not sure what the client can do other than wait until the
DELEGRETURN. If that fails with NFS4ERR_ADMIN_REVOKED, then we'll just
have to try to unwind the whole mess. Send LOCKUs for all of them and
consider them all to be lost.

Actually, it may be reasonable to just do the same thing for v4.1. The
client tracks NFS_LOCK_LOST on a per-lockstateid basis, so once you have
any unreclaimable lock, any I/O done with that stateid is going to fail
anyway. You might as well just release any locks you do hold at that
point.

The other question is whether the server ought to have any role to play
here. In principle it could track whether an open/lock stateid is
descended from a still outstanding delegation, and revoke those
stateids if the delegation is revoked. That would probably not be
trivial to do with the current Linux server implementation, however.
Trond Myklebust Nov. 5, 2014, 12:41 p.m. UTC | #9
On Wed, Nov 5, 2014 at 6:57 AM, Jeff Layton <jeff.layton@primarydata.com> wrote:
> On Mon, 13 Oct 2014 18:24:21 -0400
> Trond Myklebust <trond.myklebust@primarydata.com> wrote:
>
>> On Mon, Oct 13, 2014 at 6:13 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>> > On Mon, Oct 13, 2014 at 5:29 PM, Trond Myklebust
>> > <trond.myklebust@primarydata.com> wrote:
>> >> On Mon, Oct 13, 2014 at 5:12 PM, Trond Myklebust
>> >> <trond.myklebust@primarydata.com> wrote:
>> >>> On Mon, Oct 13, 2014 at 4:23 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>> >>>> On Mon, Oct 13, 2014 at 3:53 PM, Trond Myklebust
>> >>>> <trond.myklebust@primarydata.com> wrote:
>> >>>>> On Mon, Oct 13, 2014 at 2:51 PM, Olga Kornievskaia <aglo@umich.edu> wrote:
>> >>>>>> +               }
>> >>>>>> +       }
>> >>>>>>         return nfs4_handle_delegation_recall_error(server, state, stateid, err);
>> >>>>>>  }
>> >>>>>>
>> >>>>>> @@ -5957,6 +5973,10 @@ int nfs4_lock_delegation_recall(struct
>> >>>>>> file_lock *fl, struct nfs4_state *state,
>> >>>>>>         err = nfs4_set_lock_state(state, fl);
>> >>>>>>         if (err != 0)
>> >>>>>>                 return err;
>> >>>>>> +       if (test_bit(NFS_LOCK_LOST, &fl->fl_u.nfs4_fl.owner->ls_flags)) {
>> >>>>>> +               pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n",
>> >>>>>> __func__);
>> >>>>>> +               return -EIO;
>> >>>>>> +       }
>> >>>>>>         err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
>> >>>>>
>> >>>>> Note that there is a potential race here if the server is playing with
>> >>>>> NFS4ERR_DELEG_REVOKED or NFS4ERR_ADMIN_REVOKED. Since we do not
>> >>>>> present the delegation as part of the LOCK request, we have no way of
>> >>>>> knowing if the delegation is still in effect. I guess we can check the
>> >>>>> return value of DELEGRETURN, but if it returns NFS4ERR_DELEG_REVOKED
>> >>>>> or NFS4ERR_ADMIN_REVOKED, then we still do not know whether or not the
>> >>>>> LOCK is safe.
>> >>>>
>> >>>> I'm not following you. We send LOCK before we send DELEGRETURN? Also,
>> >>>> we normally send in LOCK the open_stateid returned by the open with
>> >>>> cur so do we know that delegation is still in effect.
>> >>>
>> >>> How so? The open stateid doesn't tell you that the delegation is still
>> >>> in effect. If the DELEGRETURN returns NFS4ERR_DELEG_REVOKED, how can
>> >>> you tell if the delegation was revoked before or after the LOCK
>> >>> request was handled?
>> >>
>> >> Actually, let me answer that myself. You can sort of figure things out
>> >> in NFSv4.1 if you look at the SEQ4_STATUS_RECALLABLE_STATE_REVOKED
>> >> flag. If it is set, you should probably distrust the lock stateid that
>> >> you just attempted to recover, since you now know that at least one
>> >> delegation was just revoked.
>> >>
>> >> In that case, we probably also have to do a TEST_STATEID+FREE_STATEID
>> >> on the delegation stateid.
>> >
>> > I think we are mis-communicating here by talking about different
>> > nuances. I agree with you that when an operation is sent there is no
>> > way of knowing if in the mean while the server has decided to revoke
>> > the delegation. However, this is not what I'm confused about regarding
>> > your comment. I'm noticing that in the flow of operations, we send (1)
>> > open with cur, then (2) lock, then (3) delegreturn. So I was confused
>> > about how can we check return of delegreturn, step 3, if we are in
>> > step 2.
>> >
>> > I think the LOCK is safe if the reply to the LOCK is successful.
>>
>> It needs to be concurrent with the delegation as well, otherwise
>> general lock atomicity is broken.
>>
>> > Let me just step back from this to note that your solution to "lost
>> > locks during delegation" is to recognize the open with cure failure
>> > and skip locking and delegreturn. I can work on a patch for that.
>> >
>> > Do you agree that the state recovery should not be initiated in case
>> > we get those errors?
>>
>> State recovery _should_ be initiated so that we do reclaim opens (I
>> don't care about share lock atomicity on Linux). However
>> nfs_delegation_claim_locks() _should_not_ be called.
>>
>> I'll give some more thought as to how we can ensure the missing lock atomicity.
>>
>
>
> (cc'ing Tom here since we may want to consider providing guidance in
>  the spec for this situation)
>
> Ok, I think both of you are right here :). Here's my interpretation:
>
> Olga is correct that the LOCK operation itself is safe since LOCK
> doesn't actually modify the contents of the file. What it's not safe to
> do is to trust that LOCK unless and until the DELEGRETURN is also
> successful.
>
> First, let's clarify the potential race that Trond pointed out:
>
> Suppose we have a delegation and delegated locks. That delegation is
> recalled and we do something like this:
>
> OPEN with DELEGATE_CUR: NFS4_OK
> LOCK:                   NFS4_OK
> LOCK:                   NFS4_OK
> ...(maybe more successful locks here)...
> DELEGRETURN:            NFS4ERR_ADMIN_REVOKED
>
> ...at that point, we're screwed.
>
> The delegation was obviously revoked after we did the OPEN but before
> the DELEGRETURN. None of those LOCK requests can be trusted since
> another client may have opened the file at any point in there, acquired
> any one of those locks and then released it.
>
> For v4.1+ the client can do what Trond suggests. Check for
> SEQ4_STATUS_RECALLABLE_STATE_REVOKED in each LOCK response. If it's set
> then we can do the TEST_STATEID/FREE_STATEID dance. If the TEST_STATEID
> fails, then we must consider the most recently acquired lock lost.
> LOCKU it and give up trying to reclaim the rest of them.
>
> For v4.0, I'm not sure what the client can do other than wait until the
> DELEGRETURN. If that fails with NFS4ERR_ADMIN_REVOKED, then we'll just
> have to try to unwind the whole mess. Send LOCKUs for all of them and
> consider them all to be lost.
>
> Actually, it may be reasonable to just do the same thing for v4.1. The
> client tracks NFS_LOCK_LOST on a per-lockstateid basis, so once you have
> any unreclaimable lock, any I/O done with that stateid is going to fail
> anyway. You might as well just release any locks you do hold at that
> point.
>
> The other question is whether the server ought to have any role to play
> here. In principle it could track whether an open/lock stateid is
> descended from a still outstanding delegation, and revoke those
> stateids if the delegation is revoked. That would probably not be
> trivial to do with the current Linux server implementation, however.
>

What the server could (and probably should) do is revoke all
open/lock/layout state for the clientid+file combination for which it
is also revoking the delegation. That means that all applications that
were using that file on that client would be screwed, but they
probably will be anyway if the file gets corrupted due to non-atomic
locking.

Cheers
  Trond
--
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
J. Bruce Fields Nov. 5, 2014, 6:31 p.m. UTC | #10
On Wed, Nov 05, 2014 at 07:41:58AM -0500, Trond Myklebust wrote:
> On Wed, Nov 5, 2014 at 6:57 AM, Jeff Layton <jeff.layton@primarydata.com> wrote:
> > (cc'ing Tom here since we may want to consider providing guidance in
> >  the spec for this situation)
> >
> > Ok, I think both of you are right here :). Here's my interpretation:
> >
> > Olga is correct that the LOCK operation itself is safe since LOCK
> > doesn't actually modify the contents of the file. What it's not safe to
> > do is to trust that LOCK unless and until the DELEGRETURN is also
> > successful.
> >
> > First, let's clarify the potential race that Trond pointed out:
> >
> > Suppose we have a delegation and delegated locks. That delegation is
> > recalled and we do something like this:
> >
> > OPEN with DELEGATE_CUR: NFS4_OK
> > LOCK:                   NFS4_OK
> > LOCK:                   NFS4_OK
> > ...(maybe more successful locks here)...
> > DELEGRETURN:            NFS4ERR_ADMIN_REVOKED
> >
> > ...at that point, we're screwed.
> >
> > The delegation was obviously revoked after we did the OPEN but before
> > the DELEGRETURN. None of those LOCK requests can be trusted since
> > another client may have opened the file at any point in there, acquired
> > any one of those locks and then released it.
> >
> > For v4.1+ the client can do what Trond suggests. Check for
> > SEQ4_STATUS_RECALLABLE_STATE_REVOKED in each LOCK response. If it's set
> > then we can do the TEST_STATEID/FREE_STATEID dance. If the TEST_STATEID
> > fails, then we must consider the most recently acquired lock lost.
> > LOCKU it and give up trying to reclaim the rest of them.
> >
> > For v4.0, I'm not sure what the client can do other than wait until the
> > DELEGRETURN. If that fails with NFS4ERR_ADMIN_REVOKED, then we'll just
> > have to try to unwind the whole mess. Send LOCKUs for all of them and
> > consider them all to be lost.
> >
> > Actually, it may be reasonable to just do the same thing for v4.1. The
> > client tracks NFS_LOCK_LOST on a per-lockstateid basis, so once you have
> > any unreclaimable lock, any I/O done with that stateid is going to fail
> > anyway. You might as well just release any locks you do hold at that
> > point.
> >
> > The other question is whether the server ought to have any role to play
> > here. In principle it could track whether an open/lock stateid is
> > descended from a still outstanding delegation, and revoke those
> > stateids if the delegation is revoked. That would probably not be
> > trivial to do with the current Linux server implementation, however.

That sounds like a problem for whoever wants to implement support for
administrative revocation of state.  We don't really support it
currently.

Oops, right, except for the case where the delegation's revoked just
because the client ran out of time doing the recall.  In which case I
think the final error's going to be either EXPIRED (4.0) or
DELEG_REVOKED (4.1)?  (Except I think the Linux server's returning
BAD_STATEID in the 4.0 case, which looks wrong.)

--b.

> What the server could (and probably should) do is revoke all
> open/lock/layout state for the clientid+file combination for which it
> is also revoking the delegation. That means that all applications that
> were using that file on that client would be screwed, but they
> probably will be anyway if the file gets corrupted due to non-atomic
> locking.
--
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
Jeff Layton Nov. 5, 2014, 7:42 p.m. UTC | #11
On Wed, 5 Nov 2014 13:31:52 -0500
"J. Bruce Fields" <bfields@fieldses.org> wrote:

> On Wed, Nov 05, 2014 at 07:41:58AM -0500, Trond Myklebust wrote:
> > On Wed, Nov 5, 2014 at 6:57 AM, Jeff Layton <jeff.layton@primarydata.com> wrote:
> > > (cc'ing Tom here since we may want to consider providing guidance in
> > >  the spec for this situation)
> > >
> > > Ok, I think both of you are right here :). Here's my interpretation:
> > >
> > > Olga is correct that the LOCK operation itself is safe since LOCK
> > > doesn't actually modify the contents of the file. What it's not safe to
> > > do is to trust that LOCK unless and until the DELEGRETURN is also
> > > successful.
> > >
> > > First, let's clarify the potential race that Trond pointed out:
> > >
> > > Suppose we have a delegation and delegated locks. That delegation is
> > > recalled and we do something like this:
> > >
> > > OPEN with DELEGATE_CUR: NFS4_OK
> > > LOCK:                   NFS4_OK
> > > LOCK:                   NFS4_OK
> > > ...(maybe more successful locks here)...
> > > DELEGRETURN:            NFS4ERR_ADMIN_REVOKED
> > >
> > > ...at that point, we're screwed.
> > >
> > > The delegation was obviously revoked after we did the OPEN but before
> > > the DELEGRETURN. None of those LOCK requests can be trusted since
> > > another client may have opened the file at any point in there, acquired
> > > any one of those locks and then released it.
> > >
> > > For v4.1+ the client can do what Trond suggests. Check for
> > > SEQ4_STATUS_RECALLABLE_STATE_REVOKED in each LOCK response. If it's set
> > > then we can do the TEST_STATEID/FREE_STATEID dance. If the TEST_STATEID
> > > fails, then we must consider the most recently acquired lock lost.
> > > LOCKU it and give up trying to reclaim the rest of them.
> > >
> > > For v4.0, I'm not sure what the client can do other than wait until the
> > > DELEGRETURN. If that fails with NFS4ERR_ADMIN_REVOKED, then we'll just
> > > have to try to unwind the whole mess. Send LOCKUs for all of them and
> > > consider them all to be lost.
> > >
> > > Actually, it may be reasonable to just do the same thing for v4.1. The
> > > client tracks NFS_LOCK_LOST on a per-lockstateid basis, so once you have
> > > any unreclaimable lock, any I/O done with that stateid is going to fail
> > > anyway. You might as well just release any locks you do hold at that
> > > point.
> > >
> > > The other question is whether the server ought to have any role to play
> > > here. In principle it could track whether an open/lock stateid is
> > > descended from a still outstanding delegation, and revoke those
> > > stateids if the delegation is revoked. That would probably not be
> > > trivial to do with the current Linux server implementation, however.
> 
> That sounds like a problem for whoever wants to implement support for
> administrative revocation of state.  We don't really support it
> currently.
> 
> Oops, right, except for the case where the delegation's revoked just
> because the client ran out of time doing the recall.  In which case I
> think the final error's going to be either EXPIRED (4.0) or
> DELEG_REVOKED (4.1)?  (Except I think the Linux server's returning
> BAD_STATEID in the 4.0 case, which looks wrong.)
> 

I'm not sure that that's right... RFC3530 says:

   NFS4ERR_EXPIRED       A lease has expired that is being used in the
                         current operation.

...implicit in the scenario I layed out above is that the lease is
being maintained. It's just that the client failed to return the
delegation in time. So, BAD_STATEID may be correct, actually?

> 
> > What the server could (and probably should) do is revoke all
> > open/lock/layout state for the clientid+file combination for which it
> > is also revoking the delegation. That means that all applications that
> > were using that file on that client would be screwed, but they
> > probably will be anyway if the file gets corrupted due to non-atomic
> > locking.
> --
> 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
J. Bruce Fields Nov. 5, 2014, 7:54 p.m. UTC | #12
On Wed, Nov 05, 2014 at 02:42:51PM -0500, Jeff Layton wrote:
> On Wed, 5 Nov 2014 13:31:52 -0500
> "J. Bruce Fields" <bfields@fieldses.org> wrote:
> 
> > On Wed, Nov 05, 2014 at 07:41:58AM -0500, Trond Myklebust wrote:
> > > On Wed, Nov 5, 2014 at 6:57 AM, Jeff Layton <jeff.layton@primarydata.com> wrote:
> > > > (cc'ing Tom here since we may want to consider providing guidance in
> > > >  the spec for this situation)
> > > >
> > > > Ok, I think both of you are right here :). Here's my interpretation:
> > > >
> > > > Olga is correct that the LOCK operation itself is safe since LOCK
> > > > doesn't actually modify the contents of the file. What it's not safe to
> > > > do is to trust that LOCK unless and until the DELEGRETURN is also
> > > > successful.
> > > >
> > > > First, let's clarify the potential race that Trond pointed out:
> > > >
> > > > Suppose we have a delegation and delegated locks. That delegation is
> > > > recalled and we do something like this:
> > > >
> > > > OPEN with DELEGATE_CUR: NFS4_OK
> > > > LOCK:                   NFS4_OK
> > > > LOCK:                   NFS4_OK
> > > > ...(maybe more successful locks here)...
> > > > DELEGRETURN:            NFS4ERR_ADMIN_REVOKED
> > > >
> > > > ...at that point, we're screwed.
> > > >
> > > > The delegation was obviously revoked after we did the OPEN but before
> > > > the DELEGRETURN. None of those LOCK requests can be trusted since
> > > > another client may have opened the file at any point in there, acquired
> > > > any one of those locks and then released it.
> > > >
> > > > For v4.1+ the client can do what Trond suggests. Check for
> > > > SEQ4_STATUS_RECALLABLE_STATE_REVOKED in each LOCK response. If it's set
> > > > then we can do the TEST_STATEID/FREE_STATEID dance. If the TEST_STATEID
> > > > fails, then we must consider the most recently acquired lock lost.
> > > > LOCKU it and give up trying to reclaim the rest of them.
> > > >
> > > > For v4.0, I'm not sure what the client can do other than wait until the
> > > > DELEGRETURN. If that fails with NFS4ERR_ADMIN_REVOKED, then we'll just
> > > > have to try to unwind the whole mess. Send LOCKUs for all of them and
> > > > consider them all to be lost.
> > > >
> > > > Actually, it may be reasonable to just do the same thing for v4.1. The
> > > > client tracks NFS_LOCK_LOST on a per-lockstateid basis, so once you have
> > > > any unreclaimable lock, any I/O done with that stateid is going to fail
> > > > anyway. You might as well just release any locks you do hold at that
> > > > point.
> > > >
> > > > The other question is whether the server ought to have any role to play
> > > > here. In principle it could track whether an open/lock stateid is
> > > > descended from a still outstanding delegation, and revoke those
> > > > stateids if the delegation is revoked. That would probably not be
> > > > trivial to do with the current Linux server implementation, however.
> > 
> > That sounds like a problem for whoever wants to implement support for
> > administrative revocation of state.  We don't really support it
> > currently.
> > 
> > Oops, right, except for the case where the delegation's revoked just
> > because the client ran out of time doing the recall.  In which case I
> > think the final error's going to be either EXPIRED (4.0) or
> > DELEG_REVOKED (4.1)?  (Except I think the Linux server's returning
> > BAD_STATEID in the 4.0 case, which looks wrong.)
> > 
> 
> I'm not sure that that's right... RFC3530 says:
> 
>    NFS4ERR_EXPIRED       A lease has expired that is being used in the
>                          current operation.
> 
> ...implicit in the scenario I layed out above is that the lease is
> being maintained. It's just that the client failed to return the
> delegation in time. So, BAD_STATEID may be correct, actually?

Yes, I misread that EXPIRED text.

That's a bit of a digression--in any case we agree that it's this late
DELEGRETURN case that's the only real bug right now?

On the client side I guess I can't think of anything better than your
suggestion of waiting for the error on DELEGRETURN as you describe.

And on the server side:

> > > What the server could (and probably should) do is revoke all
> > > open/lock/layout state for the clientid+file combination for which it
> > > is also revoking the delegation. That means that all applications that
> > > were using that file on that client would be screwed, but they
> > > probably will be anyway if the file gets corrupted due to non-atomic
> > > locking.

That sounds harsh at first, but I guess it makes sense.

--b.
--
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
Jeff Layton Nov. 5, 2014, 8:06 p.m. UTC | #13
On Wed, 5 Nov 2014 14:54:20 -0500
"J. Bruce Fields" <bfields@fieldses.org> wrote:

> On Wed, Nov 05, 2014 at 02:42:51PM -0500, Jeff Layton wrote:
> > On Wed, 5 Nov 2014 13:31:52 -0500
> > "J. Bruce Fields" <bfields@fieldses.org> wrote:
> > 
> > > On Wed, Nov 05, 2014 at 07:41:58AM -0500, Trond Myklebust wrote:
> > > > On Wed, Nov 5, 2014 at 6:57 AM, Jeff Layton <jeff.layton@primarydata.com> wrote:
> > > > > (cc'ing Tom here since we may want to consider providing guidance in
> > > > >  the spec for this situation)
> > > > >
> > > > > Ok, I think both of you are right here :). Here's my interpretation:
> > > > >
> > > > > Olga is correct that the LOCK operation itself is safe since LOCK
> > > > > doesn't actually modify the contents of the file. What it's not safe to
> > > > > do is to trust that LOCK unless and until the DELEGRETURN is also
> > > > > successful.
> > > > >
> > > > > First, let's clarify the potential race that Trond pointed out:
> > > > >
> > > > > Suppose we have a delegation and delegated locks. That delegation is
> > > > > recalled and we do something like this:
> > > > >
> > > > > OPEN with DELEGATE_CUR: NFS4_OK
> > > > > LOCK:                   NFS4_OK
> > > > > LOCK:                   NFS4_OK
> > > > > ...(maybe more successful locks here)...
> > > > > DELEGRETURN:            NFS4ERR_ADMIN_REVOKED
> > > > >
> > > > > ...at that point, we're screwed.
> > > > >
> > > > > The delegation was obviously revoked after we did the OPEN but before
> > > > > the DELEGRETURN. None of those LOCK requests can be trusted since
> > > > > another client may have opened the file at any point in there, acquired
> > > > > any one of those locks and then released it.
> > > > >
> > > > > For v4.1+ the client can do what Trond suggests. Check for
> > > > > SEQ4_STATUS_RECALLABLE_STATE_REVOKED in each LOCK response. If it's set
> > > > > then we can do the TEST_STATEID/FREE_STATEID dance. If the TEST_STATEID
> > > > > fails, then we must consider the most recently acquired lock lost.
> > > > > LOCKU it and give up trying to reclaim the rest of them.
> > > > >
> > > > > For v4.0, I'm not sure what the client can do other than wait until the
> > > > > DELEGRETURN. If that fails with NFS4ERR_ADMIN_REVOKED, then we'll just
> > > > > have to try to unwind the whole mess. Send LOCKUs for all of them and
> > > > > consider them all to be lost.
> > > > >
> > > > > Actually, it may be reasonable to just do the same thing for v4.1. The
> > > > > client tracks NFS_LOCK_LOST on a per-lockstateid basis, so once you have
> > > > > any unreclaimable lock, any I/O done with that stateid is going to fail
> > > > > anyway. You might as well just release any locks you do hold at that
> > > > > point.
> > > > >
> > > > > The other question is whether the server ought to have any role to play
> > > > > here. In principle it could track whether an open/lock stateid is
> > > > > descended from a still outstanding delegation, and revoke those
> > > > > stateids if the delegation is revoked. That would probably not be
> > > > > trivial to do with the current Linux server implementation, however.
> > > 
> > > That sounds like a problem for whoever wants to implement support for
> > > administrative revocation of state.  We don't really support it
> > > currently.
> > > 
> > > Oops, right, except for the case where the delegation's revoked just
> > > because the client ran out of time doing the recall.  In which case I
> > > think the final error's going to be either EXPIRED (4.0) or
> > > DELEG_REVOKED (4.1)?  (Except I think the Linux server's returning
> > > BAD_STATEID in the 4.0 case, which looks wrong.)
> > > 
> > 
> > I'm not sure that that's right... RFC3530 says:
> > 
> >    NFS4ERR_EXPIRED       A lease has expired that is being used in the
> >                          current operation.
> > 
> > ...implicit in the scenario I layed out above is that the lease is
> > being maintained. It's just that the client failed to return the
> > delegation in time. So, BAD_STATEID may be correct, actually?
> 
> Yes, I misread that EXPIRED text.
> 
> That's a bit of a digression--in any case we agree that it's this late
> DELEGRETURN case that's the only real bug right now?
> 

Yes I think so, given that we have no mechanism to administratively
revoke delegations (other than the fault injection code, which I'll
just ignore here ;).

> On the client side I guess I can't think of anything better than your
> suggestion of waiting for the error on DELEGRETURN as you describe.
> 

...and given the comments above, we have to handle a BAD_STATEID error
on a DELEGRETURN the same way we would an ADMIN_REVOKED error, I think.

> And on the server side:
> 
> > > > What the server could (and probably should) do is revoke all
> > > > open/lock/layout state for the clientid+file combination for which it
> > > > is also revoking the delegation. That means that all applications that
> > > > were using that file on that client would be screwed, but they
> > > > probably will be anyway if the file gets corrupted due to non-atomic
> > > > locking.
> 
> That sounds harsh at first, but I guess it makes sense.
> 

Agreed. We could also consider expiring the client prematurely, but
that's even more harsh.
Trond Myklebust Nov. 5, 2014, 8:06 p.m. UTC | #14
On Wed, Nov 5, 2014 at 2:42 PM, Jeff Layton <jeff.layton@primarydata.com> wrote:
> On Wed, 5 Nov 2014 13:31:52 -0500
> "J. Bruce Fields" <bfields@fieldses.org> wrote:
>> Oops, right, except for the case where the delegation's revoked just
>> because the client ran out of time doing the recall.  In which case I
>> think the final error's going to be either EXPIRED (4.0) or
>> DELEG_REVOKED (4.1)?  (Except I think the Linux server's returning
>> BAD_STATEID in the 4.0 case, which looks wrong.)
>>
>
> I'm not sure that that's right... RFC3530 says:
>
>    NFS4ERR_EXPIRED       A lease has expired that is being used in the
>                          current operation.
>
> ...implicit in the scenario I layed out above is that the lease is
> being maintained. It's just that the client failed to return the
> delegation in time. So, BAD_STATEID may be correct, actually?

NFS4ERR_ADMIN_REVOKED is the expected error, but that requires the
server to keep the stateid around for a while (which is why NFSv4.1
added the FREE_STATEID requirement). NFS4ERR_BAD_STATEID will work in
a pinch...
J. Bruce Fields Nov. 5, 2014, 8:13 p.m. UTC | #15
On Wed, Nov 05, 2014 at 03:06:02PM -0500, Jeff Layton wrote:
> On Wed, 5 Nov 2014 14:54:20 -0500
> "J. Bruce Fields" <bfields@fieldses.org> wrote:
> 
> > On Wed, Nov 05, 2014 at 02:42:51PM -0500, Jeff Layton wrote:
> > > On Wed, 5 Nov 2014 13:31:52 -0500
> > > "J. Bruce Fields" <bfields@fieldses.org> wrote:
> > > 
> > > > On Wed, Nov 05, 2014 at 07:41:58AM -0500, Trond Myklebust wrote:
> > > > > On Wed, Nov 5, 2014 at 6:57 AM, Jeff Layton <jeff.layton@primarydata.com> wrote:
> > > > > > (cc'ing Tom here since we may want to consider providing guidance in
> > > > > >  the spec for this situation)
> > > > > >
> > > > > > Ok, I think both of you are right here :). Here's my interpretation:
> > > > > >
> > > > > > Olga is correct that the LOCK operation itself is safe since LOCK
> > > > > > doesn't actually modify the contents of the file. What it's not safe to
> > > > > > do is to trust that LOCK unless and until the DELEGRETURN is also
> > > > > > successful.
> > > > > >
> > > > > > First, let's clarify the potential race that Trond pointed out:
> > > > > >
> > > > > > Suppose we have a delegation and delegated locks. That delegation is
> > > > > > recalled and we do something like this:
> > > > > >
> > > > > > OPEN with DELEGATE_CUR: NFS4_OK
> > > > > > LOCK:                   NFS4_OK
> > > > > > LOCK:                   NFS4_OK
> > > > > > ...(maybe more successful locks here)...
> > > > > > DELEGRETURN:            NFS4ERR_ADMIN_REVOKED
> > > > > >
> > > > > > ...at that point, we're screwed.
> > > > > >
> > > > > > The delegation was obviously revoked after we did the OPEN but before
> > > > > > the DELEGRETURN. None of those LOCK requests can be trusted since
> > > > > > another client may have opened the file at any point in there, acquired
> > > > > > any one of those locks and then released it.
> > > > > >
> > > > > > For v4.1+ the client can do what Trond suggests. Check for
> > > > > > SEQ4_STATUS_RECALLABLE_STATE_REVOKED in each LOCK response. If it's set
> > > > > > then we can do the TEST_STATEID/FREE_STATEID dance. If the TEST_STATEID
> > > > > > fails, then we must consider the most recently acquired lock lost.
> > > > > > LOCKU it and give up trying to reclaim the rest of them.
> > > > > >
> > > > > > For v4.0, I'm not sure what the client can do other than wait until the
> > > > > > DELEGRETURN. If that fails with NFS4ERR_ADMIN_REVOKED, then we'll just
> > > > > > have to try to unwind the whole mess. Send LOCKUs for all of them and
> > > > > > consider them all to be lost.
> > > > > >
> > > > > > Actually, it may be reasonable to just do the same thing for v4.1. The
> > > > > > client tracks NFS_LOCK_LOST on a per-lockstateid basis, so once you have
> > > > > > any unreclaimable lock, any I/O done with that stateid is going to fail
> > > > > > anyway. You might as well just release any locks you do hold at that
> > > > > > point.
> > > > > >
> > > > > > The other question is whether the server ought to have any role to play
> > > > > > here. In principle it could track whether an open/lock stateid is
> > > > > > descended from a still outstanding delegation, and revoke those
> > > > > > stateids if the delegation is revoked. That would probably not be
> > > > > > trivial to do with the current Linux server implementation, however.
> > > > 
> > > > That sounds like a problem for whoever wants to implement support for
> > > > administrative revocation of state.  We don't really support it
> > > > currently.
> > > > 
> > > > Oops, right, except for the case where the delegation's revoked just
> > > > because the client ran out of time doing the recall.  In which case I
> > > > think the final error's going to be either EXPIRED (4.0) or
> > > > DELEG_REVOKED (4.1)?  (Except I think the Linux server's returning
> > > > BAD_STATEID in the 4.0 case, which looks wrong.)
> > > > 
> > > 
> > > I'm not sure that that's right... RFC3530 says:
> > > 
> > >    NFS4ERR_EXPIRED       A lease has expired that is being used in the
> > >                          current operation.
> > > 
> > > ...implicit in the scenario I layed out above is that the lease is
> > > being maintained. It's just that the client failed to return the
> > > delegation in time. So, BAD_STATEID may be correct, actually?
> > 
> > Yes, I misread that EXPIRED text.
> > 
> > That's a bit of a digression--in any case we agree that it's this late
> > DELEGRETURN case that's the only real bug right now?
> > 
> 
> Yes I think so, given that we have no mechanism to administratively
> revoke delegations (other than the fault injection code, which I'll
> just ignore here ;).
> 
> > On the client side I guess I can't think of anything better than your
> > suggestion of waiting for the error on DELEGRETURN as you describe.
> > 
> 
> ...and given the comments above, we have to handle a BAD_STATEID error
> on a DELEGRETURN the same way we would an ADMIN_REVOKED error, I think.

And DELEG_REVOKED in the >=4.1 case.

And now that I look at it I think there's a server bug there--it looks
like it's still returning BAD_STATEID in the >=4.1 case, but it should
be returning DELEG_REVOKED.

--b.
--
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
diff mbox

Patch

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5aa55c1..523fae0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1682,6 +1682,22 @@  int nfs4_open_delegation_recall(struct
nfs_open_context *ctx, struct nfs4_state
        nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
        err = nfs4_open_recover(opendata, state);
        nfs4_opendata_put(opendata);
+       switch(err) {
+               case -NFS4ERR_DELEG_REVOKED:
+               case -NFS4ERR_ADMIN_REVOKED:
+               case -NFS4ERR_BAD_STATEID:
+               case -NFS4ERR_OPENMODE: {
+                       struct nfs4_lock_state *lock;
+                       /* go through open locks and mark them lost */
+                       spin_lock(&state->state_lock);
+                       list_for_each_entry(lock, &state->lock_states,
ls_locks) {
+                               if (!test_bit(NFS_LOCK_INITIALIZED,
&lock->ls_flags))
+                                       set_bit(NFS_LOCK_LOST, &lock->ls_flags);
+                       }
+                       spin_unlock(&state->state_lock);
+                       return 0;
+               }
+       }