From 9c856e866360bf6877f0e47fdfef22bd8e33cf14 Mon Sep 17 00:00:00 2001 From: Matt Barden Date: Wed, 24 Feb 2016 16:37:46 -0500 Subject: [PATCH] 10968 Kernel panic in smb_session_delete Reviewed by: Kevin Crowe Reviewed by: Matt Barden Reviewed by: Gordon Ross Approved by: Joshua M. Clulow --- usr/src/uts/common/fs/smbsrv/smb_oplock.c | 11 ++++-- 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 39677ffdd52c..c413dd0b3ed6 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 3caa759caa03..76f867d0b922 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 @@ -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); }