Skip to content

Commit

Permalink
10968 Kernel panic in smb_session_delete
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mbarden authored and gwr committed May 19, 2019
1 parent 58ccc3d commit 9c856e8
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 6 deletions.
11 changes: 9 additions & 2 deletions usr/src/uts/common/fs/smbsrv/smb_oplock.c
Expand Up @@ -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
Expand All @@ -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;
Expand Down
41 changes: 37 additions & 4 deletions usr/src/uts/common/fs/smbsrv/smb_session.c
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 9c856e8

Please sign in to comment.