From: Chuck Lever <chuck.lever@oracle.com>
To: Jeff Layton <jlayton@kernel.org>,
Li Lingfeng <lilingfeng3@huawei.com>,
neil@brown.name, okorniev@redhat.com, Dai.Ngo@oracle.com,
tom@talpey.com, linux-nfs@vger.kernel.org,
linux-kernel@vger.kernel.org
Cc: yukuai1@huaweicloud.com, houtao1@huawei.com, yi.zhang@huawei.com,
yangerkun@huawei.com, lilingfeng@huaweicloud.com,
zhangjian496@huawei.com, bcodding@redhat.com
Subject: Re: [PATCH v2] nfsd: remove long-standing revoked delegations by force
Date: Thu, 4 Sep 2025 10:08:51 -0400 [thread overview]
Message-ID: <ce18bf9b-889c-4746-902c-4f9077b22a32@oracle.com> (raw)
In-Reply-To: <837da22b428e5a7cbda1f56868cbfe23e89dccf7.camel@kernel.org>
On 9/3/25 8:15 AM, Jeff Layton wrote:
> On Wed, 2025-09-03 at 19:59 +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 like this:
>> nfs4_laundromat nfsd4_delegreturn
>> unhash_delegation_locked
>> list_add // add dp to reaplist
>> // by dl_recall_lru
>> list_del_init // delete dp from
>> // reaplist
>> destroy_delegation
>> unhash_delegation_locked
>> // do nothing but return false
>> revoke_delegation
>> list_add // add dp to cl_revoked
>> // by dl_recall_lru
>>
>> The delegation will remain in the server's cl_revoked list while 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>
>> ---
>> Changes in v2:
>> 1) Set SC_STATUS_CLOSED unconditionally in destroy_delegation();
>> 2) Determine whether to remove the delegation based on SC_STATUS_CLOSED,
>> rather than by timeout;
>> 3) Modify the commit message.
>> fs/nfsd/nfs4state.c | 20 ++++++++++++++++++++
>> 1 file changed, 20 insertions(+)
>>
>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> index 88c347957da5..bb9e1df4e41f 100644
>> --- a/fs/nfsd/nfs4state.c
>> +++ b/fs/nfsd/nfs4state.c
>> @@ -1336,6 +1336,11 @@ static void destroy_delegation(struct nfs4_delegation *dp)
>>
>> spin_lock(&state_lock);
>> unhashed = unhash_delegation_locked(dp, SC_STATUS_CLOSED);
>> + /*
>> + * Unconditionally set SC_STATUS_CLOSED, regardless of whether the
>> + * delegation is hashed, to mark the current delegation as invalid.
>> + */
>> + dp->dl_stid.sc_status |= SC_STATUS_CLOSED;
>> spin_unlock(&state_lock);
>> if (unhashed)
>> destroy_unhashed_deleg(dp);
>> @@ -4326,6 +4331,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;
>>
>
> nit: These could be moved inside the if statement below.
>
>> if (resp->opcnt != 1)
>> return nfserr_sequence_pos;
>> @@ -4470,6 +4477,19 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>> default:
>> seq->status_flags = 0;
>> }
>
> I wouldn't mind a comment here that explains why we have to do this.
> This is the sort of thing that will have us all scratching our heads in
> a few years.
>
>> + if (!list_empty(&clp->cl_revoked)) {
>> + spin_lock(&clp->cl_lock);
>> + list_for_each_safe(pos, next, &clp->cl_revoked) {
>> + dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
>> + if (dp->dl_stid.sc_status & SC_STATUS_CLOSED) {
>> + list_del_init(&dp->dl_recall_lru);
>> + spin_unlock(&clp->cl_lock);
>> + nfs4_put_stid(&dp->dl_stid);
>> + spin_lock(&clp->cl_lock);
>> + }
>> + }
>> + spin_unlock(&clp->cl_lock);
>> + }
>
> nit: I'd move the if statement below inside the above if statement. No
> need to check list_empty() twice if it was empty the first time. Maybe
> the compiler papers over this and only does it once?
>
>> if (!list_empty(&clp->cl_revoked))
>> seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
>> if (atomic_read(&clp->cl_admin_revoked))
>
> Otherwise, this looks great. Thanks for the patch!
>
> Reviewed-by: Jeff Layton <jlayton@kernel.org>
Li, I'm assuming you are going to address Jeff's additional comments
here and send another revision of this patch. So I'm waiting for
another version... let me know if you plan not to send one.
--
Chuck Lever
next prev parent reply other threads:[~2025-09-04 14:09 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-03 11:59 [PATCH v2] nfsd: remove long-standing revoked delegations by force Li Lingfeng
2025-09-03 12:15 ` Jeff Layton
2025-09-04 14:08 ` Chuck Lever [this message]
2025-09-05 0:59 ` Li Lingfeng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ce18bf9b-889c-4746-902c-4f9077b22a32@oracle.com \
--to=chuck.lever@oracle.com \
--cc=Dai.Ngo@oracle.com \
--cc=bcodding@redhat.com \
--cc=houtao1@huawei.com \
--cc=jlayton@kernel.org \
--cc=lilingfeng3@huawei.com \
--cc=lilingfeng@huaweicloud.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
--cc=yangerkun@huawei.com \
--cc=yi.zhang@huawei.com \
--cc=yukuai1@huaweicloud.com \
--cc=zhangjian496@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox