diff options
author | Matt Barden <matt.barden@nexenta.com> | 2016-02-24 16:37:46 -0500 |
---|---|---|
committer | Gordon Ross <gwr@nexenta.com> | 2019-05-19 19:20:47 -0400 |
commit | 9c856e866360bf6877f0e47fdfef22bd8e33cf14 (patch) | |
tree | f3978b8696f4ea8b100b9443d2bdc2839f173853 /usr/src/uts | |
parent | 58ccc3dc6cf31bbb97afd9f13137fe67844f1c95 (diff) | |
download | illumos-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.c | 11 | ||||
-rw-r--r-- | usr/src/uts/common/fs/smbsrv/smb_session.c | 41 |
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); } |