If the delegation was revoked, we don't want to retry the delegreturn.
Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/delegation.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index c34bb81d37e2..630167e243be 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -1190,7 +1190,8 @@ bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
if (delegation != NULL &&
- nfs4_stateid_match_other(dst, &delegation->stateid)) {
+ nfs4_stateid_match_other(dst, &delegation->stateid) &&
+ !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
dst->seqid = delegation->stateid.seqid;
ret = true;
}
--
2.23.0
Rename nfs_inode_return_delegation_noreclaim() to
nfs_inode_evict_delegation(), which better describes what it
does.
Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/delegation.c | 11 +++++++----
fs/nfs/delegation.h | 2 +-
fs/nfs/nfs4super.c | 4 ++--
3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 630167e243be..0c9339d559f5 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -585,19 +585,22 @@ int nfs_client_return_marked_delegations(struct nfs_client *clp)
}
/**
- * nfs_inode_return_delegation_noreclaim - return delegation, don't reclaim opens
+ * nfs_inode_evict_delegation - return delegation, don't reclaim opens
* @inode: inode to process
*
* Does not protect against delegation reclaims, therefore really only safe
- * to be called from nfs4_clear_inode().
+ * to be called from nfs4_clear_inode(). Guaranteed to always free
+ * the delegation structure.
*/
-void nfs_inode_return_delegation_noreclaim(struct inode *inode)
+void nfs_inode_evict_delegation(struct inode *inode)
{
struct nfs_delegation *delegation;
delegation = nfs_inode_detach_delegation(inode);
- if (delegation != NULL)
+ if (delegation != NULL) {
+ set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags);
nfs_do_return_delegation(inode, delegation, 1);
+ }
}
/**
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 8b14d441e699..74b7fb601365 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -43,7 +43,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
fmode_t type, const nfs4_stateid *stateid, unsigned long pagemod_limit);
int nfs4_inode_return_delegation(struct inode *inode);
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
-void nfs_inode_return_delegation_noreclaim(struct inode *inode);
+void nfs_inode_evict_delegation(struct inode *inode);
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
void nfs_server_return_all_delegations(struct nfs_server *);
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 04c57066a11a..2c9cbade561a 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -92,8 +92,8 @@ static void nfs4_evict_inode(struct inode *inode)
{
truncate_inode_pages_final(&inode->i_data);
clear_inode(inode);
- /* If we are holding a delegation, return it! */
- nfs_inode_return_delegation_noreclaim(inode);
+ /* If we are holding a delegation, return and free it */
+ nfs_inode_evict_delegation(inode);
/* Note that above delegreturn would trigger pnfs return-on-close */
pnfs_return_layout(inode);
pnfs_destroy_layout(NFS_I(inode));
--
2.23.0
Add a check to ensure that we haven't already removed the delegation
from the inode after we take all the relevant locks.
Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/delegation.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 0c9339d559f5..e80419a63fb5 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -298,6 +298,10 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
return NULL;
spin_lock(&delegation->lock);
+ if (!delegation->inode) {
+ spin_unlock(&delegation->lock);
+ return NULL;
+ }
set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
list_del_rcu(&delegation->super_list);
delegation->inode = NULL;
--
2.23.0
Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/delegation.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index e80419a63fb5..7ebeb57cb597 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -387,8 +387,10 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
/* Is this an update of the existing delegation? */
if (nfs4_stateid_match_other(&old_delegation->stateid,
&delegation->stateid)) {
+ spin_lock(&old_delegation->lock);
nfs_update_inplace_delegation(old_delegation,
delegation);
+ spin_unlock(&old_delegation->lock);
goto out;
}
/*
--
2.23.0