Add a routine to return the delegation immediately upon close of the file if it was marked for return-on-close. Signed-off-by: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx> --- fs/nfs/delegation.c | 33 +++++++++++++++++++++++++++++++++ fs/nfs/delegation.h | 1 + fs/nfs/nfs4state.c | 1 + 3 files changed, 35 insertions(+) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index b5b14618b73e..90e50f32f3e0 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -639,6 +639,39 @@ int nfs4_inode_return_delegation(struct inode *inode) return err; } +/** + * nfs_inode_return_delegation_on_close - asynchronously return a delegation + * @inode: inode to process + * + * This routine is called on file close in order to determine if the + * inode delegation needs to be returned immediately. + */ +void nfs4_inode_return_delegation_on_close(struct inode *inode) +{ + struct nfs_delegation *delegation; + struct nfs_delegation *ret = NULL; + + if (!inode) + return; + rcu_read_lock(); + delegation = nfs4_get_valid_delegation(inode); + if (!delegation) + goto out; + if (test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags)) { + spin_lock(&delegation->lock); + if (delegation->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; + } + spin_unlock(&delegation->lock); + } +out: + rcu_read_unlock(); + nfs_end_delegation_return(inode, ret, 0); +} + /** * nfs4_inode_make_writeable * @inode: pointer to inode diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 15d3484be028..31b84604d383 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -42,6 +42,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, 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); +void nfs4_inode_return_delegation_on_close(struct inode *inode); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); void nfs_inode_evict_delegation(struct inode *inode); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 34552329233d..958ed4e4cde2 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -766,6 +766,7 @@ void nfs4_put_open_state(struct nfs4_state *state) list_del(&state->open_states); spin_unlock(&inode->i_lock); spin_unlock(&owner->so_lock); + nfs4_inode_return_delegation_on_close(inode); iput(inode); nfs4_free_open_state(state); nfs4_put_state_owner(owner); -- 2.24.1