changeset 13931:3f18ae9d8c98

3502 panic in smb_server_shutdown (sl_count assertion) Reviewed by: Gordon Ross <gwr@nexenta.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Approved by: Richard Lowe <richlowe@richlowe.net>
author Kevin Crowe <kevin.crowe@nexenta.com>
date Tue, 17 Jul 2012 12:40:19 -0400
parents f2303e5259ca
children b74723e0c05f
files usr/src/uts/common/fs/smbsrv/smb_kshare.c usr/src/uts/common/fs/smbsrv/smb_server.c
diffstat 2 files changed, 39 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Tue Feb 15 21:27:02 2011 -0500
+++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Tue Jul 17 12:40:19 2012 -0400
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <smbsrv/smb_door.h>
@@ -60,6 +61,9 @@
 	smb_kshare_destroy
 };
 
+extern int smb_server_lookup(smb_server_t **);
+extern void smb_server_release(smb_server_t *);
+
 /*
  * This function is not MultiThread safe. The caller has to make sure only one
  * thread calls this function.
@@ -347,22 +351,35 @@
 int
 smb_kshare_export_list(smb_ioc_share_t *ioc)
 {
-	nvlist_t	*shrlist;
+	nvlist_t	*shrlist = NULL;
 	nvlist_t	 *share;
 	nvpair_t	 *nvp;
 	smb_kshare_t	 *shr;
 	char		*shrname;
-	int		rc;
+	int		rc = 0;
+	smb_server_t	*sv = NULL;
 
 	if (!smb_export_isready())
 		return (ENOTACTIVE);
 
+	if ((rc = smb_server_lookup(&sv)) != 0)
+		return (rc);
+
 	if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, KM_SLEEP))
 	    != 0)
-		return (rc);
+		goto out;
 
 	for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
 	    nvp = nvlist_next_nvpair(shrlist, nvp)) {
+
+		/*
+		 * Since this loop can run for a while we want to exit
+		 * as soon as the server state is anything but RUNNING
+		 * to allow shutdown to proceed.
+		 */
+		if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
+			goto out;
+
 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
 			continue;
 
@@ -381,14 +398,19 @@
 			continue;
 		}
 
+		/* smb_kshare_export consumes shr so it's not leaked */
 		if ((rc = smb_kshare_export(shr)) != 0) {
 			smb_kshare_destroy(shr);
 			continue;
 		}
 	}
+	rc = 0;
 
-	nvlist_free(shrlist);
-	return (0);
+out:
+	if (shrlist != NULL)
+		nvlist_free(shrlist);
+	smb_server_release(sv);
+	return (rc);
 }
 
 /*
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c	Tue Feb 15 21:27:02 2011 -0500
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c	Tue Jul 17 12:40:19 2012 -0400
@@ -230,8 +230,8 @@
 static void smb_server_kstat_init(smb_server_t *);
 static void smb_server_kstat_fini(smb_server_t *);
 static void smb_server_timers(smb_thread_t *, void *);
-static int smb_server_lookup(smb_server_t **);
-static void smb_server_release(smb_server_t *);
+int smb_server_lookup(smb_server_t **);
+void smb_server_release(smb_server_t *);
 static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *);
 static void smb_server_shutdown(smb_server_t *);
 static int smb_server_fsop_start(smb_server_t *);
@@ -1408,6 +1408,14 @@
 	smb_server_listener_stop(&sv->sv_tcp_daemon);
 
 	if (sv->sv_session != NULL) {
+		/*
+		 * smb_kshare_export may have a request on here.
+		 * Normal sessions do this in smb_session_cancel()
+		 * but this is a "fake" session used only for the
+		 * requests used by the kshare thread(s).
+		 */
+		smb_slist_wait_for_empty(&sv->sv_session->s_req_list);
+
 		smb_session_delete(sv->sv_session);
 		sv->sv_session = NULL;
 	}
@@ -1637,7 +1645,7 @@
  * This function tries to find the server associated with the zone of the
  * caller.
  */
-static int
+int
 smb_server_lookup(smb_server_t **psv)
 {
 	zoneid_t	zid;
@@ -1673,7 +1681,7 @@
  * This function decrements the reference count of the server and signals its
  * condition variable if the state of the server is SMB_SERVER_STATE_DELETING.
  */
-static void
+void
 smb_server_release(smb_server_t *sv)
 {
 	SMB_SERVER_VALID(sv);