Skip to content

Commit

Permalink
nfscl: Do not use nfso_own for delayed nfsrpc_doclose()
Browse files Browse the repository at this point in the history
When an initial attempt to close an NFSv4 lock returns NFSERR_DELAY,
the open structure is put on a list for delayed closing.  When this
is done, the nfso_own field is set to NULL, so it cannot be used by
nfsrpc_doclose().

Without this patch, the NFSv4 client can crash when a NFSv4 server
replies NFSERR_DELAY to a Close operation.  Fortunately, most extant
NFSv4 servers do not do this.  This patch avoids the crash for any
that do return NFSERR_DELAY for Close.

Found during a IETF bakeathon testing event this week.

MFC after:	5 days
  • Loading branch information
Rick Macklem authored and Rick Macklem committed Apr 26, 2024
1 parent f0e59ec commit 6251027
Showing 1 changed file with 14 additions and 6 deletions.
20 changes: 14 additions & 6 deletions sys/fs/nfsclient/nfs_clrpcops.c
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,7 @@ nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p,
u_int64_t off = 0, len = 0;
u_int32_t type = NFSV4LOCKT_READ;
int error, do_unlock, trycnt;
bool own_not_null;

tcred = newnfs_getcred();
newnfs_copycred(&op->nfso_cred, tcred);
Expand Down Expand Up @@ -892,22 +893,29 @@ nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p,
* There could be other Opens for different files on the same
* OpenOwner, so locking is required.
*/
NFSLOCKCLSTATE();
nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
NFSUNLOCKCLSTATE();
own_not_null = false;
if (op->nfso_own != NULL) {
own_not_null = true;
NFSLOCKCLSTATE();
nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
NFSUNLOCKCLSTATE();
}
do {
error = nfscl_tryclose(op, tcred, nmp, p, loop_on_delayed);
if (error == NFSERR_GRACE)
(void) nfs_catnap(PZERO, error, "nfs_close");
} while (error == NFSERR_GRACE);
NFSLOCKCLSTATE();
nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
if (own_not_null) {
NFSLOCKCLSTATE();
nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
}

LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
nfscl_freelockowner(lp, 0);
if (freeop && error != NFSERR_DELAY)
nfscl_freeopen(op, 0, true);
NFSUNLOCKCLSTATE();
if (own_not_null)
NFSUNLOCKCLSTATE();
NFSFREECRED(tcred);
return (error);
}
Expand Down

0 comments on commit 6251027

Please sign in to comment.