Home | History | Annotate | Download | only in iscsitgtd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <strings.h>
     32 #include <unistd.h>
     33 #include <assert.h>
     34 #include <syslog.h>
     35 #include <synch.h>
     36 #include <time.h>
     37 #include <umem.h>
     38 
     39 #include "queue.h"
     40 #include "iscsi_conn.h"
     41 #include "utility.h"
     42 #include "target.h"
     43 #include "t10.h"
     44 
     45 /*
     46  * Constants
     47  */
     48 static const timespec_t usec = {0, 1000};
     49 
     50 FILE *qlog = NULL;
     51 int qlog_lvl = 0;
     52 
     53 pthread_mutex_t q_mutex;
     54 int queue_num;
     55 
     56 void
     57 queue_init()
     58 {
     59 	(void) pthread_mutex_init(&q_mutex, NULL);
     60 	queue_log(True);
     61 }
     62 
     63 target_queue_t *
     64 queue_alloc()
     65 {
     66 	target_queue_t	*q =
     67 	    (target_queue_t *)calloc(1, sizeof (target_queue_t));
     68 
     69 	if (q == NULL)
     70 		return (NULL);
     71 
     72 	(void) pthread_mutex_lock(&q_mutex);
     73 	q->q_num = queue_num++;
     74 	(void) pthread_mutex_unlock(&q_mutex);
     75 
     76 	(void) sema_init(&q->q_sema, 0, USYNC_THREAD, NULL);
     77 	(void) pthread_mutex_init(&q->q_mutex, NULL);
     78 
     79 	return (q);
     80 }
     81 
     82 void
     83 queue_log(Boolean_t on)
     84 {
     85 	(void) pthread_mutex_lock(&q_mutex);
     86 	if ((on == True) && (qlog == NULL) && (qlog_lvl != 0)) {
     87 		qlog = fopen(target_log, "ab");
     88 	} else if ((on == False) && (qlog != NULL)) {
     89 		(void) fclose(qlog);
     90 		qlog = NULL;
     91 	}
     92 	(void) pthread_mutex_unlock(&q_mutex);
     93 }
     94 
     95 /*
     96  * []----
     97  * | queue_message_set -- add a given message to the queue.
     98  * []----
     99  */
    100 void
    101 queue_message_set(target_queue_t *q, uint32_t lvl, msg_type_t type,
    102     void *data)
    103 {
    104 	msg_t	*msg;
    105 
    106 	if ((msg = umem_cache_alloc(queue_cache, 0)) == NULL)
    107 		return;
    108 
    109 	bzero(msg, sizeof (*msg));
    110 	msg->msg_pri_level	= lvl;
    111 	msg->msg_type		= type;
    112 	msg->msg_data		= data;
    113 
    114 	(void) pthread_mutex_lock(&q->q_mutex);
    115 
    116 	if (q->q_head == NULL) {
    117 		q->q_head = msg;
    118 		assert(q->q_tail == NULL);
    119 		q->q_tail = msg;
    120 	} else if (lvl & Q_HIGH) {
    121 		msg->msg_next = q->q_head;
    122 		q->q_head->msg_prev = msg;
    123 		q->q_head = msg;
    124 	} else {
    125 		q->q_tail->msg_next = msg;
    126 		msg->msg_prev = q->q_tail;
    127 		q->q_tail = msg;
    128 	}
    129 
    130 	(void) pthread_mutex_unlock(&q->q_mutex);
    131 
    132 	(void) sema_post(&q->q_sema);
    133 }
    134 
    135 /*
    136  * []----
    137  * | queue_message_get -- retrieve the first message in the queue
    138  * []----
    139  */
    140 msg_t *
    141 queue_message_get(target_queue_t *q)
    142 {
    143 	msg_t *m;
    144 
    145 	while (sema_wait(&q->q_sema) == -1)
    146 		(void) nanosleep(&usec, 0);
    147 	(void) pthread_mutex_lock(&q->q_mutex);
    148 	m = q->q_head;
    149 	if (m == NULL) {
    150 		assert(q->q_tail == NULL);
    151 		(void) pthread_mutex_unlock(&q->q_mutex);
    152 		return (NULL);
    153 	}
    154 	q->q_head = m->msg_next;
    155 	if (q->q_head == NULL)
    156 		q->q_tail = NULL;
    157 	(void) pthread_mutex_unlock(&q->q_mutex);
    158 
    159 	return (m);
    160 }
    161 
    162 /*
    163  * []----
    164  * | queue_message_try_get -- see if there's a message available
    165  * []----
    166  */
    167 msg_t *
    168 queue_message_try_get(target_queue_t *q)
    169 {
    170 	msg_t	*m;
    171 
    172 	if (sema_trywait(&q->q_sema) != 0)
    173 		return (NULL);
    174 	(void) pthread_mutex_lock(&q->q_mutex);
    175 	m = q->q_head;
    176 	q->q_head = m->msg_next;
    177 	if (q->q_head == NULL)
    178 		q->q_tail = NULL;
    179 	(void) pthread_mutex_unlock(&q->q_mutex);
    180 
    181 	return (m);
    182 }
    183 
    184 /*
    185  * []----
    186  * | queue_walker_free -- Run through a queue and free certain messages.
    187  * |
    188  * | Users of the queues should not walk the queue structure themselves
    189  * | unless they also need to grab the lock. To prevent that level of
    190  * | knowledge of the queue structures this method is provided to enable
    191  * | other subsystems to walk the queue looking for messages which need
    192  * | to be deleted.
    193  * []----
    194  */
    195 void
    196 queue_walker_free(target_queue_t *q, Boolean_t (*func)(msg_t *m, void *v),
    197     void *v1)
    198 {
    199 	msg_t	*m;		/* current working message */
    200 	msg_t	*n;		/* next message */
    201 
    202 	(void) pthread_mutex_lock(&q->q_mutex);
    203 	m = q->q_head;
    204 	while (m) {
    205 		if ((*func)(m, v1) == True) {
    206 			if (m == q->q_head) {
    207 				q->q_head = m->msg_next;
    208 				if (m->msg_next == NULL)
    209 					q->q_tail = NULL;
    210 				else
    211 					m->msg_next->msg_prev = NULL;
    212 			} else {
    213 				m->msg_prev->msg_next = m->msg_next;
    214 				if (m->msg_next == NULL)
    215 					q->q_tail = m->msg_prev;
    216 				else
    217 					m->msg_next->msg_prev = m->msg_prev;
    218 			}
    219 			n = m->msg_next;
    220 			queue_message_free(m);
    221 			m = n;
    222 		} else {
    223 			m = m->msg_next;
    224 		}
    225 	}
    226 	(void) pthread_mutex_unlock(&q->q_mutex);
    227 }
    228 
    229 /*
    230  * []----
    231  * | queue_reset -- Flush a queue of all command messages messages.
    232  * []----
    233  */
    234 void
    235 queue_reset(target_queue_t *q)
    236 {
    237 	msg_t	*m;
    238 	msg_t	*n;
    239 
    240 	(void) pthread_mutex_lock(&q->q_mutex);
    241 	m = q->q_head;
    242 	while (m != NULL) {
    243 
    244 		switch (m->msg_type) {
    245 		case msg_cmd_data_out:
    246 		case msg_cmd_send:
    247 			if (m == q->q_head) {
    248 				q->q_head = m->msg_next;
    249 				if (m->msg_next == NULL)
    250 					q->q_tail = NULL;
    251 				else
    252 					m->msg_next->msg_prev = NULL;
    253 			} else {
    254 				assert(m->msg_prev != NULL);
    255 				m->msg_prev->msg_next = m->msg_next;
    256 				if (m->msg_next == NULL)
    257 					q->q_tail = m->msg_prev;
    258 				else
    259 					m->msg_next->msg_prev = m->msg_prev;
    260 			}
    261 			n = m->msg_next;
    262 			queue_message_free(m);
    263 			m = n;
    264 			(void) sema_wait(&q->q_sema);
    265 			break;
    266 
    267 		case msg_reset_lu:
    268 		case msg_shutdown:
    269 		case msg_lu_add:
    270 		case msg_lu_remove:
    271 		case msg_lu_online:
    272 		case msg_thick_provo:
    273 			/*
    274 			 * Don't flush the control messages
    275 			 */
    276 			m = m->msg_next;
    277 			break;
    278 
    279 		default:
    280 			queue_prt(mgmtq, Q_STE_ERRS,
    281 			    "---- Unexpected msg type %d ----", m->msg_type);
    282 			m = m->msg_next;
    283 			break;
    284 		}
    285 	}
    286 
    287 	(void) pthread_mutex_unlock(&q->q_mutex);
    288 }
    289 
    290 void
    291 queue_message_free(msg_t *m)
    292 {
    293 	umem_cache_free(queue_cache, m);
    294 }
    295 
    296 /*
    297  * []----
    298  * | queue_free -- free resources used by queue structure
    299  * []----
    300  */
    301 void
    302 queue_free(target_queue_t *q, void (*free_func)(msg_t *))
    303 {
    304 	msg_t	*m;
    305 	msg_t	*n;
    306 
    307 	(void) pthread_mutex_lock(&q->q_mutex);
    308 	m = q->q_head;
    309 	while (m != NULL) {
    310 		if (free_func != NULL)
    311 			(*free_func)(m);
    312 		n = m->msg_next;
    313 		queue_message_free(m);
    314 		m = n;
    315 	}
    316 	(void) pthread_mutex_unlock(&q->q_mutex);
    317 
    318 	(void) pthread_mutex_destroy(&q->q_mutex);
    319 	(void) sema_destroy(&q->q_sema);
    320 	free(q);
    321 }
    322 
    323 void
    324 queue_prt(target_queue_t *q, int type, char *fmt, ...)
    325 {
    326 	va_list		ap;
    327 	char		buf[80];
    328 
    329 	va_start(ap, fmt);
    330 	/* LINTED variable format specifier */
    331 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
    332 	queue_str(q, type, msg_log, buf);
    333 	va_end(ap);
    334 }
    335 
    336 /*
    337  * []----
    338  * | queue_str -- helper function which sends a string to the queue
    339  * []----
    340  */
    341 void
    342 queue_str(target_queue_t *q, uint32_t lvl, msg_type_t type, char *fmt)
    343 {
    344 	int		len;
    345 	char		*m;
    346 	hrtime_t	h	= gethrtime();
    347 	hrtime_t	delta;
    348 	static hrtime_t	last_h	= 0;
    349 	time_t		tval = time((time_t *)0);
    350 	char		debug[80];
    351 
    352 	(void) pthread_mutex_lock(&q_mutex);
    353 	if ((qlog) && (qlog_lvl & lvl)) {
    354 		(void) ctime_r(&tval, debug, sizeof (debug));
    355 		(void) fprintf(qlog, "%s %s", debug, fmt);
    356 		(void) fflush(qlog);
    357 	}
    358 	(void) pthread_mutex_unlock(&q_mutex);
    359 
    360 	if ((dbg_timestamps == True) && (lvl != 0) && ((lvl & Q_HIGH) == 0)) {
    361 		len	= strlen(fmt) + 12;
    362 		m	= malloc(len);
    363 		delta	= h - last_h;
    364 		last_h	= h;
    365 		(void) snprintf(m, len, "%9.3f %s",
    366 		    (double)delta / (double)1000000.0, fmt);
    367 		queue_message_set(q, lvl, type, (void *)m);
    368 	} else {
    369 		len	= strlen(fmt) + 1;
    370 		m	= malloc(len);
    371 		(void) strncpy(m, fmt, len);
    372 		queue_message_set(q, lvl, type, (void *)m);
    373 	}
    374 }
    375 
    376 /*
    377  * []------------------------------------------------------------------[]
    378  * | Specialized free routines for queue data.				|
    379  * | It is possible for a shutdown to start because the STE thread	|
    380  * | receives an error while reading from the socket. If at the same	|
    381  * | time the connection poll thread is processing a PDU it could place	|
    382  * | a msg_ste_datain package on the STE queue. When the STE hits the	|
    383  * | shutdown message first it will exit and we need to clean up	|
    384  * | anything on that queue which means freeing memory in the		|
    385  * | appropriate manner. This is just one example and there are several	|
    386  * | others. Another method to deal with this would be to have a closed	|
    387  * | flag such that any futher calls to queue_message_set would return	|
    388  * | an error. This would require any calls to queue_message_set() deal	|
    389  * | with this condition. The approach used here seems cleaner.		|
    390  * | The drawback to this approach is that if any new messages are	|
    391  * | added then the developer had better add it to these routines as	|
    392  * | appropriate.							|
    393  * []------------------------------------------------------------------[]
    394  */
    395 
    396 /*
    397  * []----
    398  * | sess_queue_data_remove -- free any message data left on the sess queue
    399  * |
    400  * | XXX This should be recoded so that we're doing the cleanup within
    401  * | the session code. Peal off any messages and deal with them there.
    402  * []----
    403  */
    404 void
    405 sess_queue_data_remove(msg_t *m)
    406 {
    407 	mgmt_request_t	*mq;
    408 	char		**buf;
    409 
    410 	syslog(LOG_ERR, "sess_queue_data: type %d", m->msg_type);
    411 	switch (m->msg_type) {
    412 	default:
    413 		syslog(LOG_ERR, "Unknown session type data being free'd, %d",
    414 		    m->msg_type);
    415 		free(m->msg_data);
    416 		break;
    417 
    418 	case msg_shutdown:
    419 	case msg_shutdown_rsp:
    420 	case msg_ste_media_error:
    421 		syslog(LOG_ERR, "Impossible message left in session queue"
    422 		    " of type %d", m->msg_type);
    423 		break;
    424 
    425 	case msg_cmd_data_out:
    426 		break;
    427 
    428 	case msg_initiator_name:
    429 	case msg_initiator_alias:
    430 	case msg_target_name:
    431 		free(((name_request_t *)m->msg_data)->nr_name);
    432 		break;
    433 
    434 	case msg_mgmt_rqst:
    435 		mq = (mgmt_request_t *)m->msg_data;
    436 		(void) pthread_mutex_lock(&mq->m_resp_mutex);
    437 		tgt_buf_add(mq->m_u.m_resp, "queue_freed", NULL);
    438 		(void) pthread_mutex_unlock(&mq->m_resp_mutex);
    439 		queue_message_set(mq->m_q, 0, msg_mgmt_rply, 0);
    440 		break;
    441 
    442 	case msg_mgmt_rply:
    443 		mq	= (mgmt_request_t *)m->msg_data;
    444 		buf	= mq->m_u.m_resp;
    445 		tgt_buf_add_tag(buf, XML_ELEMENT_STATS, Tag_End);
    446 		tgt_buf_add_tag(buf, XML_ELEMENT_CONN, Tag_End);
    447 
    448 		(void) pthread_mutex_unlock(&mq->m_resp_mutex);
    449 		queue_message_set(mq->m_q, 0, msg_mgmt_rply, 0);
    450 		break;
    451 
    452 	case msg_reset_targ:
    453 	case msg_reset_lu:
    454 		/* ---- these are safe to ignore, no data to free ---- */
    455 		break;
    456 	}
    457 }
    458 
    459 /*
    460  * []----
    461  * | conn_queue_data_remove -- free any message data left on the conn queue
    462  * []----
    463  */
    464 void
    465 conn_queue_data_remove(msg_t *m)
    466 {
    467 	mgmt_request_t	*mq;
    468 
    469 	syslog(LOG_ERR, "conn_queue_data: type %d", m->msg_type);
    470 	switch (m->msg_type) {
    471 	case msg_cmd_data_rqst:
    472 	case msg_cmd_data_out:
    473 	case msg_cmd_cmplt:
    474 		syslog(LOG_ERR, "Free'ing data which should already be gone");
    475 		free(m->msg_data);
    476 		break;
    477 
    478 	case msg_mgmt_rqst:
    479 		mq = (mgmt_request_t *)m->msg_data;
    480 		(void) pthread_mutex_lock(&mq->m_resp_mutex);
    481 		if (mq->m_u.m_resp != NULL)
    482 			tgt_buf_add(mq->m_u.m_resp, "queue_freed", NULL);
    483 		(void) pthread_mutex_unlock(&mq->m_resp_mutex);
    484 		queue_message_set(mq->m_q, 0, msg_mgmt_rply, 0);
    485 		break;
    486 
    487 	default:
    488 		syslog(LOG_ERR, "Unknown connection message being free'd: %d",
    489 		    m->msg_type);
    490 		free(m->msg_data);
    491 		break;
    492 	}
    493 }
    494