Skip to content

Commit 327e2e3

Browse files
committed
NFSv4: Allow FREE_STATEID to clean up delegations
jira LE-4649 Rebuild_History Non-Buildable kernel-5.14.0-570.60.1.el9_6 commit-author Benjamin Coddington <bcodding@redhat.com> commit 77be29b The NFS client's list of delegations can grow quite large (well beyond the delegation watermark) if the server is revoking or there are repeated events that expire state. Once this happens, the revoked delegations can cause a performance problem for subsequent walks of the servers->delegations list when the client tries to test and free state. If we can determine that the FREE_STATEID operation has completed without error, we can prune the delegation from the list. Since the NFS client combines TEST_STATEID with FREE_STATEID in its minor version operations, there isn't an easy way to communicate success of FREE_STATEID. Rather than re-arrange quite a number of calling paths to break out the separate procedures, let's signal the success of FREE_STATEID by setting the stateid's type. Set NFS4_FREED_STATEID_TYPE for stateids that have been successfully discarded from the server, and use that type to signal that the delegation can be cleaned up. Signed-off-by: Benjamin Coddington <bcodding@redhat.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com> (cherry picked from commit 77be29b) Signed-off-by: Jonathan Maple <jmaple@ciq.com>
1 parent 4040ff4 commit 327e2e3

File tree

4 files changed

+26
-15
lines changed

4 files changed

+26
-15
lines changed

fs/nfs/delegation.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -969,13 +969,6 @@ static void nfs_revoke_delegation(struct inode *inode,
969969
nfs_inode_find_state_and_recover(inode, stateid);
970970
}
971971

972-
void nfs_remove_bad_delegation(struct inode *inode,
973-
const nfs4_stateid *stateid)
974-
{
975-
nfs_revoke_delegation(inode, stateid);
976-
}
977-
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
978-
979972
void nfs_delegation_mark_returned(struct inode *inode,
980973
const nfs4_stateid *stateid)
981974
{
@@ -1012,6 +1005,24 @@ void nfs_delegation_mark_returned(struct inode *inode,
10121005
nfs_inode_find_state_and_recover(inode, stateid);
10131006
}
10141007

1008+
/**
1009+
* nfs_remove_bad_delegation - handle delegations that are unusable
1010+
* @inode: inode to process
1011+
* @stateid: the delegation's stateid
1012+
*
1013+
* If the server ACK-ed our FREE_STATEID then clean
1014+
* up the delegation, else mark and keep the revoked state.
1015+
*/
1016+
void nfs_remove_bad_delegation(struct inode *inode,
1017+
const nfs4_stateid *stateid)
1018+
{
1019+
if (stateid && stateid->type == NFS4_FREED_STATEID_TYPE)
1020+
nfs_delegation_mark_returned(inode, stateid);
1021+
else
1022+
nfs_revoke_delegation(inode, stateid);
1023+
}
1024+
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
1025+
10151026
/**
10161027
* nfs_expire_unused_delegation_types
10171028
* @clp: client to process

fs/nfs/nfs4_fs.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ struct nfs4_minor_version_ops {
6666
void (*free_lock_state)(struct nfs_server *,
6767
struct nfs4_lock_state *);
6868
int (*test_and_free_expired)(struct nfs_server *,
69-
const nfs4_stateid *,
70-
const struct cred *);
69+
nfs4_stateid *, const struct cred *);
7170
struct nfs_seqid *
7271
(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
7372
void (*session_trunk)(struct rpc_clnt *clnt,

fs/nfs/nfs4proc.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
105105
bool is_privileged);
106106
static int nfs41_test_stateid(struct nfs_server *, const nfs4_stateid *,
107107
const struct cred *);
108-
static int nfs41_free_stateid(struct nfs_server *, const nfs4_stateid *,
108+
static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *,
109109
const struct cred *, bool);
110110
#endif
111111

@@ -2883,16 +2883,14 @@ static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
28832883
}
28842884

28852885
static int nfs40_test_and_free_expired_stateid(struct nfs_server *server,
2886-
const nfs4_stateid *stateid,
2887-
const struct cred *cred)
2886+
nfs4_stateid *stateid, const struct cred *cred)
28882887
{
28892888
return -NFS4ERR_BAD_STATEID;
28902889
}
28912890

28922891
#if defined(CONFIG_NFS_V4_1)
28932892
static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
2894-
const nfs4_stateid *stateid,
2895-
const struct cred *cred)
2893+
nfs4_stateid *stateid, const struct cred *cred)
28962894
{
28972895
int status;
28982896

@@ -2901,6 +2899,7 @@ static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
29012899
break;
29022900
case NFS4_INVALID_STATEID_TYPE:
29032901
case NFS4_SPECIAL_STATEID_TYPE:
2902+
case NFS4_FREED_STATEID_TYPE:
29042903
return -NFS4ERR_BAD_STATEID;
29052904
case NFS4_REVOKED_STATEID_TYPE:
29062905
goto out_free;
@@ -10568,7 +10567,7 @@ static const struct rpc_call_ops nfs41_free_stateid_ops = {
1056810567
* Note: this function is always asynchronous.
1056910568
*/
1057010569
static int nfs41_free_stateid(struct nfs_server *server,
10571-
const nfs4_stateid *stateid,
10570+
nfs4_stateid *stateid,
1057210571
const struct cred *cred,
1057310572
bool privileged)
1057410573
{
@@ -10608,6 +10607,7 @@ static int nfs41_free_stateid(struct nfs_server *server,
1060810607
if (IS_ERR(task))
1060910608
return PTR_ERR(task);
1061010609
rpc_put_task(task);
10610+
stateid->type = NFS4_FREED_STATEID_TYPE;
1061110611
return 0;
1061210612
}
1061310613

include/linux/nfs4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ struct nfs4_stateid_struct {
7070
NFS4_LAYOUT_STATEID_TYPE,
7171
NFS4_PNFS_DS_STATEID_TYPE,
7272
NFS4_REVOKED_STATEID_TYPE,
73+
NFS4_FREED_STATEID_TYPE,
7374
} type;
7475
};
7576

0 commit comments

Comments
 (0)