diff options
-rw-r--r-- | fs/nfs/delegation.c | 36 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 1 |
3 files changed, 38 insertions, 0 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index aff2416dc277..8c176c921554 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -806,6 +806,42 @@ void nfs_remove_bad_delegation(struct inode *inode, } EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation); +void nfs_delegation_mark_returned(struct inode *inode, + const nfs4_stateid *stateid) +{ + struct nfs_delegation *delegation; + + if (!inode) + return; + + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(inode)->delegation); + if (!delegation) + goto out_rcu_unlock; + + spin_lock(&delegation->lock); + if (!nfs4_stateid_match_other(stateid, &delegation->stateid)) + goto out_spin_unlock; + if (stateid->seqid) { + /* If delegation->stateid is newer, dont mark as returned */ + if (nfs4_stateid_is_newer(&delegation->stateid, stateid)) + goto out_clear_returning; + if (delegation->stateid.seqid != stateid->seqid) + delegation->stateid.seqid = stateid->seqid; + } + + set_bit(NFS_DELEGATION_REVOKED, &delegation->flags); + +out_clear_returning: + clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags); +out_spin_unlock: + spin_unlock(&delegation->lock); +out_rcu_unlock: + rcu_read_unlock(); + + nfs_inode_find_state_and_recover(inode, stateid); +} + /** * nfs_expire_unused_delegation_types * @clp: client to process diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 74b7fb601365..15d3484be028 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -53,6 +53,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp); int nfs_client_return_marked_delegations(struct nfs_client *clp); int nfs_delegations_present(struct nfs_client *clp); void nfs_remove_bad_delegation(struct inode *inode, const nfs4_stateid *stateid); +void nfs_delegation_mark_returned(struct inode *inode, const nfs4_stateid *stateid); void nfs_delegation_mark_reclaim(struct nfs_client *clp); void nfs_delegation_reap_unclaimed(struct nfs_client *clp); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 217885e32852..a222122e7151 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6214,6 +6214,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) if (exception.retry) goto out_restart; } + nfs_delegation_mark_returned(data->inode, data->args.stateid); data->rpc_status = task->tk_status; return; out_restart: |