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