Skip to content

Commit cf6726e

Browse files
committed
NFSv4: Deal with atomic upgrades of an existing delegation
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 <[email protected]>
1 parent 89f0ff3 commit cf6726e

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

fs/nfs/delegation.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,17 @@ nfs_inode_detach_delegation(struct inode *inode)
301301
return nfs_detach_delegation(nfsi, delegation, server);
302302
}
303303

304+
static void
305+
nfs_update_inplace_delegation(struct nfs_delegation *delegation,
306+
const struct nfs_delegation *update)
307+
{
308+
if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
309+
delegation->stateid.seqid = update->stateid.seqid;
310+
smp_wmb();
311+
delegation->type = update->type;
312+
}
313+
}
314+
304315
/**
305316
* nfs_inode_set_delegation - set up a delegation on an inode
306317
* @inode: inode to which delegation applies
@@ -334,9 +345,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
334345
old_delegation = rcu_dereference_protected(nfsi->delegation,
335346
lockdep_is_held(&clp->cl_lock));
336347
if (old_delegation != NULL) {
337-
if (nfs4_stateid_match(&delegation->stateid,
338-
&old_delegation->stateid) &&
339-
delegation->type == old_delegation->type) {
348+
/* Is this an update of the existing delegation? */
349+
if (nfs4_stateid_match_other(&old_delegation->stateid,
350+
&delegation->stateid)) {
351+
nfs_update_inplace_delegation(old_delegation,
352+
delegation);
353+
nfsi->delegation_state = old_delegation->type;
340354
goto out;
341355
}
342356
/*

0 commit comments

Comments
 (0)