[PATCH 3/3] NFSD: Annotate caller preconditions for the state-table walkers
Chuck Lever <[email protected]>
| Newsgroups | gmane.linux.nfs |
|---|---|
| Message-ID | <[email protected]> |
The state-table walkers now assert nfsd_mutex with lockdep_assert_held() and document the nfsd_mutex / nn->nfsd_serv precondition in a Context: kdoc section, so the next caller added to this path cannot silently reintroduce the same use-after-free. Signed-off-by: Chuck Lever <[email protected]> --- fs/nfsd/nfs4proc.c | 6 ++++++ fs/nfsd/nfs4state.c | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index eb8a2a16839f..3e4de45aa360 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1587,6 +1587,11 @@ static bool nfsd4_copy_on_sb(const struct nfsd4_copy *copy, * nfsd4_cancel_copy_by_sb - cancel async copy operations on @sb * @net: net namespace containing the copy operations * @sb: targeted superblock + * + * Context: Caller must hold nfsd_mutex with nn->nfsd_serv confirmed + * non-NULL. nfs4_state_destroy_net() frees conf_id_hashtbl + * at server shutdown without clearing the pointer, so a + * walk without these guarantees iterates freed slab memory. */ void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb) { @@ -1596,6 +1601,7 @@ void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb) unsigned int idhashval; LIST_HEAD(to_cancel); + lockdep_assert_held(&nfsd_mutex); spin_lock(&nn->client_lock); for (idhashval = 0; idhashval < CLIENT_HASH_SIZE; idhashval++) { struct list_head *head = &nn->conf_id_hashtbl[idhashval]; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index bef0ec9be459..2a6a0c9ef65f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1873,14 +1873,21 @@ static void revoke_one_stid(struct nfsd_net *nn, struct nfs4_client *clp, * being released. Thus nfsd will no longer prevent the filesystem from being * unmounted. * - * The clients which own the states will subsequently being notified that the + * The clients which own the states will subsequently be notified that the * states have been "admin-revoked". + * + * Context: Caller must hold nfsd_mutex with nn->nfsd_serv confirmed + * non-NULL. nfs4_state_destroy_net() frees conf_id_hashtbl + * at server shutdown without clearing the pointer, so a + * walk without these guarantees iterates freed slab memory. */ void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) { unsigned int idhashval; unsigned int sc_types; + lockdep_assert_held(&nfsd_mutex); + sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK | SC_TYPE_DELEG | SC_TYPE_LAYOUT; spin_lock(&nn->client_lock); @@ -1946,12 +1953,19 @@ static struct nfs4_stid *find_one_export_stid(struct nfs4_client *clp, * * Userspace (exportfs -u) sends this after removing the last client * for a path, enabling the underlying filesystem to be unmounted. + * + * Context: Caller must hold nfsd_mutex with nn->nfsd_serv confirmed + * non-NULL. nfs4_state_destroy_net() frees conf_id_hashtbl + * at server shutdown without clearing the pointer, so a + * walk without these guarantees iterates freed slab memory. */ void nfsd4_revoke_export_states(struct nfsd_net *nn, const struct path *path) { unsigned int idhashval; unsigned int sc_types; + lockdep_assert_held(&nfsd_mutex); + sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK | SC_TYPE_DELEG | SC_TYPE_LAYOUT; spin_lock(&nn->client_lock); -- 2.54.0