xref: /illumos-gate/usr/src/cmd/vntsd/vntsdvcc.c (revision 476d5ff7)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo /*
223c96341aSnarayan  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
231ae08745Sheppo  * Use is subject to license terms.
241ae08745Sheppo  */
251ae08745Sheppo 
261ae08745Sheppo /*
271ae08745Sheppo  * Configuration and setup interface to vcc driver.
281ae08745Sheppo  * At intialization time, vntsd opens vcc ctrl port and read initial
291ae08745Sheppo  * configuratioa. It manages console groups, creates the listen thread,
301ae08745Sheppo  * dynamically adds and removes virtual console within a group.
311ae08745Sheppo  */
321ae08745Sheppo 
331ae08745Sheppo 
341ae08745Sheppo #include <syslog.h>
351ae08745Sheppo #include <stdio.h>
361ae08745Sheppo #include <sys/types.h>
371ae08745Sheppo #include <sys/ipc.h>
381ae08745Sheppo #include <stdlib.h>
391ae08745Sheppo #include <string.h>
401ae08745Sheppo #include <unistd.h>
411ae08745Sheppo #include <sys/socket.h>
421ae08745Sheppo #include <sys/ipc.h>
431ae08745Sheppo #include <sys/shm.h>
441ae08745Sheppo #include <sys/sem.h>
451ae08745Sheppo #include <wait.h>
461ae08745Sheppo #include <time.h>
471ae08745Sheppo #include <synch.h>
481ae08745Sheppo #include <netinet/in.h>
491ae08745Sheppo #include <thread.h>
501ae08745Sheppo #include <signal.h>
511ae08745Sheppo #include "vntsd.h"
521ae08745Sheppo 
531ae08745Sheppo /* signal all clients that console has been deleted */
541ae08745Sheppo boolean_t
vntsd_notify_client_cons_del(vntsd_client_t * clientp)551ae08745Sheppo vntsd_notify_client_cons_del(vntsd_client_t *clientp)
561ae08745Sheppo {
571ae08745Sheppo 	(void) mutex_lock(&clientp->lock);
581ae08745Sheppo 	clientp->status |= VNTSD_CLIENT_CONS_DELETED;
591ae08745Sheppo 	(void) thr_kill(clientp->cons_tid, SIGUSR1);
601ae08745Sheppo 	(void) mutex_unlock(&clientp->lock);
611ae08745Sheppo 	return (B_FALSE);
621ae08745Sheppo }
631ae08745Sheppo 
641ae08745Sheppo /* free console  structure */
651ae08745Sheppo static void
free_cons(vntsd_cons_t * consp)661ae08745Sheppo free_cons(vntsd_cons_t *consp)
671ae08745Sheppo {
681ae08745Sheppo 	assert(consp);
691ae08745Sheppo 	(void) mutex_destroy(&consp->lock);
701ae08745Sheppo 	(void) cond_destroy(&consp->cvp);
714d39be2bSsg 	if (consp->vcc_fd != -1)
724d39be2bSsg 		(void) close(consp->vcc_fd);
731ae08745Sheppo 	free(consp);
741ae08745Sheppo }
751ae08745Sheppo 
764d39be2bSsg /* free group structure */
774d39be2bSsg static void
free_group(vntsd_group_t * groupp)784d39be2bSsg free_group(vntsd_group_t *groupp)
794d39be2bSsg {
804d39be2bSsg 	assert(groupp);
814d39be2bSsg 	(void) mutex_destroy(&groupp->lock);
824d39be2bSsg 	(void) cond_destroy(&groupp->cvp);
834d39be2bSsg 	if (groupp->sockfd != -1)
844d39be2bSsg 		(void) close(groupp->sockfd);
854d39be2bSsg 	free(groupp);
864d39be2bSsg }
874d39be2bSsg 
881ae08745Sheppo /*
891ae08745Sheppo  *  all clients connected to a console must disconnect before
901ae08745Sheppo  *  removing a console.
911ae08745Sheppo  */
921ae08745Sheppo static void
cleanup_cons(vntsd_cons_t * consp)931ae08745Sheppo cleanup_cons(vntsd_cons_t *consp)
941ae08745Sheppo {
951ae08745Sheppo 	vntsd_group_t	*groupp;
961ae08745Sheppo 	timestruc_t	to;
971ae08745Sheppo 
981ae08745Sheppo 	assert(consp);
991ae08745Sheppo 	D1(stderr, "t@%d vntsd_disconn_clients@%d\n", thr_self(),
1001ae08745Sheppo 	    consp->cons_no);
1011ae08745Sheppo 
1021ae08745Sheppo 	groupp = consp->group;
1031ae08745Sheppo 	assert(groupp);
1041ae08745Sheppo 
1051ae08745Sheppo 
1061ae08745Sheppo 	(void) mutex_lock(&consp->lock);
1071ae08745Sheppo 
1081ae08745Sheppo 	/* wait for all clients disconnect from the console */
1091ae08745Sheppo 	while (consp->clientpq != NULL) {
1101ae08745Sheppo 		consp->status |= VNTSD_CONS_SIG_WAIT;
1111ae08745Sheppo 
1121ae08745Sheppo 		/* signal client to disconnect the console */
1131ae08745Sheppo 		(void) vntsd_que_walk(consp->clientpq,
1141ae08745Sheppo 		    (el_func_t)vntsd_notify_client_cons_del);
1151ae08745Sheppo 
1161ae08745Sheppo 		(void) thr_kill(consp->wr_tid, SIGUSR1);
1171ae08745Sheppo 		to.tv_sec = VNTSD_CV_WAIT_DELTIME;
1181ae08745Sheppo 		to.tv_nsec = 0;
1191ae08745Sheppo 
1201ae08745Sheppo 		/* wait for clients to disconnect  */
1211ae08745Sheppo 		(void) cond_reltimedwait(&consp->cvp, &consp->lock, &to);
1221ae08745Sheppo 	}
1231ae08745Sheppo 
1243af08d82Slm 	/* reduce console count in the group */
1253af08d82Slm 	(void) mutex_lock(&groupp->lock);
1263af08d82Slm 	assert(groupp->num_cons > 0);
1273af08d82Slm 	groupp->num_cons--;
1283af08d82Slm 	(void) mutex_unlock(&groupp->lock);
1293af08d82Slm 
1301ae08745Sheppo 	(void) mutex_unlock(&consp->lock);
1311ae08745Sheppo 
1321ae08745Sheppo 	free_cons(consp);
1331ae08745Sheppo }
1341ae08745Sheppo 
1351ae08745Sheppo /* search for a group whose console is being deleted */
1361ae08745Sheppo static boolean_t
find_clean_cons_group(vntsd_group_t * groupp)1371ae08745Sheppo find_clean_cons_group(vntsd_group_t *groupp)
1381ae08745Sheppo {
1391ae08745Sheppo 	if (groupp->status & VNTSD_GROUP_CLEAN_CONS) {
1401ae08745Sheppo 		return (B_TRUE);
1411ae08745Sheppo 	} else {
1421ae08745Sheppo 		return (B_FALSE);
1431ae08745Sheppo 	}
1441ae08745Sheppo }
1451ae08745Sheppo 
1461ae08745Sheppo /* search for a console that is being deleted */
1471ae08745Sheppo static boolean_t
find_clean_cons(vntsd_cons_t * consp)1481ae08745Sheppo find_clean_cons(vntsd_cons_t *consp)
1491ae08745Sheppo {
1501ae08745Sheppo 	if (consp->status & VNTSD_CONS_DELETED) {
1511ae08745Sheppo 		return (B_TRUE);
1521ae08745Sheppo 	} else {
1531ae08745Sheppo 		return (B_FALSE);
1541ae08745Sheppo 	}
1551ae08745Sheppo }
1561ae08745Sheppo 
1571ae08745Sheppo /* delete a console */
1581ae08745Sheppo void
vntsd_delete_cons(vntsd_t * vntsdp)1591ae08745Sheppo vntsd_delete_cons(vntsd_t *vntsdp)
1601ae08745Sheppo {
1611ae08745Sheppo 	vntsd_group_t *groupp;
1621ae08745Sheppo 	vntsd_cons_t *consp;
1631ae08745Sheppo 
1641ae08745Sheppo 	for (; ; ) {
1651ae08745Sheppo 		/* get the group contains deleted console */
1661ae08745Sheppo 		(void) mutex_lock(&vntsdp->lock);
1671ae08745Sheppo 		groupp = vntsd_que_walk(vntsdp->grouppq,
1681ae08745Sheppo 		    (el_func_t)find_clean_cons_group);
1691ae08745Sheppo 		if (groupp == NULL) {
1701ae08745Sheppo 			/* no more group has console deleted */
1711ae08745Sheppo 			(void) mutex_unlock(&vntsdp->lock);
1721ae08745Sheppo 			return;
1731ae08745Sheppo 		}
1747636cb21Slm 		(void) mutex_lock(&groupp->lock);
1751ae08745Sheppo 		groupp->status &= ~VNTSD_GROUP_CLEAN_CONS;
1767636cb21Slm 		(void) mutex_unlock(&groupp->lock);
1771ae08745Sheppo 		(void) mutex_unlock(&vntsdp->lock);
1781ae08745Sheppo 
1791ae08745Sheppo 		for (; ; ) {
1801ae08745Sheppo 			/* get the console to be deleted */
1811ae08745Sheppo 			(void) mutex_lock(&groupp->lock);
1821ae08745Sheppo 
1834d39be2bSsg 			/* clean up any deleted console in the group */
1844d39be2bSsg 			if (groupp->conspq != NULL) {
1854d39be2bSsg 				consp = vntsd_que_walk(groupp->conspq,
1864d39be2bSsg 				    (el_func_t)find_clean_cons);
1874d39be2bSsg 				if (consp == NULL) {
1884d39be2bSsg 					/* no more cons to delete */
1894d39be2bSsg 					(void) mutex_unlock(&groupp->lock);
1904d39be2bSsg 					break;
1914d39be2bSsg 				}
1924d39be2bSsg 
1934d39be2bSsg 				/* remove console from the group */
1944d39be2bSsg 				(void) vntsd_que_rm(&groupp->conspq, consp);
1954d39be2bSsg 				(void) mutex_unlock(&groupp->lock);
1961ae08745Sheppo 
1974d39be2bSsg 				/* clean up the console */
1984d39be2bSsg 				cleanup_cons(consp);
1994d39be2bSsg 			}
2001ae08745Sheppo 
2011ae08745Sheppo 			/* delete group? */
2024d39be2bSsg 			if (groupp->conspq == NULL) {
2034d39be2bSsg 				/* no more console in the group delete group */
2041ae08745Sheppo 				assert(groupp->vntsd);
2051ae08745Sheppo 
2061ae08745Sheppo 				(void) mutex_lock(&groupp->vntsd->lock);
2071ae08745Sheppo 				(void) vntsd_que_rm(&groupp->vntsd->grouppq,
208*476d5ff7SToomas Soome 				    groupp);
2091ae08745Sheppo 				(void) mutex_unlock(&groupp->vntsd->lock);
2101ae08745Sheppo 
2111ae08745Sheppo 				/* clean up the group */
2121ae08745Sheppo 				vntsd_clean_group(groupp);
2131ae08745Sheppo 				break;
2141ae08745Sheppo 			}
2151ae08745Sheppo 		}
2161ae08745Sheppo 	}
2171ae08745Sheppo }
2181ae08745Sheppo 
2191ae08745Sheppo /* clean up a group */
2201ae08745Sheppo void
vntsd_clean_group(vntsd_group_t * groupp)2211ae08745Sheppo vntsd_clean_group(vntsd_group_t *groupp)
2221ae08745Sheppo {
2231ae08745Sheppo 
2241ae08745Sheppo 	timestruc_t	to;
2251ae08745Sheppo 
2261ae08745Sheppo 	D1(stderr, "t@%d clean_group() group=%s tcp=%lld\n", thr_self(),
2271ae08745Sheppo 	    groupp->group_name, groupp->tcp_port);
2281ae08745Sheppo 
2291ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
2301ae08745Sheppo 
2311ae08745Sheppo 	/* prevent from reentry */
2324d39be2bSsg 	if (groupp->status & VNTSD_GROUP_IN_CLEANUP) {
2331ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
2341ae08745Sheppo 		return;
2351ae08745Sheppo 	}
2364d39be2bSsg 	groupp->status |= VNTSD_GROUP_IN_CLEANUP;
2374d39be2bSsg 
2384d39be2bSsg 	/* mark group waiting for listen thread to exits */
2394d39be2bSsg 	groupp->status |= VNTSD_GROUP_SIG_WAIT;
2401ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
2411ae08745Sheppo 
2423af08d82Slm 	vntsd_free_que(&groupp->conspq, (clean_func_t)cleanup_cons);
2433af08d82Slm 
2444d39be2bSsg 	(void) mutex_lock(&groupp->lock);
2451ae08745Sheppo 	/* walk through no cons client queue */
2461ae08745Sheppo 	while (groupp->no_cons_clientpq != NULL) {
2471ae08745Sheppo 		(void) vntsd_que_walk(groupp->no_cons_clientpq,
2481ae08745Sheppo 		    (el_func_t)vntsd_notify_client_cons_del);
2491ae08745Sheppo 		to.tv_sec = VNTSD_CV_WAIT_DELTIME;
2501ae08745Sheppo 		to.tv_nsec = 0;
2511ae08745Sheppo 		(void) cond_reltimedwait(&groupp->cvp, &groupp->lock, &to);
2521ae08745Sheppo 	}
2531ae08745Sheppo 
2544d39be2bSsg 	/* waiting for listen thread to exit */
2551ae08745Sheppo 	while (groupp->status & VNTSD_GROUP_SIG_WAIT) {
2564d39be2bSsg 		/* signal listen thread to exit  */
2571ae08745Sheppo 		(void) thr_kill(groupp->listen_tid, SIGUSR1);
2581ae08745Sheppo 		to.tv_sec = VNTSD_CV_WAIT_DELTIME;
2591ae08745Sheppo 		to.tv_nsec = 0;
2601ae08745Sheppo 		/* wait listen thread to exit  */
2611ae08745Sheppo 		(void) cond_reltimedwait(&groupp->cvp, &groupp->lock, &to);
2621ae08745Sheppo 	}
2631ae08745Sheppo 
2641ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
2651ae08745Sheppo 	(void) thr_join(groupp->listen_tid, NULL, NULL);
2661ae08745Sheppo 	/* free group */
2674d39be2bSsg 	free_group(groupp);
2681ae08745Sheppo }
2691ae08745Sheppo 
2701ae08745Sheppo /* allocate and initialize console structure */
2711ae08745Sheppo static vntsd_cons_t *
alloc_cons(vntsd_group_t * groupp,vcc_console_t * consolep)2721ae08745Sheppo alloc_cons(vntsd_group_t *groupp, vcc_console_t *consolep)
2731ae08745Sheppo {
2741ae08745Sheppo 	vntsd_cons_t *consp;
2751ae08745Sheppo 	int	rv;
2761ae08745Sheppo 
2771ae08745Sheppo 	/* allocate console */
2781ae08745Sheppo 	consp = (vntsd_cons_t *)malloc(sizeof (vntsd_cons_t));
2791ae08745Sheppo 	if (consp == NULL) {
2801ae08745Sheppo 		vntsd_log(VNTSD_ERR_NO_MEM, "alloc_cons");
2811ae08745Sheppo 		return (NULL);
2821ae08745Sheppo 	}
2831ae08745Sheppo 
2841ae08745Sheppo 	/* intialize console */
2851ae08745Sheppo 	bzero(consp, sizeof (vntsd_cons_t));
2861ae08745Sheppo 
2871ae08745Sheppo 	(void) mutex_init(&consp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL);
2881ae08745Sheppo 	(void) cond_init(&consp->cvp, USYNC_THREAD, NULL);
2891ae08745Sheppo 
2901ae08745Sheppo 	consp->cons_no = consolep->cons_no;
2911ae08745Sheppo 	(void) strlcpy(consp->domain_name, consolep->domain_name, MAXPATHLEN);
2921ae08745Sheppo 	(void) strlcpy(consp->dev_name, consolep->dev_name, MAXPATHLEN);
2931ae08745Sheppo 	consp->wr_tid = (thread_t)-1;
2944d39be2bSsg 	consp->vcc_fd = -1;
2951ae08745Sheppo 
2961ae08745Sheppo 	/* join the group */
2971ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
2981ae08745Sheppo 
2991ae08745Sheppo 	if ((rv = vntsd_que_append(&groupp->conspq, consp)) !=
3001ae08745Sheppo 	    VNTSD_SUCCESS) {
3011ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
3021ae08745Sheppo 		vntsd_log(rv, "alloc_cons");
3031ae08745Sheppo 		free_cons(consp);
3041ae08745Sheppo 		return (NULL);
3051ae08745Sheppo 	}
3061ae08745Sheppo 	groupp->num_cons++;
3071ae08745Sheppo 	consp->group = groupp;
3081ae08745Sheppo 
3091ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
3101ae08745Sheppo 
3111ae08745Sheppo 	D1(stderr, "t@%d alloc_cons@%d %s %s\n", thr_self(),
3121ae08745Sheppo 	    consp->cons_no, consp->domain_name, consp->dev_name);
3131ae08745Sheppo 
3141ae08745Sheppo 	return (consp);
3151ae08745Sheppo }
3161ae08745Sheppo 
3171ae08745Sheppo /* compare tcp with group->tcp */
3181ae08745Sheppo static boolean_t
grp_by_tcp(vntsd_group_t * groupp,uint64_t * tcp_port)3191ae08745Sheppo grp_by_tcp(vntsd_group_t *groupp, uint64_t *tcp_port)
3201ae08745Sheppo {
3211ae08745Sheppo 	assert(groupp);
3221ae08745Sheppo 	assert(tcp_port);
3231ae08745Sheppo 	return (groupp->tcp_port == *tcp_port);
3241ae08745Sheppo }
3251ae08745Sheppo 
3261ae08745Sheppo /* allocate and initialize group */
3271ae08745Sheppo static vntsd_group_t *
alloc_group(vntsd_t * vntsdp,char * group_name,uint64_t tcp_port)3281ae08745Sheppo alloc_group(vntsd_t *vntsdp, char *group_name, uint64_t tcp_port)
3291ae08745Sheppo {
3301ae08745Sheppo 	vntsd_group_t *groupp;
3311ae08745Sheppo 
3321ae08745Sheppo 	/* allocate group */
3331ae08745Sheppo 	groupp = (vntsd_group_t *)malloc(sizeof (vntsd_group_t));
3341ae08745Sheppo 	if (groupp == NULL) {
3351ae08745Sheppo 		vntsd_log(VNTSD_ERR_NO_MEM, "alloc_group");
3361ae08745Sheppo 		return (NULL);
3371ae08745Sheppo 	}
3381ae08745Sheppo 
3391ae08745Sheppo 	/* initialize group */
3401ae08745Sheppo 	bzero(groupp, sizeof (vntsd_group_t));
3411ae08745Sheppo 
3421ae08745Sheppo 	(void) mutex_init(&groupp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL);
3431ae08745Sheppo 	(void) cond_init(&groupp->cvp, USYNC_THREAD, NULL);
3441ae08745Sheppo 
3451ae08745Sheppo 	if (group_name != NULL) {
3461ae08745Sheppo 		(void) memcpy(groupp->group_name, group_name, MAXPATHLEN);
3471ae08745Sheppo 	}
3481ae08745Sheppo 
3491ae08745Sheppo 	groupp->tcp_port = tcp_port;
3501ae08745Sheppo 	groupp->listen_tid = (thread_t)-1;
3514d39be2bSsg 	groupp->sockfd = -1;
3521ae08745Sheppo 	groupp->vntsd = vntsdp;
3531ae08745Sheppo 
3541ae08745Sheppo 	D1(stderr, "t@%d alloc_group@%lld:%s\n", thr_self(), groupp->tcp_port,
3551ae08745Sheppo 	    groupp->group_name);
3561ae08745Sheppo 
3571ae08745Sheppo 	return (groupp);
3581ae08745Sheppo }
359