* [PATCH] nfsd: remove long-standing revoked delegations by force
@ 2025-09-02 2:22 Li Lingfeng
2025-09-02 10:21 ` Jeff Layton
0 siblings, 1 reply; 13+ messages in thread
From: Li Lingfeng @ 2025-09-02 2:22 UTC (permalink / raw)
To: chuck.lever, jlayton, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel
Cc: yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng, lilingfeng3,
zhangjian496
When file access conflicts occur between clients, the server recalls
delegations. If the client holding delegation fails to return it after
a recall, nfs4_laundromat adds the delegation to cl_revoked list.
This causes subsequent SEQUENCE operations to set the
SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag, forcing the client to
validate all delegations and return the revoked one.
However, if the client fails to return the delegation due to a timeout
after receiving the recall or a server bug, the delegation remains in the
server's cl_revoked list. The client marks it revoked and won't find it
upon detecting SEQ4_STATUS_RECALLABLE_STATE_REVOKED. This leads to a loop:
the server persistently sets SEQ4_STATUS_RECALLABLE_STATE_REVOKED, and the
client repeatedly tests all delegations, severely impacting performance
when numerous delegations exist.
Since abnormal delegations are removed from flc_lease via nfs4_laundromat
--> revoke_delegation --> destroy_unhashed_deleg -->
nfs4_unlock_deleg_lease --> kernel_setlease, and do not block new open
requests indefinitely, retaining such a delegation on the server is
unnecessary.
Reported-by: Zhang Jian <zhangjian496@huawei.com>
Fixes: 3bd64a5ba171 ("nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED")
Closes: https://lore.kernel.org/all/ff8debe9-6877-4cf7-ba29-fc98eae0ffa0@huawei.com/
Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
---
fs/nfsd/nfs4state.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 88c347957da5..aa65a685dbb9 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4326,6 +4326,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
int buflen;
struct net *net = SVC_NET(rqstp);
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct list_head *pos, *next;
+ struct nfs4_delegation *dp;
if (resp->opcnt != 1)
return nfserr_sequence_pos;
@@ -4470,6 +4472,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
default:
seq->status_flags = 0;
}
+ if (!list_empty(&clp->cl_revoked)) {
+ list_for_each_safe(pos, next, &clp->cl_revoked) {
+ dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
+ if (dp->dl_time < (ktime_get_boottime_seconds() - 2 * nn->nfsd4_lease)) {
+ list_del_init(&dp->dl_recall_lru);
+ nfs4_put_stid(&dp->dl_stid);
+ }
+ }
+ }
if (!list_empty(&clp->cl_revoked))
seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
if (atomic_read(&clp->cl_admin_revoked))
--
2.46.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 2:22 [PATCH] nfsd: remove long-standing revoked delegations by force Li Lingfeng
@ 2025-09-02 10:21 ` Jeff Layton
2025-09-02 12:10 ` Li Lingfeng
0 siblings, 1 reply; 13+ messages in thread
From: Jeff Layton @ 2025-09-02 10:21 UTC (permalink / raw)
To: Li Lingfeng, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel
Cc: yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng, zhangjian496
On Tue, 2025-09-02 at 10:22 +0800, Li Lingfeng wrote:
> When file access conflicts occur between clients, the server recalls
> delegations. If the client holding delegation fails to return it after
> a recall, nfs4_laundromat adds the delegation to cl_revoked list.
> This causes subsequent SEQUENCE operations to set the
> SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag, forcing the client to
> validate all delegations and return the revoked one.
>
> However, if the client fails to return the delegation due to a timeout
> after receiving the recall or a server bug, the delegation remains in the
> server's cl_revoked list. The client marks it revoked and won't find it
> upon detecting SEQ4_STATUS_RECALLABLE_STATE_REVOKED. This leads to a loop:
> the server persistently sets SEQ4_STATUS_RECALLABLE_STATE_REVOKED, and the
> client repeatedly tests all delegations, severely impacting performance
> when numerous delegations exist.
>
It is a performance impact, but I don't get the "loop" here. Are you
saying that this problem compounds itself? That testing all delegations
causes others to be revoked?
> Since abnormal delegations are removed from flc_lease via nfs4_laundromat
> --> revoke_delegation --> destroy_unhashed_deleg -->
> nfs4_unlock_deleg_lease --> kernel_setlease, and do not block new open
> requests indefinitely, retaining such a delegation on the server is
> unnecessary.
>
> Reported-by: Zhang Jian <zhangjian496@huawei.com>
> Fixes: 3bd64a5ba171 ("nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED")
> Closes: https://lore.kernel.org/all/ff8debe9-6877-4cf7-ba29-fc98eae0ffa0@huawei.com/
> Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
> ---
> fs/nfsd/nfs4state.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 88c347957da5..aa65a685dbb9 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -4326,6 +4326,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> int buflen;
> struct net *net = SVC_NET(rqstp);
> struct nfsd_net *nn = net_generic(net, nfsd_net_id);
> + struct list_head *pos, *next;
> + struct nfs4_delegation *dp;
>
> if (resp->opcnt != 1)
> return nfserr_sequence_pos;
> @@ -4470,6 +4472,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> default:
> seq->status_flags = 0;
> }
> + if (!list_empty(&clp->cl_revoked)) {
> + list_for_each_safe(pos, next, &clp->cl_revoked) {
> + dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
> + if (dp->dl_time < (ktime_get_boottime_seconds() - 2 * nn->nfsd4_lease)) {
> + list_del_init(&dp->dl_recall_lru);
> + nfs4_put_stid(&dp->dl_stid);
> + }
> + }
> + }
> if (!list_empty(&clp->cl_revoked))
> seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
> if (atomic_read(&clp->cl_admin_revoked))
This seems like a violation of the spec. AIUI, the server is required
to hang onto a record of the delegation until the client does the
TEST_STATEID/FREE_STATEID dance to remove it. Just discarding them like
this seems wrong.
Should we instead just administratively evict the client since it's
clearly not behaving right in this case?
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 10:21 ` Jeff Layton
@ 2025-09-02 12:10 ` Li Lingfeng
2025-09-02 12:43 ` Benjamin Coddington
2025-09-02 13:40 ` Jeff Layton
0 siblings, 2 replies; 13+ messages in thread
From: Li Lingfeng @ 2025-09-02 12:10 UTC (permalink / raw)
To: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel
Cc: yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng, zhangjian496
Hi,
在 2025/9/2 18:21, Jeff Layton 写道:
> On Tue, 2025-09-02 at 10:22 +0800, Li Lingfeng wrote:
>> When file access conflicts occur between clients, the server recalls
>> delegations. If the client holding delegation fails to return it after
>> a recall, nfs4_laundromat adds the delegation to cl_revoked list.
>> This causes subsequent SEQUENCE operations to set the
>> SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag, forcing the client to
>> validate all delegations and return the revoked one.
>>
>> However, if the client fails to return the delegation due to a timeout
>> after receiving the recall or a server bug, the delegation remains in the
>> server's cl_revoked list. The client marks it revoked and won't find it
>> upon detecting SEQ4_STATUS_RECALLABLE_STATE_REVOKED. This leads to a loop:
>> the server persistently sets SEQ4_STATUS_RECALLABLE_STATE_REVOKED, and the
>> client repeatedly tests all delegations, severely impacting performance
>> when numerous delegations exist.
>>
> It is a performance impact, but I don't get the "loop" here. Are you
> saying that this problem compounds itself? That testing all delegations
> causes others to be revoked?
The delegation will be removed from server->delegations in client after
NFSPROC4_CLNT_DELEGRETURN is performed.
nfs4_delegreturn_done
nfs_delegation_mark_returned
nfs_detach_delegation
nfs_detach_delegation_locked
list_del_rcu // remove delegation from server->delegations
From the client's perspective, the delegation has been returned, but on
the server side, it is left in the cl_revoked list.[1].
Subsequently, every sequence from the client will be flagged with
SEQ4_STATUS_RECALLABLE_STATE_REVOKED as long as cl_revoked remains
non-empty.
nfsd4_sequence
seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED
When the client detects SEQ4_STATUS_RECALLABLE_STATE_REVOKED while
processing a sequence result, it sets NFS_DELEGATION_TEST_EXPIRED for all
delegations and wakes up the state manager for handling.
nfs41_sequence_done
nfs41_sequence_process
nfs41_handle_sequence_flag_errors
nfs41_handle_recallable_state_revoked
nfs_test_expired_all_delegations
nfs_mark_test_expired_all_delegations
nfs_delegation_mark_test_expired_server
// set NFS_DELEGATION_TEST_EXPIRED for delegations in
server->delegations
nfs4_schedule_state_manager
The state manager tests all delegations except the one that was returned,
as it is no longer in server->delegations.
nfs4_state_manager
nfs4_begin_drain_session
nfs_reap_expired_delegations
nfs_server_reap_expired_delegations
// test delegations in server->delegations
There may be a loop:
1) send a sequence(client)
2) return SEQ4_STATUS_RECALLABLE_STATE_REVOKED(server)
3) set NFS_DELEGATION_TEST_EXPIRED for all delegations(client)
4) test all delegations by state manager(client)
5) send another sequence(client)
The state manager's traversal of delegations occurs between
nfs4_begin_drain_session and nfs4_end_drain_session. Non-privileged requests
will be blocked because the NFS4_SLOT_TBL_DRAINING flag is set. If there are
many delegations to traverse, this blocking time can be relatively long.
>> Since abnormal delegations are removed from flc_lease via nfs4_laundromat
>> --> revoke_delegation --> destroy_unhashed_deleg -->
>> nfs4_unlock_deleg_lease --> kernel_setlease, and do not block new open
>> requests indefinitely, retaining such a delegation on the server is
>> unnecessary.
>>
>> Reported-by: Zhang Jian <zhangjian496@huawei.com>
>> Fixes: 3bd64a5ba171 ("nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED")
>> Closes: https://lore.kernel.org/all/ff8debe9-6877-4cf7-ba29-fc98eae0ffa0@huawei.com/
>> Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
>> ---
>> fs/nfsd/nfs4state.c | 11 +++++++++++
>> 1 file changed, 11 insertions(+)
>>
>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> index 88c347957da5..aa65a685dbb9 100644
>> --- a/fs/nfsd/nfs4state.c
>> +++ b/fs/nfsd/nfs4state.c
>> @@ -4326,6 +4326,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>> int buflen;
>> struct net *net = SVC_NET(rqstp);
>> struct nfsd_net *nn = net_generic(net, nfsd_net_id);
>> + struct list_head *pos, *next;
>> + struct nfs4_delegation *dp;
>>
>> if (resp->opcnt != 1)
>> return nfserr_sequence_pos;
>> @@ -4470,6 +4472,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>> default:
>> seq->status_flags = 0;
>> }
>> + if (!list_empty(&clp->cl_revoked)) {
>> + list_for_each_safe(pos, next, &clp->cl_revoked) {
>> + dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
>> + if (dp->dl_time < (ktime_get_boottime_seconds() - 2 * nn->nfsd4_lease)) {
>> + list_del_init(&dp->dl_recall_lru);
>> + nfs4_put_stid(&dp->dl_stid);
>> + }
>> + }
>> + }
>> if (!list_empty(&clp->cl_revoked))
>> seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
>> if (atomic_read(&clp->cl_admin_revoked))
> This seems like a violation of the spec. AIUI, the server is required
> to hang onto a record of the delegation until the client does the
> TEST_STATEID/FREE_STATEID dance to remove it. Just discarding them like
> this seems wrong.
Our expected outcome was that the client would release the abnormal
delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
However, this problematic delegation is no longer present in the
client's server->delegations list—whether due to client-side timeouts or
the server-side bug [1].
>
> Should we instead just administratively evict the client since it's
> clearly not behaving right in this case?
Thanks for the suggestion. While administratively evicting the client would
certainly resolve the immediate delegation issue, I'm concerned that
approach
might be a bit heavy-handed.
The problematic behavior seems isolated to a single delegation. Meanwhile,
the client itself likely has numerous other open files and active state on
the server. Forcing a complete client reconnect would tear down all that
state, which could cause significant application disruption and be perceived
as a service outage from the client's perspective.
[1]
https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
Thanks,
Lingfeng
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 12:10 ` Li Lingfeng
@ 2025-09-02 12:43 ` Benjamin Coddington
2025-09-02 13:08 ` Li Lingfeng
2025-09-03 3:46 ` zhangjian (CG)
2025-09-02 13:40 ` Jeff Layton
1 sibling, 2 replies; 13+ messages in thread
From: Benjamin Coddington @ 2025-09-02 12:43 UTC (permalink / raw)
To: Li Lingfeng
Cc: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel, yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng,
zhangjian496
On 2 Sep 2025, at 8:10, Li Lingfeng wrote:
> Our expected outcome was that the client would release the abnormal
> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
> However, this problematic delegation is no longer present in the
> client's server->delegations list—whether due to client-side timeouts or
> the server-side bug [1].
How does the client timeout TEST_STATEID - are you mounting with 'soft'?
We should find the server-side bug and fix it rather than write code to
paper over it. I do think the synchronization of state here is a bit
fragile and wish the protocol had a generation, sequence, or marker for
setting SEQ4_STATUS_ bits..
>>
>> Should we instead just administratively evict the client since it's
>> clearly not behaving right in this case?
> Thanks for the suggestion. While administratively evicting the client would
> certainly resolve the immediate delegation issue, I'm concerned that approach
> might be a bit heavy-handed.
> The problematic behavior seems isolated to a single delegation. Meanwhile,
> the client itself likely has numerous other open files and active state on
> the server. Forcing a complete client reconnect would tear down all that
> state, which could cause significant application disruption and be perceived
> as a service outage from the client's perspective.
>
> [1] https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
^^ in this thread you reference v5.10 - there was a knfsd fix for a
cl_revoked leak "3b816601e279", and there have been 3 or 4 fixes to fix
problems and optimize the client walk of delegations since then. Jeff
pointed out that there have been fixes in these areas. Are you finding this
problem still with all those fixes included?
Ben
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 12:43 ` Benjamin Coddington
@ 2025-09-02 13:08 ` Li Lingfeng
2025-09-03 3:46 ` zhangjian (CG)
1 sibling, 0 replies; 13+ messages in thread
From: Li Lingfeng @ 2025-09-02 13:08 UTC (permalink / raw)
To: Benjamin Coddington
Cc: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel, yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng,
zhangjian496
Hi, Ben
在 2025/9/2 20:43, Benjamin Coddington 写道:
> On 2 Sep 2025, at 8:10, Li Lingfeng wrote:
>
>> Our expected outcome was that the client would release the abnormal
>> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
>> However, this problematic delegation is no longer present in the
>> client's server->delegations list—whether due to client-side timeouts or
>> the server-side bug [1].
> How does the client timeout TEST_STATEID - are you mounting with 'soft'?
I have never actually encountered a timeout; on 5.10, I triggered it by
forcibly injecting a timeout error.
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6509,6 +6509,10 @@ static void nfs4_delegreturn_prepare(struct
rpc_task *task, void *data)
&d_data->args.seq_args,
&d_data->res.seq_res,
task);
+
+ printk("%s force inject err\n", __func__);
+ task->tk_rpc_status = -ETIMEDOUT;
+ rpc_exit(task, -ETIMEDOUT);
}
> We should find the server-side bug and fix it rather than write code to
> paper over it. I do think the synchronization of state here is a bit
> fragile and wish the protocol had a generation, sequence, or marker for
> setting SEQ4_STATUS_ bits..
I was able to reproduce a server-side bug by adding delays (without using
fault injection). The server-side bug is detailed in reference [1].
I would appreciate it if you could provide any suggestions for
modifications.
>>> Should we instead just administratively evict the client since it's
>>> clearly not behaving right in this case?
>> Thanks for the suggestion. While administratively evicting the client would
>> certainly resolve the immediate delegation issue, I'm concerned that approach
>> might be a bit heavy-handed.
>> The problematic behavior seems isolated to a single delegation. Meanwhile,
>> the client itself likely has numerous other open files and active state on
>> the server. Forcing a complete client reconnect would tear down all that
>> state, which could cause significant application disruption and be perceived
>> as a service outage from the client's perspective.
>>
>> [1] https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
> ^^ in this thread you reference v5.10 - there was a knfsd fix for a
> cl_revoked leak "3b816601e279", and there have been 3 or 4 fixes to fix
> problems and optimize the client walk of delegations since then. Jeff
> pointed out that there have been fixes in these areas. Are you finding this
> problem still with all those fixes included?
As shown in [1], the problem can be reproduced at master(commit
b320789d6883),
I think all those fixes are included.
Thanks,
Lingfeng
>
> Ben
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 12:10 ` Li Lingfeng
2025-09-02 12:43 ` Benjamin Coddington
@ 2025-09-02 13:40 ` Jeff Layton
2025-09-02 14:21 ` Li Lingfeng
1 sibling, 1 reply; 13+ messages in thread
From: Jeff Layton @ 2025-09-02 13:40 UTC (permalink / raw)
To: Li Lingfeng, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel
Cc: yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng, zhangjian496
On Tue, 2025-09-02 at 20:10 +0800, Li Lingfeng wrote:
> Hi,
>
> 在 2025/9/2 18:21, Jeff Layton 写道:
> > On Tue, 2025-09-02 at 10:22 +0800, Li Lingfeng wrote:
> > > When file access conflicts occur between clients, the server recalls
> > > delegations. If the client holding delegation fails to return it after
> > > a recall, nfs4_laundromat adds the delegation to cl_revoked list.
> > > This causes subsequent SEQUENCE operations to set the
> > > SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag, forcing the client to
> > > validate all delegations and return the revoked one.
> > >
> > > However, if the client fails to return the delegation due to a timeout
> > > after receiving the recall or a server bug, the delegation remains in the
> > > server's cl_revoked list. The client marks it revoked and won't find it
> > > upon detecting SEQ4_STATUS_RECALLABLE_STATE_REVOKED. This leads to a loop:
> > > the server persistently sets SEQ4_STATUS_RECALLABLE_STATE_REVOKED, and the
> > > client repeatedly tests all delegations, severely impacting performance
> > > when numerous delegations exist.
> > >
> > It is a performance impact, but I don't get the "loop" here. Are you
> > saying that this problem compounds itself? That testing all delegations
> > causes others to be revoked?
> The delegation will be removed from server->delegations in client after
> NFSPROC4_CLNT_DELEGRETURN is performed.
> nfs4_delegreturn_done
> nfs_delegation_mark_returned
> nfs_detach_delegation
> nfs_detach_delegation_locked
> list_del_rcu // remove delegation from server->delegations
>
> From the client's perspective, the delegation has been returned, but on
> the server side, it is left in the cl_revoked list.[1].
>
> Subsequently, every sequence from the client will be flagged with
> SEQ4_STATUS_RECALLABLE_STATE_REVOKED as long as cl_revoked remains
> non-empty.
> nfsd4_sequence
> seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED
>
> When the client detects SEQ4_STATUS_RECALLABLE_STATE_REVOKED while
> processing a sequence result, it sets NFS_DELEGATION_TEST_EXPIRED for all
> delegations and wakes up the state manager for handling.
> nfs41_sequence_done
> nfs41_sequence_process
> nfs41_handle_sequence_flag_errors
> nfs41_handle_recallable_state_revoked
> nfs_test_expired_all_delegations
> nfs_mark_test_expired_all_delegations
> nfs_delegation_mark_test_expired_server
> // set NFS_DELEGATION_TEST_EXPIRED for delegations in
> server->delegations
> nfs4_schedule_state_manager
>
> The state manager tests all delegations except the one that was returned,
> as it is no longer in server->delegations.
> nfs4_state_manager
> nfs4_begin_drain_session
> nfs_reap_expired_delegations
> nfs_server_reap_expired_delegations
> // test delegations in server->delegations
>
> There may be a loop:
> 1) send a sequence(client)
> 2) return SEQ4_STATUS_RECALLABLE_STATE_REVOKED(server)
> 3) set NFS_DELEGATION_TEST_EXPIRED for all delegations(client)
> 4) test all delegations by state manager(client)
> 5) send another sequence(client)
>
> The state manager's traversal of delegations occurs between
> nfs4_begin_drain_session and nfs4_end_drain_session. Non-privileged requests
> will be blocked because the NFS4_SLOT_TBL_DRAINING flag is set. If there are
> many delegations to traverse, this blocking time can be relatively long.
> > > Since abnormal delegations are removed from flc_lease via nfs4_laundromat
> > > --> revoke_delegation --> destroy_unhashed_deleg -->
> > > nfs4_unlock_deleg_lease --> kernel_setlease, and do not block new open
> > > requests indefinitely, retaining such a delegation on the server is
> > > unnecessary.
> > >
> > > Reported-by: Zhang Jian <zhangjian496@huawei.com>
> > > Fixes: 3bd64a5ba171 ("nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED")
> > > Closes: https://lore.kernel.org/all/ff8debe9-6877-4cf7-ba29-fc98eae0ffa0@huawei.com/
> > > Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
> > > ---
> > > fs/nfsd/nfs4state.c | 11 +++++++++++
> > > 1 file changed, 11 insertions(+)
> > >
> > > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > > index 88c347957da5..aa65a685dbb9 100644
> > > --- a/fs/nfsd/nfs4state.c
> > > +++ b/fs/nfsd/nfs4state.c
> > > @@ -4326,6 +4326,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > > int buflen;
> > > struct net *net = SVC_NET(rqstp);
> > > struct nfsd_net *nn = net_generic(net, nfsd_net_id);
> > > + struct list_head *pos, *next;
> > > + struct nfs4_delegation *dp;
> > >
> > > if (resp->opcnt != 1)
> > > return nfserr_sequence_pos;
> > > @@ -4470,6 +4472,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > > default:
> > > seq->status_flags = 0;
> > > }
> > > + if (!list_empty(&clp->cl_revoked)) {
> > > + list_for_each_safe(pos, next, &clp->cl_revoked) {
> > > + dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
> > > + if (dp->dl_time < (ktime_get_boottime_seconds() - 2 * nn->nfsd4_lease)) {
> > > + list_del_init(&dp->dl_recall_lru);
> > > + nfs4_put_stid(&dp->dl_stid);
> > > + }
> > > + }
FYI: this list is protected by the clp->cl_lock. You need to hold it to
do this list walk.
> > > + }
> > > if (!list_empty(&clp->cl_revoked))
> > > seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
> > > if (atomic_read(&clp->cl_admin_revoked))
> > This seems like a violation of the spec. AIUI, the server is required
> > to hang onto a record of the delegation until the client does the
> > TEST_STATEID/FREE_STATEID dance to remove it. Just discarding them like
> > this seems wrong.
> Our expected outcome was that the client would release the abnormal
> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
> However, this problematic delegation is no longer present in the
> client's server->delegations list—whether due to client-side timeouts or
> the server-side bug [1].
> >
> > Should we instead just administratively evict the client since it's
> > clearly not behaving right in this case?
> Thanks for the suggestion. While administratively evicting the client would
> certainly resolve the immediate delegation issue, I'm concerned that
> approach
> might be a bit heavy-handed.
> The problematic behavior seems isolated to a single delegation. Meanwhile,
> the client itself likely has numerous other open files and active state on
> the server. Forcing a complete client reconnect would tear down all that
> state, which could cause significant application disruption and be perceived
> as a service outage from the client's perspective.
>
> [1]
> https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
>
> Thanks,
> Lingfeng
Ok, I get the problem, but I still disagree with the solution. I don't
think we can just time these things out. Ideally we'd close the race
window, but the sc_status field is protected by the global state_lock
and I don't think we want to take it in revoke_delegation.
The best solution I can see is to have destroy_delegation()
unconditionally set SC_STATUS_CLOSED, and then you can do the list walk
above, but checking for that flag instead of testing for a timeout.
I'm still not thrilled with this solution though. It makes SEQUENCE a
bit more heavyweight than I'd like. I'm starting to think that we need
to rework the overall delegation locking, but that's an ugly problem to
tackle.
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 13:40 ` Jeff Layton
@ 2025-09-02 14:21 ` Li Lingfeng
2025-09-02 14:29 ` Jeff Layton
0 siblings, 1 reply; 13+ messages in thread
From: Li Lingfeng @ 2025-09-02 14:21 UTC (permalink / raw)
To: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel
Cc: yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng, zhangjian496
在 2025/9/2 21:40, Jeff Layton 写道:
> On Tue, 2025-09-02 at 20:10 +0800, Li Lingfeng wrote:
>> Hi,
>>
>> 在 2025/9/2 18:21, Jeff Layton 写道:
>>> On Tue, 2025-09-02 at 10:22 +0800, Li Lingfeng wrote:
>>>> When file access conflicts occur between clients, the server recalls
>>>> delegations. If the client holding delegation fails to return it after
>>>> a recall, nfs4_laundromat adds the delegation to cl_revoked list.
>>>> This causes subsequent SEQUENCE operations to set the
>>>> SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag, forcing the client to
>>>> validate all delegations and return the revoked one.
>>>>
>>>> However, if the client fails to return the delegation due to a timeout
>>>> after receiving the recall or a server bug, the delegation remains in the
>>>> server's cl_revoked list. The client marks it revoked and won't find it
>>>> upon detecting SEQ4_STATUS_RECALLABLE_STATE_REVOKED. This leads to a loop:
>>>> the server persistently sets SEQ4_STATUS_RECALLABLE_STATE_REVOKED, and the
>>>> client repeatedly tests all delegations, severely impacting performance
>>>> when numerous delegations exist.
>>>>
>>> It is a performance impact, but I don't get the "loop" here. Are you
>>> saying that this problem compounds itself? That testing all delegations
>>> causes others to be revoked?
>> The delegation will be removed from server->delegations in client after
>> NFSPROC4_CLNT_DELEGRETURN is performed.
>> nfs4_delegreturn_done
>> nfs_delegation_mark_returned
>> nfs_detach_delegation
>> nfs_detach_delegation_locked
>> list_del_rcu // remove delegation from server->delegations
>>
>> From the client's perspective, the delegation has been returned, but on
>> the server side, it is left in the cl_revoked list.[1].
>>
>> Subsequently, every sequence from the client will be flagged with
>> SEQ4_STATUS_RECALLABLE_STATE_REVOKED as long as cl_revoked remains
>> non-empty.
>> nfsd4_sequence
>> seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED
>>
>> When the client detects SEQ4_STATUS_RECALLABLE_STATE_REVOKED while
>> processing a sequence result, it sets NFS_DELEGATION_TEST_EXPIRED for all
>> delegations and wakes up the state manager for handling.
>> nfs41_sequence_done
>> nfs41_sequence_process
>> nfs41_handle_sequence_flag_errors
>> nfs41_handle_recallable_state_revoked
>> nfs_test_expired_all_delegations
>> nfs_mark_test_expired_all_delegations
>> nfs_delegation_mark_test_expired_server
>> // set NFS_DELEGATION_TEST_EXPIRED for delegations in
>> server->delegations
>> nfs4_schedule_state_manager
>>
>> The state manager tests all delegations except the one that was returned,
>> as it is no longer in server->delegations.
>> nfs4_state_manager
>> nfs4_begin_drain_session
>> nfs_reap_expired_delegations
>> nfs_server_reap_expired_delegations
>> // test delegations in server->delegations
>>
>> There may be a loop:
>> 1) send a sequence(client)
>> 2) return SEQ4_STATUS_RECALLABLE_STATE_REVOKED(server)
>> 3) set NFS_DELEGATION_TEST_EXPIRED for all delegations(client)
>> 4) test all delegations by state manager(client)
>> 5) send another sequence(client)
>>
>> The state manager's traversal of delegations occurs between
>> nfs4_begin_drain_session and nfs4_end_drain_session. Non-privileged requests
>> will be blocked because the NFS4_SLOT_TBL_DRAINING flag is set. If there are
>> many delegations to traverse, this blocking time can be relatively long.
>>>> Since abnormal delegations are removed from flc_lease via nfs4_laundromat
>>>> --> revoke_delegation --> destroy_unhashed_deleg -->
>>>> nfs4_unlock_deleg_lease --> kernel_setlease, and do not block new open
>>>> requests indefinitely, retaining such a delegation on the server is
>>>> unnecessary.
>>>>
>>>> Reported-by: Zhang Jian <zhangjian496@huawei.com>
>>>> Fixes: 3bd64a5ba171 ("nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED")
>>>> Closes: https://lore.kernel.org/all/ff8debe9-6877-4cf7-ba29-fc98eae0ffa0@huawei.com/
>>>> Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
>>>> ---
>>>> fs/nfsd/nfs4state.c | 11 +++++++++++
>>>> 1 file changed, 11 insertions(+)
>>>>
>>>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>>>> index 88c347957da5..aa65a685dbb9 100644
>>>> --- a/fs/nfsd/nfs4state.c
>>>> +++ b/fs/nfsd/nfs4state.c
>>>> @@ -4326,6 +4326,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>>>> int buflen;
>>>> struct net *net = SVC_NET(rqstp);
>>>> struct nfsd_net *nn = net_generic(net, nfsd_net_id);
>>>> + struct list_head *pos, *next;
>>>> + struct nfs4_delegation *dp;
>>>>
>>>> if (resp->opcnt != 1)
>>>> return nfserr_sequence_pos;
>>>> @@ -4470,6 +4472,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>>>> default:
>>>> seq->status_flags = 0;
>>>> }
>>>> + if (!list_empty(&clp->cl_revoked)) {
>>>> + list_for_each_safe(pos, next, &clp->cl_revoked) {
>>>> + dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
>>>> + if (dp->dl_time < (ktime_get_boottime_seconds() - 2 * nn->nfsd4_lease)) {
>>>> + list_del_init(&dp->dl_recall_lru);
>>>> + nfs4_put_stid(&dp->dl_stid);
>>>> + }
>>>> + }
> FYI: this list is protected by the clp->cl_lock. You need to hold it to
> do this list walk.
>
>>>> + }
>>>> if (!list_empty(&clp->cl_revoked))
>>>> seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
>>>> if (atomic_read(&clp->cl_admin_revoked))
>>> This seems like a violation of the spec. AIUI, the server is required
>>> to hang onto a record of the delegation until the client does the
>>> TEST_STATEID/FREE_STATEID dance to remove it. Just discarding them like
>>> this seems wrong.
>> Our expected outcome was that the client would release the abnormal
>> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
>> However, this problematic delegation is no longer present in the
>> client's server->delegations list—whether due to client-side timeouts or
>> the server-side bug [1].
>>> Should we instead just administratively evict the client since it's
>>> clearly not behaving right in this case?
>> Thanks for the suggestion. While administratively evicting the client would
>> certainly resolve the immediate delegation issue, I'm concerned that
>> approach
>> might be a bit heavy-handed.
>> The problematic behavior seems isolated to a single delegation. Meanwhile,
>> the client itself likely has numerous other open files and active state on
>> the server. Forcing a complete client reconnect would tear down all that
>> state, which could cause significant application disruption and be perceived
>> as a service outage from the client's perspective.
>>
>> [1]
>> https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
>>
>> Thanks,
>> Lingfeng
> Ok, I get the problem, but I still disagree with the solution. I don't
> think we can just time these things out. Ideally we'd close the race
> window, but the sc_status field is protected by the global state_lock
> and I don't think we want to take it in revoke_delegation.
>
> The best solution I can see is to have destroy_delegation()
> unconditionally set SC_STATUS_CLOSED, and then you can do the list walk
> above, but checking for that flag instead of testing for a timeout.
This might potentially affect the normal TEST_STATEID/FREE_STATEID flow,
as nfsd4_free_stateid() branches differently based on whether
SC_STATUS_CLOSED is set. Alternatively, I was wondering if you could
suggest a workaround to avoid this issue?
Thanks,
Lingfeng
>
> I'm still not thrilled with this solution though. It makes SEQUENCE a
> bit more heavyweight than I'd like. I'm starting to think that we need
> to rework the overall delegation locking, but that's an ugly problem to
> tackle.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 14:21 ` Li Lingfeng
@ 2025-09-02 14:29 ` Jeff Layton
2025-09-03 1:34 ` Li Lingfeng
0 siblings, 1 reply; 13+ messages in thread
From: Jeff Layton @ 2025-09-02 14:29 UTC (permalink / raw)
To: Li Lingfeng, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel
Cc: yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng, zhangjian496
On Tue, 2025-09-02 at 22:21 +0800, Li Lingfeng wrote:
> 在 2025/9/2 21:40, Jeff Layton 写道:
> > On Tue, 2025-09-02 at 20:10 +0800, Li Lingfeng wrote:
> > > Hi,
> > >
> > > 在 2025/9/2 18:21, Jeff Layton 写道:
> > > > On Tue, 2025-09-02 at 10:22 +0800, Li Lingfeng wrote:
> > > > > When file access conflicts occur between clients, the server recalls
> > > > > delegations. If the client holding delegation fails to return it after
> > > > > a recall, nfs4_laundromat adds the delegation to cl_revoked list.
> > > > > This causes subsequent SEQUENCE operations to set the
> > > > > SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag, forcing the client to
> > > > > validate all delegations and return the revoked one.
> > > > >
> > > > > However, if the client fails to return the delegation due to a timeout
> > > > > after receiving the recall or a server bug, the delegation remains in the
> > > > > server's cl_revoked list. The client marks it revoked and won't find it
> > > > > upon detecting SEQ4_STATUS_RECALLABLE_STATE_REVOKED. This leads to a loop:
> > > > > the server persistently sets SEQ4_STATUS_RECALLABLE_STATE_REVOKED, and the
> > > > > client repeatedly tests all delegations, severely impacting performance
> > > > > when numerous delegations exist.
> > > > >
> > > > It is a performance impact, but I don't get the "loop" here. Are you
> > > > saying that this problem compounds itself? That testing all delegations
> > > > causes others to be revoked?
> > > The delegation will be removed from server->delegations in client after
> > > NFSPROC4_CLNT_DELEGRETURN is performed.
> > > nfs4_delegreturn_done
> > > nfs_delegation_mark_returned
> > > nfs_detach_delegation
> > > nfs_detach_delegation_locked
> > > list_del_rcu // remove delegation from server->delegations
> > >
> > > From the client's perspective, the delegation has been returned, but on
> > > the server side, it is left in the cl_revoked list.[1].
> > >
> > > Subsequently, every sequence from the client will be flagged with
> > > SEQ4_STATUS_RECALLABLE_STATE_REVOKED as long as cl_revoked remains
> > > non-empty.
> > > nfsd4_sequence
> > > seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED
> > >
> > > When the client detects SEQ4_STATUS_RECALLABLE_STATE_REVOKED while
> > > processing a sequence result, it sets NFS_DELEGATION_TEST_EXPIRED for all
> > > delegations and wakes up the state manager for handling.
> > > nfs41_sequence_done
> > > nfs41_sequence_process
> > > nfs41_handle_sequence_flag_errors
> > > nfs41_handle_recallable_state_revoked
> > > nfs_test_expired_all_delegations
> > > nfs_mark_test_expired_all_delegations
> > > nfs_delegation_mark_test_expired_server
> > > // set NFS_DELEGATION_TEST_EXPIRED for delegations in
> > > server->delegations
> > > nfs4_schedule_state_manager
> > >
> > > The state manager tests all delegations except the one that was returned,
> > > as it is no longer in server->delegations.
> > > nfs4_state_manager
> > > nfs4_begin_drain_session
> > > nfs_reap_expired_delegations
> > > nfs_server_reap_expired_delegations
> > > // test delegations in server->delegations
> > >
> > > There may be a loop:
> > > 1) send a sequence(client)
> > > 2) return SEQ4_STATUS_RECALLABLE_STATE_REVOKED(server)
> > > 3) set NFS_DELEGATION_TEST_EXPIRED for all delegations(client)
> > > 4) test all delegations by state manager(client)
> > > 5) send another sequence(client)
> > >
> > > The state manager's traversal of delegations occurs between
> > > nfs4_begin_drain_session and nfs4_end_drain_session. Non-privileged requests
> > > will be blocked because the NFS4_SLOT_TBL_DRAINING flag is set. If there are
> > > many delegations to traverse, this blocking time can be relatively long.
> > > > > Since abnormal delegations are removed from flc_lease via nfs4_laundromat
> > > > > --> revoke_delegation --> destroy_unhashed_deleg -->
> > > > > nfs4_unlock_deleg_lease --> kernel_setlease, and do not block new open
> > > > > requests indefinitely, retaining such a delegation on the server is
> > > > > unnecessary.
> > > > >
> > > > > Reported-by: Zhang Jian <zhangjian496@huawei.com>
> > > > > Fixes: 3bd64a5ba171 ("nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED")
> > > > > Closes: https://lore.kernel.org/all/ff8debe9-6877-4cf7-ba29-fc98eae0ffa0@huawei.com/
> > > > > Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
> > > > > ---
> > > > > fs/nfsd/nfs4state.c | 11 +++++++++++
> > > > > 1 file changed, 11 insertions(+)
> > > > >
> > > > > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > > > > index 88c347957da5..aa65a685dbb9 100644
> > > > > --- a/fs/nfsd/nfs4state.c
> > > > > +++ b/fs/nfsd/nfs4state.c
> > > > > @@ -4326,6 +4326,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > > > > int buflen;
> > > > > struct net *net = SVC_NET(rqstp);
> > > > > struct nfsd_net *nn = net_generic(net, nfsd_net_id);
> > > > > + struct list_head *pos, *next;
> > > > > + struct nfs4_delegation *dp;
> > > > >
> > > > > if (resp->opcnt != 1)
> > > > > return nfserr_sequence_pos;
> > > > > @@ -4470,6 +4472,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > > > > default:
> > > > > seq->status_flags = 0;
> > > > > }
> > > > > + if (!list_empty(&clp->cl_revoked)) {
> > > > > + list_for_each_safe(pos, next, &clp->cl_revoked) {
> > > > > + dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
> > > > > + if (dp->dl_time < (ktime_get_boottime_seconds() - 2 * nn->nfsd4_lease)) {
> > > > > + list_del_init(&dp->dl_recall_lru);
> > > > > + nfs4_put_stid(&dp->dl_stid);
> > > > > + }
> > > > > + }
> > FYI: this list is protected by the clp->cl_lock. You need to hold it to
> > do this list walk.
> >
> > > > > + }
> > > > > if (!list_empty(&clp->cl_revoked))
> > > > > seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
> > > > > if (atomic_read(&clp->cl_admin_revoked))
> > > > This seems like a violation of the spec. AIUI, the server is required
> > > > to hang onto a record of the delegation until the client does the
> > > > TEST_STATEID/FREE_STATEID dance to remove it. Just discarding them like
> > > > this seems wrong.
> > > Our expected outcome was that the client would release the abnormal
> > > delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
> > > However, this problematic delegation is no longer present in the
> > > client's server->delegations list—whether due to client-side timeouts or
> > > the server-side bug [1].
> > > > Should we instead just administratively evict the client since it's
> > > > clearly not behaving right in this case?
> > > Thanks for the suggestion. While administratively evicting the client would
> > > certainly resolve the immediate delegation issue, I'm concerned that
> > > approach
> > > might be a bit heavy-handed.
> > > The problematic behavior seems isolated to a single delegation. Meanwhile,
> > > the client itself likely has numerous other open files and active state on
> > > the server. Forcing a complete client reconnect would tear down all that
> > > state, which could cause significant application disruption and be perceived
> > > as a service outage from the client's perspective.
> > >
> > > [1]
> > > https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
> > >
> > > Thanks,
> > > Lingfeng
> > Ok, I get the problem, but I still disagree with the solution. I don't
> > think we can just time these things out. Ideally we'd close the race
> > window, but the sc_status field is protected by the global state_lock
> > and I don't think we want to take it in revoke_delegation.
> >
> > The best solution I can see is to have destroy_delegation()
> > unconditionally set SC_STATUS_CLOSED, and then you can do the list walk
> > above, but checking for that flag instead of testing for a timeout.
> This might potentially affect the normal TEST_STATEID/FREE_STATEID flow,
> as nfsd4_free_stateid() branches differently based on whether
> SC_STATUS_CLOSED is set. Alternatively, I was wondering if you could
> suggest a workaround to avoid this issue?
>
I can't think of any workarounds other than turning off delegations
altogether.
I guess your concern is that TEST_STATEID and FREE_STATEID would return
BAD_STATEID in this case, even though the entry was still (technically)
on the cl_revoked list? That seems like correct behavior. The client
did send DELEGRETURN, after all.
> >
> > I'm still not thrilled with this solution though. It makes SEQUENCE a
> > bit more heavyweight than I'd like. I'm starting to think that we need
> > to rework the overall delegation locking, but that's an ugly problem to
> > tackle.
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 14:29 ` Jeff Layton
@ 2025-09-03 1:34 ` Li Lingfeng
0 siblings, 0 replies; 13+ messages in thread
From: Li Lingfeng @ 2025-09-03 1:34 UTC (permalink / raw)
To: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel
Cc: yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng, zhangjian496
在 2025/9/2 22:29, Jeff Layton 写道:
> On Tue, 2025-09-02 at 22:21 +0800, Li Lingfeng wrote:
>> 在 2025/9/2 21:40, Jeff Layton 写道:
>>> On Tue, 2025-09-02 at 20:10 +0800, Li Lingfeng wrote:
>>>> Hi,
>>>>
>>>> 在 2025/9/2 18:21, Jeff Layton 写道:
>>>>> On Tue, 2025-09-02 at 10:22 +0800, Li Lingfeng wrote:
>>>>>> When file access conflicts occur between clients, the server recalls
>>>>>> delegations. If the client holding delegation fails to return it after
>>>>>> a recall, nfs4_laundromat adds the delegation to cl_revoked list.
>>>>>> This causes subsequent SEQUENCE operations to set the
>>>>>> SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag, forcing the client to
>>>>>> validate all delegations and return the revoked one.
>>>>>>
>>>>>> However, if the client fails to return the delegation due to a timeout
>>>>>> after receiving the recall or a server bug, the delegation remains in the
>>>>>> server's cl_revoked list. The client marks it revoked and won't find it
>>>>>> upon detecting SEQ4_STATUS_RECALLABLE_STATE_REVOKED. This leads to a loop:
>>>>>> the server persistently sets SEQ4_STATUS_RECALLABLE_STATE_REVOKED, and the
>>>>>> client repeatedly tests all delegations, severely impacting performance
>>>>>> when numerous delegations exist.
>>>>>>
>>>>> It is a performance impact, but I don't get the "loop" here. Are you
>>>>> saying that this problem compounds itself? That testing all delegations
>>>>> causes others to be revoked?
>>>> The delegation will be removed from server->delegations in client after
>>>> NFSPROC4_CLNT_DELEGRETURN is performed.
>>>> nfs4_delegreturn_done
>>>> nfs_delegation_mark_returned
>>>> nfs_detach_delegation
>>>> nfs_detach_delegation_locked
>>>> list_del_rcu // remove delegation from server->delegations
>>>>
>>>> From the client's perspective, the delegation has been returned, but on
>>>> the server side, it is left in the cl_revoked list.[1].
>>>>
>>>> Subsequently, every sequence from the client will be flagged with
>>>> SEQ4_STATUS_RECALLABLE_STATE_REVOKED as long as cl_revoked remains
>>>> non-empty.
>>>> nfsd4_sequence
>>>> seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED
>>>>
>>>> When the client detects SEQ4_STATUS_RECALLABLE_STATE_REVOKED while
>>>> processing a sequence result, it sets NFS_DELEGATION_TEST_EXPIRED for all
>>>> delegations and wakes up the state manager for handling.
>>>> nfs41_sequence_done
>>>> nfs41_sequence_process
>>>> nfs41_handle_sequence_flag_errors
>>>> nfs41_handle_recallable_state_revoked
>>>> nfs_test_expired_all_delegations
>>>> nfs_mark_test_expired_all_delegations
>>>> nfs_delegation_mark_test_expired_server
>>>> // set NFS_DELEGATION_TEST_EXPIRED for delegations in
>>>> server->delegations
>>>> nfs4_schedule_state_manager
>>>>
>>>> The state manager tests all delegations except the one that was returned,
>>>> as it is no longer in server->delegations.
>>>> nfs4_state_manager
>>>> nfs4_begin_drain_session
>>>> nfs_reap_expired_delegations
>>>> nfs_server_reap_expired_delegations
>>>> // test delegations in server->delegations
>>>>
>>>> There may be a loop:
>>>> 1) send a sequence(client)
>>>> 2) return SEQ4_STATUS_RECALLABLE_STATE_REVOKED(server)
>>>> 3) set NFS_DELEGATION_TEST_EXPIRED for all delegations(client)
>>>> 4) test all delegations by state manager(client)
>>>> 5) send another sequence(client)
>>>>
>>>> The state manager's traversal of delegations occurs between
>>>> nfs4_begin_drain_session and nfs4_end_drain_session. Non-privileged requests
>>>> will be blocked because the NFS4_SLOT_TBL_DRAINING flag is set. If there are
>>>> many delegations to traverse, this blocking time can be relatively long.
>>>>>> Since abnormal delegations are removed from flc_lease via nfs4_laundromat
>>>>>> --> revoke_delegation --> destroy_unhashed_deleg -->
>>>>>> nfs4_unlock_deleg_lease --> kernel_setlease, and do not block new open
>>>>>> requests indefinitely, retaining such a delegation on the server is
>>>>>> unnecessary.
>>>>>>
>>>>>> Reported-by: Zhang Jian <zhangjian496@huawei.com>
>>>>>> Fixes: 3bd64a5ba171 ("nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED")
>>>>>> Closes: https://lore.kernel.org/all/ff8debe9-6877-4cf7-ba29-fc98eae0ffa0@huawei.com/
>>>>>> Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
>>>>>> ---
>>>>>> fs/nfsd/nfs4state.c | 11 +++++++++++
>>>>>> 1 file changed, 11 insertions(+)
>>>>>>
>>>>>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>>>>>> index 88c347957da5..aa65a685dbb9 100644
>>>>>> --- a/fs/nfsd/nfs4state.c
>>>>>> +++ b/fs/nfsd/nfs4state.c
>>>>>> @@ -4326,6 +4326,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>>>>>> int buflen;
>>>>>> struct net *net = SVC_NET(rqstp);
>>>>>> struct nfsd_net *nn = net_generic(net, nfsd_net_id);
>>>>>> + struct list_head *pos, *next;
>>>>>> + struct nfs4_delegation *dp;
>>>>>>
>>>>>> if (resp->opcnt != 1)
>>>>>> return nfserr_sequence_pos;
>>>>>> @@ -4470,6 +4472,15 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>>>>>> default:
>>>>>> seq->status_flags = 0;
>>>>>> }
>>>>>> + if (!list_empty(&clp->cl_revoked)) {
>>>>>> + list_for_each_safe(pos, next, &clp->cl_revoked) {
>>>>>> + dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
>>>>>> + if (dp->dl_time < (ktime_get_boottime_seconds() - 2 * nn->nfsd4_lease)) {
>>>>>> + list_del_init(&dp->dl_recall_lru);
>>>>>> + nfs4_put_stid(&dp->dl_stid);
>>>>>> + }
>>>>>> + }
>>> FYI: this list is protected by the clp->cl_lock. You need to hold it to
>>> do this list walk.
>>>
>>>>>> + }
>>>>>> if (!list_empty(&clp->cl_revoked))
>>>>>> seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
>>>>>> if (atomic_read(&clp->cl_admin_revoked))
>>>>> This seems like a violation of the spec. AIUI, the server is required
>>>>> to hang onto a record of the delegation until the client does the
>>>>> TEST_STATEID/FREE_STATEID dance to remove it. Just discarding them like
>>>>> this seems wrong.
>>>> Our expected outcome was that the client would release the abnormal
>>>> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
>>>> However, this problematic delegation is no longer present in the
>>>> client's server->delegations list—whether due to client-side timeouts or
>>>> the server-side bug [1].
>>>>> Should we instead just administratively evict the client since it's
>>>>> clearly not behaving right in this case?
>>>> Thanks for the suggestion. While administratively evicting the client would
>>>> certainly resolve the immediate delegation issue, I'm concerned that
>>>> approach
>>>> might be a bit heavy-handed.
>>>> The problematic behavior seems isolated to a single delegation. Meanwhile,
>>>> the client itself likely has numerous other open files and active state on
>>>> the server. Forcing a complete client reconnect would tear down all that
>>>> state, which could cause significant application disruption and be perceived
>>>> as a service outage from the client's perspective.
>>>>
>>>> [1]
>>>> https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
>>>>
>>>> Thanks,
>>>> Lingfeng
>>> Ok, I get the problem, but I still disagree with the solution. I don't
>>> think we can just time these things out. Ideally we'd close the race
>>> window, but the sc_status field is protected by the global state_lock
>>> and I don't think we want to take it in revoke_delegation.
>>>
>>> The best solution I can see is to have destroy_delegation()
>>> unconditionally set SC_STATUS_CLOSED, and then you can do the list walk
>>> above, but checking for that flag instead of testing for a timeout.
>> This might potentially affect the normal TEST_STATEID/FREE_STATEID flow,
>> as nfsd4_free_stateid() branches differently based on whether
>> SC_STATUS_CLOSED is set. Alternatively, I was wondering if you could
>> suggest a workaround to avoid this issue?
>>
> I can't think of any workarounds other than turning off delegations
> altogether.
>
> I guess your concern is that TEST_STATEID and FREE_STATEID would return
> BAD_STATEID in this case, even though the entry was still (technically)
> on the cl_revoked list? That seems like correct behavior. The client
> did send DELEGRETURN, after all.
Sorry for the noice. I was mistaken.
I was originally concerned that after setting SC_STATUS_CLOSED via
nfsd4_delegreturn --> destroy_delegation, if the client initiated a
FREE_STATEID, the server would skip the SC_TYPE_DELEG branch in
nfsd4_free_stateid() that would normally be executed.
However, in reality, after the client completes DELEGRETURN, it will not
perform FREE_STATEID for this delegation again since the delegation is
no longer in server->delegations.
Thanks,
Lingfeng
>
>>> I'm still not thrilled with this solution though. It makes SEQUENCE a
>>> bit more heavyweight than I'd like. I'm starting to think that we need
>>> to rework the overall delegation locking, but that's an ugly problem to
>>> tackle.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-02 12:43 ` Benjamin Coddington
2025-09-02 13:08 ` Li Lingfeng
@ 2025-09-03 3:46 ` zhangjian (CG)
2025-09-03 6:45 ` Li Lingfeng
1 sibling, 1 reply; 13+ messages in thread
From: zhangjian (CG) @ 2025-09-03 3:46 UTC (permalink / raw)
To: Benjamin Coddington, Li Lingfeng
Cc: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel, yukuai1, houtao1, yi.zhang, yangerkun, lilingfeng
Hello every experts.
If we can see all delegations on hard-mounted nfs client, which are also
on server cl_revoked list, changed from
NFS_DELEGATION_RETURN_IF_CLOSED|NFS_DELEGATION_REVOKED|NFS_DELEGATION_TEST_EXPIRED
to NFS_DELEGATION_RETURN_IF_CLOSED|NFS_DELEGATION_REVOKED, can we give
some hypothesis on this problem ?
By the way, this problem can be cover over by decreasing file count on
server.
Thanks,
zhangjian
On 2025/9/2 20:43, Benjamin Coddington wrote:
> On 2 Sep 2025, at 8:10, Li Lingfeng wrote:
>
>> Our expected outcome was that the client would release the abnormal
>> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
>> However, this problematic delegation is no longer present in the
>> client's server->delegations list—whether due to client-side timeouts or
>> the server-side bug [1].
>
> How does the client timeout TEST_STATEID - are you mounting with 'soft'?
>
> We should find the server-side bug and fix it rather than write code to
> paper over it. I do think the synchronization of state here is a bit
> fragile and wish the protocol had a generation, sequence, or marker for
> setting SEQ4_STATUS_ bits..
>
>>>
>>> Should we instead just administratively evict the client since it's
>>> clearly not behaving right in this case?
>> Thanks for the suggestion. While administratively evicting the client would
>> certainly resolve the immediate delegation issue, I'm concerned that approach
>> might be a bit heavy-handed.
>> The problematic behavior seems isolated to a single delegation. Meanwhile,
>> the client itself likely has numerous other open files and active state on
>> the server. Forcing a complete client reconnect would tear down all that
>> state, which could cause significant application disruption and be perceived
>> as a service outage from the client's perspective.
>>
>> [1] https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
>
> ^^ in this thread you reference v5.10 - there was a knfsd fix for a
> cl_revoked leak "3b816601e279", and there have been 3 or 4 fixes to fix
> problems and optimize the client walk of delegations since then. Jeff
> pointed out that there have been fixes in these areas. Are you finding this
> problem still with all those fixes included?
>
> Ben
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-03 3:46 ` zhangjian (CG)
@ 2025-09-03 6:45 ` Li Lingfeng
2025-09-03 10:06 ` zhangjian (CG)
0 siblings, 1 reply; 13+ messages in thread
From: Li Lingfeng @ 2025-09-03 6:45 UTC (permalink / raw)
To: zhangjian (CG), Benjamin Coddington, Li Lingfeng
Cc: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel, yukuai1, houtao1, yi.zhang, yangerkun
Hi,
在 2025/9/3 11:46, zhangjian (CG) 写道:
> Hello every experts.
>
> If we can see all delegations on hard-mounted nfs client, which are also
> on server cl_revoked list, changed from
> NFS_DELEGATION_RETURN_IF_CLOSED|NFS_DELEGATION_REVOKED|NFS_DELEGATION_TEST_EXPIRED
> to NFS_DELEGATION_RETURN_IF_CLOSED|NFS_DELEGATION_REVOKED, can we give
> some hypothesis on this problem ?
>
> By the way, this problem can be cover over by decreasing file count on
> server.
>
> Thanks,
> zhangjian
I think NFS_DELEGATION_TEST_EXPIRED is cleared as follows:
nfs4_state_manager
nfs4_do_reclaim
nfs4_reclaim_open_state
__nfs4_reclaim_open_state // get nfs4_state from sp->so_states
nfs41_open_expired // status = ops->recover_open
nfs41_check_delegation_stateid
test_and_clear_bit // NFS_DELEGATION_TEST_EXPIRED
After the bug in [1] is triggered, although the delegation is no longer on
server->delegations, it can still be obtained by traversing sp->so_states.
However, I cannot find the connection between the number of files on the
server and this issue.
Thanks,
Lingfeng
>
> On 2025/9/2 20:43, Benjamin Coddington wrote:
>> On 2 Sep 2025, at 8:10, Li Lingfeng wrote:
>>
>>> Our expected outcome was that the client would release the abnormal
>>> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
>>> However, this problematic delegation is no longer present in the
>>> client's server->delegations list—whether due to client-side timeouts or
>>> the server-side bug [1].
>> How does the client timeout TEST_STATEID - are you mounting with 'soft'?
>>
>> We should find the server-side bug and fix it rather than write code to
>> paper over it. I do think the synchronization of state here is a bit
>> fragile and wish the protocol had a generation, sequence, or marker for
>> setting SEQ4_STATUS_ bits..
>>
>>>> Should we instead just administratively evict the client since it's
>>>> clearly not behaving right in this case?
>>> Thanks for the suggestion. While administratively evicting the client would
>>> certainly resolve the immediate delegation issue, I'm concerned that approach
>>> might be a bit heavy-handed.
>>> The problematic behavior seems isolated to a single delegation. Meanwhile,
>>> the client itself likely has numerous other open files and active state on
>>> the server. Forcing a complete client reconnect would tear down all that
>>> state, which could cause significant application disruption and be perceived
>>> as a service outage from the client's perspective.
>>>
>>> [1] https://lore.kernel.org/all/de669327-c93a-49e5-a53b-bda9e67d34a2@huawei.com/
>> ^^ in this thread you reference v5.10 - there was a knfsd fix for a
>> cl_revoked leak "3b816601e279", and there have been 3 or 4 fixes to fix
>> problems and optimize the client walk of delegations since then. Jeff
>> pointed out that there have been fixes in these areas. Are you finding this
>> problem still with all those fixes included?
>>
>> Ben
>>
>>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-03 6:45 ` Li Lingfeng
@ 2025-09-03 10:06 ` zhangjian (CG)
2025-09-03 11:40 ` Li Lingfeng
0 siblings, 1 reply; 13+ messages in thread
From: zhangjian (CG) @ 2025-09-03 10:06 UTC (permalink / raw)
To: Li Lingfeng, Benjamin Coddington
Cc: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel, yukuai1, houtao1, yi.zhang, yangerkun
On 2025/9/3 14:45, Li Lingfeng wrote:
> Hi,
>
> 在 2025/9/3 11:46, zhangjian (CG) 写道:
>> Hello every experts.
>>
>> If we can see all delegations on hard-mounted nfs client, which are also
>> on server cl_revoked list, changed from
>> NFS_DELEGATION_RETURN_IF_CLOSED|NFS_DELEGATION_REVOKED|
>> NFS_DELEGATION_TEST_EXPIRED
>> to NFS_DELEGATION_RETURN_IF_CLOSED|NFS_DELEGATION_REVOKED, can we give
>> some hypothesis on this problem ?
>>
>> By the way, this problem can be cover over by decreasing file count on
>> server.
>>
>> Thanks,
>> zhangjian
> I think NFS_DELEGATION_TEST_EXPIRED is cleared as follows:
> nfs4_state_manager
> nfs4_do_reclaim
> nfs4_reclaim_open_state
> __nfs4_reclaim_open_state // get nfs4_state from sp->so_states
> nfs41_open_expired // status = ops->recover_open
> nfs41_check_delegation_stateid
> test_and_clear_bit // NFS_DELEGATION_TEST_EXPIRED
> After the bug in [1] is triggered, although the delegation is no longer on
> server->delegations, it can still be obtained by traversing sp->so_states.
> However, I cannot find the connection between the number of files on the
> server and this issue.
>
> Thanks,
> Lingfeng
>
Thanks a lot.
NFS_DELEGATION_TEST_EXPIRED can only be set when
delegation->stateid.type != NFS4_INVALID_STATEID_TYPE. But when
NFS_DELEGATION_REVOKED is set, delegation->stateid.type will be
NFS4_INVALID_STATEID_TYPE in nfs_mark_delegation_revoked.
This implies the order could be like:
1. Deleg A is in server cl_revoked list
2. Deleg B is marked as NFS_DELEGATION_TEST_EXPIRED in client
3. Deleg B is revoked by server callback procedure and server meet [1].
deleg B is added to cl_revoked list
4. Deleg B is marked as NFS_DELEGATION_REVOKED in client
Why the first deleg A is in server cl_revoked list? Is [1] only
condition? Why this can only happen when file count is large.
I used to see 700 delegations in server but 40w+ delegations in client.
May this give some clue on the problem?
>>
>> On 2025/9/2 20:43, Benjamin Coddington wrote:
>>> On 2 Sep 2025, at 8:10, Li Lingfeng wrote:
>>>
>>>> Our expected outcome was that the client would release the abnormal
>>>> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
>>>> However, this problematic delegation is no longer present in the
>>>> client's server->delegations list—whether due to client-side
>>>> timeouts or
>>>> the server-side bug [1].
>>> How does the client timeout TEST_STATEID - are you mounting with 'soft'?
>>>
>>> We should find the server-side bug and fix it rather than write code to
>>> paper over it. I do think the synchronization of state here is a bit
>>> fragile and wish the protocol had a generation, sequence, or marker for
>>> setting SEQ4_STATUS_ bits..
>>>
>>>>> Should we instead just administratively evict the client since it's
>>>>> clearly not behaving right in this case?
>>>> Thanks for the suggestion. While administratively evicting the
>>>> client would
>>>> certainly resolve the immediate delegation issue, I'm concerned that
>>>> approach
>>>> might be a bit heavy-handed.
>>>> The problematic behavior seems isolated to a single delegation.
>>>> Meanwhile,
>>>> the client itself likely has numerous other open files and active
>>>> state on
>>>> the server. Forcing a complete client reconnect would tear down all
>>>> that
>>>> state, which could cause significant application disruption and be
>>>> perceived
>>>> as a service outage from the client's perspective.
>>>>
>>>> [1] https://lore.kernel.org/all/de669327-c93a-49e5-a53b-
>>>> bda9e67d34a2@huawei.com/
>>> ^^ in this thread you reference v5.10 - there was a knfsd fix for a
>>> cl_revoked leak "3b816601e279", and there have been 3 or 4 fixes to fix
>>> problems and optimize the client walk of delegations since then. Jeff
>>> pointed out that there have been fixes in these areas. Are you
>>> finding this
>>> problem still with all those fixes included?
>>>
>>> Ben
>>>
>>>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] nfsd: remove long-standing revoked delegations by force
2025-09-03 10:06 ` zhangjian (CG)
@ 2025-09-03 11:40 ` Li Lingfeng
0 siblings, 0 replies; 13+ messages in thread
From: Li Lingfeng @ 2025-09-03 11:40 UTC (permalink / raw)
To: zhangjian (CG), Li Lingfeng, Benjamin Coddington
Cc: Jeff Layton, chuck.lever, neil, okorniev, Dai.Ngo, tom, linux-nfs,
linux-kernel, yukuai1, houtao1, yi.zhang, yangerkun
Hi,
在 2025/9/3 18:06, zhangjian (CG) 写道:
>
> On 2025/9/3 14:45, Li Lingfeng wrote:
>> Hi,
>>
>> 在 2025/9/3 11:46, zhangjian (CG) 写道:
>>> Hello every experts.
>>>
>>> If we can see all delegations on hard-mounted nfs client, which are also
>>> on server cl_revoked list, changed from
>>> NFS_DELEGATION_RETURN_IF_CLOSED|NFS_DELEGATION_REVOKED|
>>> NFS_DELEGATION_TEST_EXPIRED
>>> to NFS_DELEGATION_RETURN_IF_CLOSED|NFS_DELEGATION_REVOKED, can we give
>>> some hypothesis on this problem ?
>>>
>>> By the way, this problem can be cover over by decreasing file count on
>>> server.
>>>
>>> Thanks,
>>> zhangjian
>> I think NFS_DELEGATION_TEST_EXPIRED is cleared as follows:
>> nfs4_state_manager
>> nfs4_do_reclaim
>> nfs4_reclaim_open_state
>> __nfs4_reclaim_open_state // get nfs4_state from sp->so_states
>> nfs41_open_expired // status = ops->recover_open
>> nfs41_check_delegation_stateid
>> test_and_clear_bit // NFS_DELEGATION_TEST_EXPIRED
>> After the bug in [1] is triggered, although the delegation is no longer on
>> server->delegations, it can still be obtained by traversing sp->so_states.
>> However, I cannot find the connection between the number of files on the
>> server and this issue.
>>
>> Thanks,
>> Lingfeng
>>
> Thanks a lot.
>
> NFS_DELEGATION_TEST_EXPIRED can only be set when
> delegation->stateid.type != NFS4_INVALID_STATEID_TYPE. But when
> NFS_DELEGATION_REVOKED is set, delegation->stateid.type will be
> NFS4_INVALID_STATEID_TYPE in nfs_mark_delegation_revoked.
> This implies the order could be like:
> 1. Deleg A is in server cl_revoked list
> 2. Deleg B is marked as NFS_DELEGATION_TEST_EXPIRED in client
> 3. Deleg B is revoked by server callback procedure and server meet [1].
> deleg B is added to cl_revoked list
> 4. Deleg B is marked as NFS_DELEGATION_REVOKED in client
I think Deleg A was added to the server's cl_revoked list due to [1]. For
the file corresponding to Deleg B, no access conflict occurred, which
means no deleg return was triggered. Therefore, unlike Deleg A, it would
not go through the process of nfs4_delegreturn_done -->
nfs_delegation_mark_returned --> nfs_mark_delegation_revoked to be set
with NFS4_INVALID_STATEID_TYPE, and thus could be flagged with
NFS_DELEGATION_TEST_EXPIRED.
> Why the first deleg A is in server cl_revoked list? Is [1] only
> condition? Why this can only happen when file count is large.
> I used to see 700 delegations in server but 40w+ delegations in client.
> May this give some clue on the problem?
I'm afraid I cannot explain why there is such a significant discrepancy in
the number of delegations between the client and the server. I truly don't
know what is happening.
Thanks,
Lingfeng
>>> On 2025/9/2 20:43, Benjamin Coddington wrote:
>>>> On 2 Sep 2025, at 8:10, Li Lingfeng wrote:
>>>>
>>>>> Our expected outcome was that the client would release the abnormal
>>>>> delegation via TEST_STATEID/FREE_STATEID upon detecting its invalidity.
>>>>> However, this problematic delegation is no longer present in the
>>>>> client's server->delegations list—whether due to client-side
>>>>> timeouts or
>>>>> the server-side bug [1].
>>>> How does the client timeout TEST_STATEID - are you mounting with 'soft'?
>>>>
>>>> We should find the server-side bug and fix it rather than write code to
>>>> paper over it. I do think the synchronization of state here is a bit
>>>> fragile and wish the protocol had a generation, sequence, or marker for
>>>> setting SEQ4_STATUS_ bits..
>>>>
>>>>>> Should we instead just administratively evict the client since it's
>>>>>> clearly not behaving right in this case?
>>>>> Thanks for the suggestion. While administratively evicting the
>>>>> client would
>>>>> certainly resolve the immediate delegation issue, I'm concerned that
>>>>> approach
>>>>> might be a bit heavy-handed.
>>>>> The problematic behavior seems isolated to a single delegation.
>>>>> Meanwhile,
>>>>> the client itself likely has numerous other open files and active
>>>>> state on
>>>>> the server. Forcing a complete client reconnect would tear down all
>>>>> that
>>>>> state, which could cause significant application disruption and be
>>>>> perceived
>>>>> as a service outage from the client's perspective.
>>>>>
>>>>> [1] https://lore.kernel.org/all/de669327-c93a-49e5-a53b-
>>>>> bda9e67d34a2@huawei.com/
>>>> ^^ in this thread you reference v5.10 - there was a knfsd fix for a
>>>> cl_revoked leak "3b816601e279", and there have been 3 or 4 fixes to fix
>>>> problems and optimize the client walk of delegations since then. Jeff
>>>> pointed out that there have been fixes in these areas. Are you
>>>> finding this
>>>> problem still with all those fixes included?
>>>>
>>>> Ben
>>>>
>>>>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-09-03 11:40 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-02 2:22 [PATCH] nfsd: remove long-standing revoked delegations by force Li Lingfeng
2025-09-02 10:21 ` Jeff Layton
2025-09-02 12:10 ` Li Lingfeng
2025-09-02 12:43 ` Benjamin Coddington
2025-09-02 13:08 ` Li Lingfeng
2025-09-03 3:46 ` zhangjian (CG)
2025-09-03 6:45 ` Li Lingfeng
2025-09-03 10:06 ` zhangjian (CG)
2025-09-03 11:40 ` Li Lingfeng
2025-09-02 13:40 ` Jeff Layton
2025-09-02 14:21 ` Li Lingfeng
2025-09-02 14:29 ` Jeff Layton
2025-09-03 1:34 ` Li Lingfeng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).