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 #include "sysevent_signal.h"
40
41 extern void syseventd_err_print(char *, ...);
42
43 struct event_list {
44 nvlist_t *ev;
45 struct event_list *next;
46 };
47
48 static rcm_handle_t *rcm_hdl = NULL;
49 static boolean_t dl_exiting;
50 static thread_t dl_notify_tid;
51 static mutex_t dl_mx;
52 static cond_t dl_cv;
53 static struct event_list *dl_events;
54
55 /* ARGSUSED */
56 static void *
datalink_notify_thread(void * arg)57 datalink_notify_thread(void *arg)
58 {
59 struct event_list *tmp_events, *ep;
60
61 (void) mutex_lock(&dl_mx);
62
63 while (! dl_exiting || dl_events != NULL) {
64 if (dl_events == NULL) {
65 (void) cond_wait(&dl_cv, &dl_mx);
66 continue;
67 }
68
69 tmp_events = dl_events;
70 dl_events = NULL;
71
72 (void) mutex_unlock(&dl_mx);
73
74 while (tmp_events != NULL) {
75 struct sigaction cbuf, dfl;
76
77 /*
78 * Ignore SIGCLD for the
79 * duration of the rcm_notify_event call.
80 */
81 (void) memset(&dfl, 0, sizeof (dfl));
82 dfl.sa_handler = SIG_IGN;
83 (void) sigaction(SIGCHLD, &dfl, &cbuf);
84
85 /*
86 * Send the PHYSLINK_NEW event to network_rcm to update
87 * the network devices cache accordingly.
88 */
89 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_PHYSLINK_NEW,
90 0, tmp_events->ev, NULL) != RCM_SUCCESS)
91 syseventd_err_print("datalink_mod: Can not "
92 "notify event: %s\n", strerror(errno));
93
94 (void) sigaction(SIGCHLD, &cbuf, NULL);
95 ep = tmp_events;
96 tmp_events = tmp_events->next;
97 nvlist_free(ep->ev);
98 free(ep);
99 }
100
101 (void) mutex_lock(&dl_mx);
102 }
103
104 (void) mutex_unlock(&dl_mx);
105
106 return (NULL);
107 }
108
109 /*ARGSUSED*/
110 static int
datalink_deliver_event(sysevent_t * ev,int unused)111 datalink_deliver_event(sysevent_t *ev, int unused)
112 {
113 const char *class = sysevent_get_class_name(ev);
114 const char *subclass = sysevent_get_subclass_name(ev);
115 nvlist_t *nvl;
116 struct event_list *newp, **elpp;
117
118 if (strcmp(class, EC_DATALINK) != 0 ||
119 strcmp(subclass, ESC_DATALINK_PHYS_ADD) != 0) {
120 return (0);
121 }
122
123 if (sysevent_get_attr_list(ev, &nvl) != 0)
124 return (EINVAL);
125
126 /*
127 * rcm_notify_event() needs to be called asynchronously otherwise when
128 * sysevent queue is full, deadlock will happen.
129 */
130 if ((newp = malloc(sizeof (struct event_list))) == NULL)
131 return (ENOMEM);
132
133 newp->ev = nvl;
134 newp->next = NULL;
135
136 /*
137 * queue up at the end of the event list and signal notify_thread to
138 * process it.
139 */
140 (void) mutex_lock(&dl_mx);
141 elpp = &dl_events;
142 while (*elpp != NULL)
143 elpp = &(*elpp)->next;
144 *elpp = newp;
145 (void) cond_signal(&dl_cv);
146 (void) mutex_unlock(&dl_mx);
147
148 return (0);
149 }
150
151 static struct slm_mod_ops datalink_mod_ops = {
152 SE_MAJOR_VERSION,
153 SE_MINOR_VERSION,
154 SE_MAX_RETRY_LIMIT,
155 datalink_deliver_event
156 };
157
158 struct slm_mod_ops *
slm_init()159 slm_init()
160 {
161 dl_events = NULL;
162 dl_exiting = B_FALSE;
163
164 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS)
165 return (NULL);
166
167 if (thr_create(NULL, 0, datalink_notify_thread, NULL, 0,
168 &dl_notify_tid) != 0) {
169 (void) rcm_free_handle(rcm_hdl);
170 return (NULL);
171 }
172
173 (void) mutex_init(&dl_mx, USYNC_THREAD, NULL);
174 (void) cond_init(&dl_cv, USYNC_THREAD, NULL);
175
176 return (&datalink_mod_ops);
177 }
178
179 void
slm_fini()180 slm_fini()
181 {
182 (void) mutex_lock(&dl_mx);
183 dl_exiting = B_TRUE;
184 (void) cond_signal(&dl_cv);
185 (void) mutex_unlock(&dl_mx);
186 (void) thr_join(dl_notify_tid, NULL, NULL);
187
188 (void) mutex_destroy(&dl_mx);
189 (void) cond_destroy(&dl_cv);
190 (void) rcm_free_handle(rcm_hdl);
191 rcm_hdl = NULL;
192 }
193