summaryrefslogtreecommitdiff
path: root/usr/src/uts
diff options
context:
space:
mode:
authorMatt Barden <matt.barden@nexenta.com>2016-02-24 16:37:46 -0500
committerGordon Ross <gwr@nexenta.com>2019-05-19 19:20:47 -0400
commit9c856e866360bf6877f0e47fdfef22bd8e33cf14 (patch)
treef3978b8696f4ea8b100b9443d2bdc2839f173853 /usr/src/uts
parent58ccc3dc6cf31bbb97afd9f13137fe67844f1c95 (diff)
downloadillumos-joyent-9c856e866360bf6877f0e47fdfef22bd8e33cf14.tar.gz
10968 Kernel panic in smb_session_delete
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com> Reviewed by: Matt Barden <matt.barden@nexenta.com> Reviewed by: Gordon Ross <gwr@nexenta.com> Approved by: Joshua M. Clulow <josh@sysmgr.org>
Diffstat (limited to 'usr/src/uts')
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_oplock.c11
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session.c41
2 files changed, 46 insertions, 6 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb_oplock.c b/usr/src/uts/common/fs/smbsrv/smb_oplock.c
index 39677ffdd5..c413dd0b3e 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c
@@ -407,7 +407,9 @@ smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk)
/*
* Make sure we can get a hold on the ofile. If we can't,
* the file is closing, and there's no point scheduling an
- * oplock break on it. (Also hold the tree and user.)
+ * oplock break on it because the close will release the
+ * oplock very soon. Same for the tree & user holds.
+ *
* These holds account for the pointers we copy into the
* smb_request fields: fid_ofile, tid_tree, uid_user.
* These holds are released via smb_request_free after
@@ -416,10 +418,15 @@ smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk)
ofile = og->og_ofile;
if (!smb_ofile_hold(ofile))
return;
+
+ if ((sr = smb_request_alloc(og->og_session, 0)) == NULL) {
+ smb_ofile_release(ofile);
+ return;
+ }
+
smb_tree_hold_internal(ofile->f_tree);
smb_user_hold_internal(ofile->f_user);
- sr = smb_request_alloc(og->og_session, 0);
sr->sr_state = SMB_REQ_STATE_SUBMITTED;
sr->user_cr = zone_kcred();
sr->fid_ofile = ofile;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c
index 3caa759caa..76f867d0b9 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/atomic.h>
@@ -602,8 +602,11 @@ smb_session_reader(smb_session_t *session)
/*
* Allocate a request context, read the whole message.
+ * If the request alloc fails, we've disconnected and
+ * won't be able to send the reply anyway, so bail now.
*/
- sr = smb_request_alloc(session, hdr.xh_length);
+ if ((sr = smb_request_alloc(session, hdr.xh_length)) == NULL)
+ break;
req_buf = (uint8_t *)sr->sr_request_buf;
resid = hdr.xh_length;
@@ -1320,7 +1323,8 @@ smb_session_isclient(smb_session_t *sn, const char *client)
* Allocate an smb_request_t structure from the kmem_cache. Partially
* initialize the found/new request.
*
- * Returns pointer to a request
+ * Returns pointer to a request, or NULL if the session state is
+ * one in which new requests are no longer allowed.
*/
smb_request_t *
smb_request_alloc(smb_session_t *session, int req_length)
@@ -1353,7 +1357,36 @@ smb_request_alloc(smb_session_t *session, int req_length)
sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
sr->sr_magic = SMB_REQ_MAGIC;
sr->sr_state = SMB_REQ_STATE_INITIALIZING;
- smb_slist_insert_tail(&session->s_req_list, sr);
+
+ /*
+ * Only allow new SMB requests in some states.
+ */
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_CONNECTED:
+ case SMB_SESSION_STATE_INITIALIZED:
+ case SMB_SESSION_STATE_ESTABLISHED:
+ case SMB_SESSION_STATE_NEGOTIATED:
+ smb_slist_insert_tail(&session->s_req_list, sr);
+ break;
+
+ default:
+ ASSERT(0);
+ /* FALLTHROUGH */
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ /* Disallow new requests in these states. */
+ if (sr->sr_request_buf)
+ kmem_free(sr->sr_request_buf, sr->sr_req_length);
+ sr->session = NULL;
+ sr->sr_magic = 0;
+ mutex_destroy(&sr->sr_mutex);
+ kmem_cache_free(smb_cache_request, sr);
+ sr = NULL;
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+
return (sr);
}