changeset 3182:175d080807a8

6480791 NULL pointer dereference panic on guest domains. 6494132 ldoms ds module could use lint cleanup
author jm22469
date Mon, 27 Nov 2006 16:54:30 -0800
parents 65ef60e5a248
children e066f975b8da
files usr/src/uts/sun4v/ds/Makefile usr/src/uts/sun4v/io/ds.c
diffstat 2 files changed, 54 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/sun4v/ds/Makefile	Mon Nov 27 14:11:55 2006 -0800
+++ b/usr/src/uts/sun4v/ds/Makefile	Mon Nov 27 16:54:30 2006 -0800
@@ -25,7 +25,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# This makefile drives the production of the zp kernel module.
+# This makefile drives the production of the ds kernel module.
 #
 # sun4v implementation architecture dependent
 #
@@ -76,7 +76,6 @@
 # Please do not carry these forward to new Makefiles.
 #
 LINTTAGS	+= -erroff=E_BAD_PTR_CAST_ALIGN
-LINTTAGS	+= -erroff=E_SUSPICIOUS_COMPARISON
 
 #
 # Default build targets.
--- a/usr/src/uts/sun4v/io/ds.c	Mon Nov 27 14:11:55 2006 -0800
+++ b/usr/src/uts/sun4v/io/ds.c	Mon Nov 27 16:54:30 2006 -0800
@@ -83,6 +83,30 @@
 #define	DS_MAXSVCS_INIT		32
 
 /*
+ * Lock Usage
+ *
+ * ds_svcs.rwlock
+ *
+ *	See comment just above definition of ds_svcs structure above.
+ *
+ * ds_port mutex
+ *
+ *	Protects the elements of each port structure.  Must be acquired for
+ *	access to any of the elements.
+ *
+ * ds_log mutex
+ *
+ *	See comment above definition of ds_log structure.
+ *
+ * Multiple lock requirements:
+ *
+ *	Some code will need to access both a ds_svc_t structure and
+ *	a ds_port_t.  In that case, the acquisition order must be:
+ *
+ *	ds_svcs.rwlock -> port lock
+ */
+
+/*
  * Taskq for internal task processing
  */
 static taskq_t *ds_taskq;
@@ -663,17 +687,11 @@
 	/*
 	 * Check the LDC event.
 	 */
-
-	mutex_enter(&port->lock);
-
-	if (event & LDC_EVT_WRITE) {
-		DS_DBG("ds@%lx: LDC write event received, not supported\n",
-		    port->id);
-		goto done;
-	}
-
 	if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) {
 
+		rw_enter(&ds_svcs.rwlock, RW_WRITER);
+		mutex_enter(&port->lock);
+
 		/* reset the port state */
 		ds_port_reset(port);
 		(void) ldc_up(ldc_hdl);
@@ -682,6 +700,7 @@
 		if ((rv = ldc_status(ldc_hdl, &ldc_state)) != 0) {
 			cmn_err(CE_NOTE, "ds@%lx: ldc_status error (%d)\n",
 			    port->id, rv);
+			rw_exit(&ds_svcs.rwlock);
 			goto done;
 		}
 		port->ldc.state = ldc_state;
@@ -695,9 +714,12 @@
 
 		ASSERT((event & (LDC_EVT_UP | LDC_EVT_READ)) == 0);
 
+		rw_exit(&ds_svcs.rwlock);
 		goto done;
 	}
 
+	mutex_enter(&port->lock);
+
 	if (event & LDC_EVT_UP) {
 		if ((rv = ldc_status(ldc_hdl, &ldc_state)) != 0) {
 			cmn_err(CE_NOTE, "ds@%lx: ldc_status error (%d)\n",
@@ -717,6 +739,12 @@
 		}
 	}
 
+	if (event & LDC_EVT_WRITE) {
+		DS_DBG("ds@%lx: LDC write event received, not supported\n",
+		    port->id);
+		goto done;
+	}
+
 	/* report any unknown LDC events */
 	if (event & ~(LDC_EVT_UP | LDC_EVT_READ)) {
 		cmn_err(CE_NOTE, "ds@%lx: Unexpected LDC event received: "
@@ -1131,7 +1159,7 @@
 
 	ack = (ds_reg_ack_t *)(buf + DS_HDR_SZ);
 
-	rw_enter(&ds_svcs.rwlock, RW_READER);
+	rw_enter(&ds_svcs.rwlock, RW_WRITER);
 
 	/* lookup appropriate client */
 	if ((svc = ds_get_svc(ack->svc_handle)) == NULL) {
@@ -1210,7 +1238,7 @@
 
 	nack = (ds_reg_nack_t *)(buf + DS_HDR_SZ);
 
-	rw_enter(&ds_svcs.rwlock, RW_READER);
+	rw_enter(&ds_svcs.rwlock, RW_WRITER);
 
 	/* lookup appropriate client */
 	if ((svc = ds_get_svc(nack->svc_handle)) == NULL) {
@@ -1301,7 +1329,7 @@
 	/* the request information */
 	req = (ds_unreg_req_t *)(buf + DS_HDR_SZ);
 
-	rw_enter(&ds_svcs.rwlock, RW_READER);
+	rw_enter(&ds_svcs.rwlock, RW_WRITER);
 
 	/* lookup appropriate client */
 	if ((svc = ds_get_svc(req->svc_handle)) == NULL) {
@@ -1352,7 +1380,7 @@
 
 	DS_DBG("ds@%lx: <unreg_ack: hdl=0x%09lx\n", port->id, ack->svc_handle);
 
-	rw_enter(&ds_svcs.rwlock, RW_READER);
+	rw_enter(&ds_svcs.rwlock, RW_WRITER);
 
 	/*
 	 * Since the unregister request was initiated locally,
@@ -1386,7 +1414,7 @@
 	DS_DBG("ds@%lx: <unreg_nack: hdl=0x%09lx\n", port->id,
 	    nack->svc_handle);
 
-	rw_enter(&ds_svcs.rwlock, RW_READER);
+	rw_enter(&ds_svcs.rwlock, RW_WRITER);
 
 	/*
 	 * Since the unregister request was initiated locally,
@@ -1467,7 +1495,7 @@
 
 	if (nack->result == DS_INV_HDL) {
 
-		rw_enter(&ds_svcs.rwlock, RW_READER);
+		rw_enter(&ds_svcs.rwlock, RW_WRITER);
 
 		if ((svc = ds_get_svc(nack->svc_handle)) == NULL) {
 			rw_exit(&ds_svcs.rwlock);
@@ -1877,7 +1905,7 @@
 	int		idx;
 	ds_svc_t	*svc;
 
-	ASSERT(RW_LOCK_HELD(&ds_svcs.rwlock));
+	ASSERT(RW_WRITE_HELD(&ds_svcs.rwlock));
 
 	/* walk every table entry */
 	for (idx = 0; idx < ds_svcs.maxsvcs; idx++) {
@@ -1958,6 +1986,8 @@
 
 	int	idx;
 
+	ASSERT(RW_WRITE_HELD(&ds_svcs.rwlock));
+
 	/* check the state of the service */
 	if (DS_SVC_ISFREE(svc) || (svc->state != DS_SVC_INACTIVE))
 		return (0);
@@ -1999,6 +2029,8 @@
 {
 	ds_port_t *port = (ds_port_t *)arg;
 
+	ASSERT(RW_WRITE_HELD(&ds_svcs.rwlock));
+
 	if (DS_SVC_ISFREE(svc)) {
 		return (0);
 	}
@@ -2098,6 +2130,8 @@
 static void
 ds_reset_svc(ds_svc_t *svc, ds_port_t *port)
 {
+	ASSERT(RW_WRITE_HELD(&ds_svcs.rwlock));
+
 	svc->state = DS_SVC_INACTIVE;
 	svc->ver_idx = 0;
 	svc->ver.major = 0;
@@ -2192,15 +2226,12 @@
 static void
 ds_port_reset(ds_port_t *port)
 {
+	ASSERT(RW_WRITE_HELD(&ds_svcs.rwlock));
 	ASSERT(MUTEX_HELD(&port->lock));
 
 	/* connection went down, mark everything inactive */
-	rw_enter(&ds_svcs.rwlock, RW_WRITER);
-
 	(void) ds_walk_svcs(ds_svc_unregister, port);
 
-	rw_exit(&ds_svcs.rwlock);
-
 	port->ver_idx = 0;
 	port->ver.major = 0;
 	port->ver.minor = 0;
@@ -2417,8 +2448,6 @@
 	ds_log.size -= DS_LOG_ENTRY_SZ(head);
 	ds_log.nentry--;
 
-	ASSERT((ds_log.size >= 0) && (ds_log.nentry >= 0));
-
 	ds_log_entry_free(head);
 
 	return (0);
@@ -2444,8 +2473,6 @@
 
 	ds_log.size -= DS_LOG_ENTRY_SZ(head);
 
-	ASSERT((ds_log.size >= 0) && (ds_log.nentry >= 0));
-
 	kmem_free(head->data, head->datasz);
 	head->data = msg;
 	head->datasz = sz;
@@ -2604,11 +2631,11 @@
 
 	ds_svcs.nsvcs++;
 
-	rw_exit(&ds_svcs.rwlock);
-
 	/* attempt to register the service */
 	(void) ds_svc_register(svc, NULL);
 
+	rw_exit(&ds_svcs.rwlock);
+
 	DS_DBG("ds_cap_init: service '%s' assigned handle 0x%09lx\n",
 	    svc->cap.svc_id, svc->hdl);