Skip to content

Commit 77be29b

Browse files
bcodding-rhAnna Schumaker
authored andcommitted
NFSv4: Allow FREE_STATEID to clean up delegations
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 <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent 4d4832e commit 77be29b

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
@@ -1021,13 +1021,6 @@ static void nfs_revoke_delegation(struct inode *inode,
10211021
nfs_inode_find_state_and_recover(inode, stateid);
10221022
}
10231023

1024-
void nfs_remove_bad_delegation(struct inode *inode,
1025-
const nfs4_stateid *stateid)
1026-
{
1027-
nfs_revoke_delegation(inode, stateid);
1028-
}
1029-
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
1030-
10311024
void nfs_delegation_mark_returned(struct inode *inode,
10321025
const nfs4_stateid *stateid)
10331026
{
@@ -1069,6 +1062,24 @@ void nfs_delegation_mark_returned(struct inode *inode,
10691062
nfs_inode_find_state_and_recover(inode, stateid);
10701063
}
10711064

1065+
/**
1066+
* nfs_remove_bad_delegation - handle delegations that are unusable
1067+
* @inode: inode to process
1068+
* @stateid: the delegation's stateid
1069+
*
1070+
* If the server ACK-ed our FREE_STATEID then clean
1071+
* up the delegation, else mark and keep the revoked state.
1072+
*/
1073+
void nfs_remove_bad_delegation(struct inode *inode,
1074+
const nfs4_stateid *stateid)
1075+
{
1076+
if (stateid && stateid->type == NFS4_FREED_STATEID_TYPE)
1077+
nfs_delegation_mark_returned(inode, stateid);
1078+
else
1079+
nfs_revoke_delegation(inode, stateid);
1080+
}
1081+
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
1082+
10721083
/**
10731084
* nfs_expire_unused_delegation_types
10741085
* @clp: client to process

fs/nfs/nfs4_fs.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ struct nfs4_minor_version_ops {
6767
void (*free_lock_state)(struct nfs_server *,
6868
struct nfs4_lock_state *);
6969
int (*test_and_free_expired)(struct nfs_server *,
70-
const nfs4_stateid *,
71-
const struct cred *);
70+
nfs4_stateid *, const struct cred *);
7271
struct nfs_seqid *
7372
(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
7473
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

@@ -2903,16 +2903,14 @@ static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
29032903
}
29042904

29052905
static int nfs40_test_and_free_expired_stateid(struct nfs_server *server,
2906-
const nfs4_stateid *stateid,
2907-
const struct cred *cred)
2906+
nfs4_stateid *stateid, const struct cred *cred)
29082907
{
29092908
return -NFS4ERR_BAD_STATEID;
29102909
}
29112910

29122911
#if defined(CONFIG_NFS_V4_1)
29132912
static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
2914-
const nfs4_stateid *stateid,
2915-
const struct cred *cred)
2913+
nfs4_stateid *stateid, const struct cred *cred)
29162914
{
29172915
int status;
29182916

@@ -2921,6 +2919,7 @@ static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
29212919
break;
29222920
case NFS4_INVALID_STATEID_TYPE:
29232921
case NFS4_SPECIAL_STATEID_TYPE:
2922+
case NFS4_FREED_STATEID_TYPE:
29242923
return -NFS4ERR_BAD_STATEID;
29252924
case NFS4_REVOKED_STATEID_TYPE:
29262925
goto out_free;
@@ -10617,7 +10616,7 @@ static const struct rpc_call_ops nfs41_free_stateid_ops = {
1061710616
* Note: this function is always asynchronous.
1061810617
*/
1061910618
static int nfs41_free_stateid(struct nfs_server *server,
10620-
const nfs4_stateid *stateid,
10619+
nfs4_stateid *stateid,
1062110620
const struct cred *cred,
1062210621
bool privileged)
1062310622
{
@@ -10657,6 +10656,7 @@ static int nfs41_free_stateid(struct nfs_server *server,
1065710656
if (IS_ERR(task))
1065810657
return PTR_ERR(task);
1065910658
rpc_put_task(task);
10659+
stateid->type = NFS4_FREED_STATEID_TYPE;
1066010660
return 0;
1066110661
}
1066210662

include/linux/nfs4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct nfs4_stateid_struct {
7272
NFS4_LAYOUT_STATEID_TYPE,
7373
NFS4_PNFS_DS_STATEID_TYPE,
7474
NFS4_REVOKED_STATEID_TYPE,
75+
NFS4_FREED_STATEID_TYPE,
7576
} type;
7677
};
7778

0 commit comments

Comments
 (0)