xref: /illumos-gate/usr/src/cmd/syseventd/modules/datalink_mod/datalink_mod.c (revision 4dc927470baa43bc10074a7a7ae03610f3741e09)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * datalink syseventd module.
28  *
29  * The purpose of this module is to identify all datalink related events,
30  * and react accordingly.
31  */
32 
33 #include <errno.h>
34 #include <sys/sysevent/eventdefs.h>
35 #include <string.h>
36 #include <libnvpair.h>
37 #include <librcm.h>
38 #include <libsysevent.h>
39 
40 extern void syseventd_err_print(char *, ...);
41 
42 struct event_list {
43 	nvlist_t *ev;
44 	struct event_list *next;
45 };
46 
47 static rcm_handle_t *rcm_hdl = NULL;
48 static boolean_t dl_exiting;
49 static thread_t dl_notify_tid;
50 static mutex_t dl_mx;
51 static cond_t dl_cv;
52 static struct event_list *dl_events;
53 
54 /* ARGSUSED */
55 static void *
56 datalink_notify_thread(void *arg)
57 {
58 	struct event_list *tmp_events, *ep;
59 
60 	(void) mutex_lock(&dl_mx);
61 
62 	while (! dl_exiting || dl_events != NULL) {
63 		if (dl_events == NULL) {
64 			(void) cond_wait(&dl_cv, &dl_mx);
65 			continue;
66 		}
67 
68 		tmp_events = dl_events;
69 		dl_events = NULL;
70 
71 		(void) mutex_unlock(&dl_mx);
72 
73 		while (tmp_events != NULL) {
74 			/*
75 			 * Send the PHYSLINK_NEW event to network_rcm to update
76 			 * the network devices cache accordingly.
77 			 */
78 			if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_PHYSLINK_NEW,
79 			    0, tmp_events->ev, NULL) != RCM_SUCCESS)
80 				syseventd_err_print("datalink_mod: Can not"
81 				    "notify event: %s\n", strerror(errno));
82 
83 			ep = tmp_events;
84 			tmp_events = tmp_events->next;
85 			nvlist_free(ep->ev);
86 			free(ep);
87 		}
88 
89 		(void) mutex_lock(&dl_mx);
90 	}
91 
92 	(void) mutex_unlock(&dl_mx);
93 
94 	return (NULL);
95 }
96 
97 /*ARGSUSED*/
98 static int
99 datalink_deliver_event(sysevent_t *ev, int unused)
100 {
101 	const char *class = sysevent_get_class_name(ev);
102 	const char *subclass = sysevent_get_subclass_name(ev);
103 	nvlist_t *nvl;
104 	struct event_list *newp, **elpp;
105 
106 	if (strcmp(class, EC_DATALINK) != 0 ||
107 	    strcmp(subclass, ESC_DATALINK_PHYS_ADD) != 0) {
108 		return (0);
109 	}
110 
111 	if (sysevent_get_attr_list(ev, &nvl) != 0)
112 		return (EINVAL);
113 
114 	/*
115 	 * rcm_notify_event() needs to be called asynchronously otherwise when
116 	 * sysevent queue is full, deadlock will happen.
117 	 */
118 	if ((newp = malloc(sizeof (struct event_list))) == NULL)
119 		return (ENOMEM);
120 
121 	newp->ev = nvl;
122 	newp->next = NULL;
123 
124 	/*
125 	 * queue up at the end of the event list and signal notify_thread to
126 	 * process it.
127 	 */
128 	(void) mutex_lock(&dl_mx);
129 	elpp = &dl_events;
130 	while (*elpp !=  NULL)
131 		elpp = &(*elpp)->next;
132 	*elpp = newp;
133 	(void) cond_signal(&dl_cv);
134 	(void) mutex_unlock(&dl_mx);
135 
136 	return (0);
137 }
138 
139 static struct slm_mod_ops datalink_mod_ops = {
140 	SE_MAJOR_VERSION,
141 	SE_MINOR_VERSION,
142 	SE_MAX_RETRY_LIMIT,
143 	datalink_deliver_event
144 };
145 
146 struct slm_mod_ops *
147 slm_init()
148 {
149 	dl_events = NULL;
150 	dl_exiting = B_FALSE;
151 
152 	if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS)
153 		return (NULL);
154 
155 	if (thr_create(NULL, 0,  datalink_notify_thread, NULL, 0,
156 	    &dl_notify_tid) != 0) {
157 		(void) rcm_free_handle(rcm_hdl);
158 		return (NULL);
159 	}
160 
161 	(void) mutex_init(&dl_mx, USYNC_THREAD, NULL);
162 	(void) cond_init(&dl_cv, USYNC_THREAD, NULL);
163 
164 	return (&datalink_mod_ops);
165 }
166 
167 void
168 slm_fini()
169 {
170 	(void) mutex_lock(&dl_mx);
171 	dl_exiting = B_TRUE;
172 	(void) cond_signal(&dl_cv);
173 	(void) mutex_unlock(&dl_mx);
174 	(void) thr_join(dl_notify_tid, NULL, NULL);
175 
176 	(void) mutex_destroy(&dl_mx);
177 	(void) cond_destroy(&dl_cv);
178 	(void) rcm_free_handle(rcm_hdl);
179 	rcm_hdl = NULL;
180 }
181