FAILED: patch "[PATCH] NFSv4: Ensure the delegation is pinned in" failed to apply to 5.5-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.5-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 8c75593c6eee0f661ddf25dfde0e6ad2a84be7a9 Mon Sep 17 00:00:00 2001
From: Trond Myklebust <[email protected]>
Date: Thu, 13 Feb 2020 14:51:06 -0500
Subject: [PATCH] NFSv4: Ensure the delegation is pinned in
nfs_do_return_delegation()
The call to nfs_do_return_delegation() needs to be taken without any RCU locks. Add a refcount to make sure the delegation remains pinned in memory until we're done.
Fixes ee05f456772d ("NFSv4: Fix races between open and delegreturn")
Signed-off-by Trond Myklebust <[email protected]>
Signed-off-by Anna Schumaker <[email protected]>
fs/nfs/delegation.c +26 -7
@@ -47,10 +47,22 @@ static void nfs_mark_delegation_revoked(struct nfs_delegation *delegation) } } +static struct nfs_delegation *nfs_get_delegation (struct nfs_delegation *delegation) +{ +refcount_inc (&delegation->refcount); +return delegation; +} + +static void nfs_put_delegation (struct nfs_delegation *delegation) +{ +if (refcount_dec_and_test (&delegation->refcount)) +__nfs_free_delegation (delegation); +} +static void nfs_free_delegation (struct nfs_delegation *delegation) {nfs_mark_delegation_revoked (delegation); -__nfs_free_delegation (delegation); +nfs_put_delegation (delegation); }/**
@@ -275,8 +287,10 @@ nfs_start_delegation_return_locked(struct nfs_inode *nfsi)if (delegation ==NULL ) goto out;spin_lock (&delegation->lock); -if (!test_and_set_bit (NFS_DELEGATION_RETURNING , &delegation->flags)) - ret = delegation; +if (!test_and_set_bit (NFS_DELEGATION_RETURNING , &delegation->flags)) { +/* Refcount matched in nfs_end_delegation_return() */ + ret =nfs_get_delegation (delegation); + }spin_unlock (&delegation->lock);if (ret)nfs_clear_verifier_delegated (&nfsi->vfs_inode);
@@ -397,6 +411,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,if (delegation ==NULL )return -ENOMEM ;nfs4_stateid_copy (&delegation->stateid, stateid); +refcount_set (&delegation->refcount,1 ); delegation->type = type; delegation->pagemod_limit = pagemod_limit; delegation->change_attr =inode_peek_iversion_raw (inode);
@@ -496,6 +511,8 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation err =nfs_do_return_delegation (inode, delegation, issync); out: +/* Refcount matched in nfs_start_delegation_return_locked() */ +nfs_put_delegation (delegation);return err; }
@@ -690,7 +707,8 @@ void nfs4_inode_return_delegation_on_close(struct inode *inode) list_empty(&NFS_I(inode)->open_files) && !test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {clear_bit (NFS_DELEGATION_RETURN_IF_CLOSED , &delegation->flags); - ret = delegation; +/* Refcount matched in nfs_end_delegation_return() */ + ret =nfs_get_delegation (delegation); }spin_unlock (&delegation->lock);if (ret)
@@ -1094,10 +1112,11 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp) delegation =nfs_start_delegation_return_locked (NFS_I (inode));rcu_read_unlock ();if (delegation !=NULL ) { - delegation =nfs_detach_delegation (NFS_I (inode), - delegation, server); -if (delegation !=NULL ) +if (nfs_detach_delegation (NFS_I (inode), delegation, + server) !=NULL )nfs_free_delegation (delegation); +/* Match nfs_start_delegation_return_locked */ +nfs_put_delegation (delegation); }iput (inode);nfs_sb_deactive (server->super);
fs/nfs/delegation.h +1 -0
@@ -22,6 +22,7 @@ struct nfs_delegation {unsigned long pagemod_limit;__u64 change_attr;unsigned long flags; +refcount_t refcount;spinlock_t lock;struct rcu_head rcu; };