aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2024-04-26 03:58:21 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2024-05-01 01:16:33 +0000
commit19b6aa047e77757de58811f02c564e8dff3679b6 (patch)
tree5f45c72548364d9a6a400e2a186187d9afe3b7ef
parent509819691cb8d2f62ec9f14fe84928872ceb126e (diff)
downloadsrc-19b6aa047e77757de58811f02c564e8dff3679b6.tar.gz
src-19b6aa047e77757de58811f02c564e8dff3679b6.zip
nfscl: Do not use nfso_own for delayed nfsrpc_doclose()
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. (cherry picked from commit 6251027c4252edb3b8f8fc359a40e610349e9af3)
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 899d81efcf7c..475034768e04 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -799,6 +799,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);
@@ -865,22 +866,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);
}