Skip to content

Commit

Permalink
NFSv4: Deal with atomic upgrades of an existing delegation
Browse files Browse the repository at this point in the history
Ensure that we deal correctly with the case where the server sends us a
newer instance of the same delegation. If the stateids match, but the
sequence numbers differ, then treat the new delegation as if it were
an atomic upgrade.

Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
  • Loading branch information
Trond Myklebust committed Jan 24, 2015
1 parent 89f0ff3 commit cf6726e
Showing 1 changed file with 17 additions and 3 deletions.
20 changes: 17 additions & 3 deletions fs/nfs/delegation.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,17 @@ nfs_inode_detach_delegation(struct inode *inode)
return nfs_detach_delegation(nfsi, delegation, server);
}

static void
nfs_update_inplace_delegation(struct nfs_delegation *delegation,
const struct nfs_delegation *update)
{
if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
delegation->stateid.seqid = update->stateid.seqid;
smp_wmb();
delegation->type = update->type;
}
}

/**
* nfs_inode_set_delegation - set up a delegation on an inode
* @inode: inode to which delegation applies
Expand Down Expand Up @@ -334,9 +345,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
old_delegation = rcu_dereference_protected(nfsi->delegation,
lockdep_is_held(&clp->cl_lock));
if (old_delegation != NULL) {
if (nfs4_stateid_match(&delegation->stateid,
&old_delegation->stateid) &&
delegation->type == old_delegation->type) {
/* Is this an update of the existing delegation? */
if (nfs4_stateid_match_other(&old_delegation->stateid,
&delegation->stateid)) {
nfs_update_inplace_delegation(old_delegation,
delegation);
nfsi->delegation_state = old_delegation->type;
goto out;
}
/*
Expand Down

0 comments on commit cf6726e

Please sign in to comment.