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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/types.h> 29 #include <sys/tzfile.h> 30 #include <sys/atomic.h> 31 #include <sys/kidmap.h> 32 #include <sys/time.h> 33 #include <sys/spl.h> 34 #include <sys/random.h> 35 #include <smbsrv/smb_kproto.h> 36 #include <smbsrv/smb_fsops.h> 37 #include <smbsrv/smbinfo.h> 38 #include <smbsrv/smb_xdr.h> 39 #include <smbsrv/smb_vops.h> 40 #include <smbsrv/smb_idmap.h> 41 42 #include <sys/sid.h> 43 #include <sys/priv_names.h> 44 45 #ifdef _FAKE_KERNEL 46 #define THR_TO_DID(t) ((kt_did_t)(uintptr_t)t) 47 #else 48 #define THR_TO_DID(t) (t->t_did) 49 #endif 50 51 static boolean_t smb_thread_continue_timedwait_locked(smb_thread_t *, int); 52 53 /* 54 * smb_thread_entry_point 55 * 56 * Common entry point for all the threads created through smb_thread_start. 57 * The state of the thread is set to "running" at the beginning and moved to 58 * "exiting" just before calling thread_exit(). The condition variable is 59 * also signaled. 60 */ 61 static void 62 smb_thread_entry_point( 63 smb_thread_t *thread) 64 { 65 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 66 mutex_enter(&thread->sth_mtx); 67 ASSERT(thread->sth_state == SMB_THREAD_STATE_STARTING); 68 69 if (!thread->sth_kill) { 70 thread->sth_state = SMB_THREAD_STATE_RUNNING; 71 cv_signal(&thread->sth_cv); 72 mutex_exit(&thread->sth_mtx); 73 74 /* Run the real thread entry point. */ 75 thread->sth_ep(thread, thread->sth_ep_arg); 76 77 mutex_enter(&thread->sth_mtx); 78 } 79 /* 80 * It's tempting to clear sth_did here too, but don't. 81 * That's needed in thread_join(). 82 */ 83 thread->sth_th = NULL; 84 thread->sth_state = SMB_THREAD_STATE_EXITING; 85 cv_broadcast(&thread->sth_cv); 86 mutex_exit(&thread->sth_mtx); 87 zthread_exit(); 88 } 89 90 /* 91 * smb_thread_init 92 */ 93 void 94 smb_thread_init( 95 smb_thread_t *thread, 96 char *name, 97 smb_thread_ep_t ep, 98 void *ep_arg, 99 pri_t pri) 100 { 101 ASSERT(thread->sth_magic != SMB_THREAD_MAGIC); 102 103 bzero(thread, sizeof (*thread)); 104 105 (void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name)); 106 thread->sth_ep = ep; 107 thread->sth_ep_arg = ep_arg; 108 thread->sth_state = SMB_THREAD_STATE_EXITED; 109 thread->sth_pri = pri; 110 mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL); 111 cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL); 112 thread->sth_magic = SMB_THREAD_MAGIC; 113 } 114 115 /* 116 * smb_thread_destroy 117 */ 118 void 119 smb_thread_destroy( 120 smb_thread_t *thread) 121 { 122 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 123 ASSERT(thread->sth_state == SMB_THREAD_STATE_EXITED); 124 thread->sth_magic = 0; 125 mutex_destroy(&thread->sth_mtx); 126 cv_destroy(&thread->sth_cv); 127 } 128 129 /* 130 * smb_thread_start 131 * 132 * This function starts a thread with the parameters provided. It waits until 133 * the state of the thread has been moved to running. 134 */ 135 /*ARGSUSED*/ 136 int 137 smb_thread_start( 138 smb_thread_t *thread) 139 { 140 int rc = 0; 141 kthread_t *tmpthread; 142 143 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 144 145 mutex_enter(&thread->sth_mtx); 146 switch (thread->sth_state) { 147 case SMB_THREAD_STATE_EXITED: 148 thread->sth_state = SMB_THREAD_STATE_STARTING; 149 mutex_exit(&thread->sth_mtx); 150 tmpthread = zthread_create(NULL, 0, smb_thread_entry_point, 151 thread, 0, thread->sth_pri); 152 ASSERT(tmpthread != NULL); 153 mutex_enter(&thread->sth_mtx); 154 thread->sth_th = tmpthread; 155 thread->sth_did = THR_TO_DID(tmpthread); 156 while (thread->sth_state == SMB_THREAD_STATE_STARTING) 157 cv_wait(&thread->sth_cv, &thread->sth_mtx); 158 if (thread->sth_state != SMB_THREAD_STATE_RUNNING) 159 rc = -1; 160 break; 161 default: 162 ASSERT(0); 163 rc = -1; 164 break; 165 } 166 mutex_exit(&thread->sth_mtx); 167 return (rc); 168 } 169 170 /* 171 * smb_thread_stop 172 * 173 * This function signals a thread to kill itself and waits until the "exiting" 174 * state has been reached. 175 */ 176 void 177 smb_thread_stop(smb_thread_t *thread) 178 { 179 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 180 181 mutex_enter(&thread->sth_mtx); 182 switch (thread->sth_state) { 183 case SMB_THREAD_STATE_RUNNING: 184 case SMB_THREAD_STATE_STARTING: 185 if (!thread->sth_kill) { 186 thread->sth_kill = B_TRUE; 187 cv_broadcast(&thread->sth_cv); 188 while (thread->sth_state != SMB_THREAD_STATE_EXITING) 189 cv_wait(&thread->sth_cv, &thread->sth_mtx); 190 mutex_exit(&thread->sth_mtx); 191 thread_join(thread->sth_did); 192 mutex_enter(&thread->sth_mtx); 193 thread->sth_state = SMB_THREAD_STATE_EXITED; 194 thread->sth_did = 0; 195 thread->sth_kill = B_FALSE; 196 cv_broadcast(&thread->sth_cv); 197 break; 198 } 199 /* FALLTHROUGH */ 200 201 case SMB_THREAD_STATE_EXITING: 202 if (thread->sth_kill) { 203 while (thread->sth_state != SMB_THREAD_STATE_EXITED) 204 cv_wait(&thread->sth_cv, &thread->sth_mtx); 205 } else { 206 thread->sth_state = SMB_THREAD_STATE_EXITED; 207 thread->sth_did = 0; 208 } 209 break; 210 211 case SMB_THREAD_STATE_EXITED: 212 break; 213 214 default: 215 ASSERT(0); 216 break; 217 } 218 mutex_exit(&thread->sth_mtx); 219 } 220 221 /* 222 * smb_thread_signal 223 * 224 * This function signals a thread. 225 */ 226 void 227 smb_thread_signal(smb_thread_t *thread) 228 { 229 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 230 231 mutex_enter(&thread->sth_mtx); 232 switch (thread->sth_state) { 233 case SMB_THREAD_STATE_RUNNING: 234 cv_signal(&thread->sth_cv); 235 break; 236 237 default: 238 break; 239 } 240 mutex_exit(&thread->sth_mtx); 241 } 242 243 boolean_t 244 smb_thread_continue(smb_thread_t *thread) 245 { 246 boolean_t result; 247 248 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 249 250 mutex_enter(&thread->sth_mtx); 251 result = smb_thread_continue_timedwait_locked(thread, 0); 252 mutex_exit(&thread->sth_mtx); 253 254 return (result); 255 } 256 257 boolean_t 258 smb_thread_continue_nowait(smb_thread_t *thread) 259 { 260 boolean_t result; 261 262 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 263 264 mutex_enter(&thread->sth_mtx); 265 /* 266 * Setting ticks=-1 requests a non-blocking check. We will 267 * still block if the thread is in "suspend" state. 268 */ 269 result = smb_thread_continue_timedwait_locked(thread, -1); 270 mutex_exit(&thread->sth_mtx); 271 272 return (result); 273 } 274 275 boolean_t 276 smb_thread_continue_timedwait(smb_thread_t *thread, int seconds) 277 { 278 boolean_t result; 279 280 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 281 282 mutex_enter(&thread->sth_mtx); 283 result = smb_thread_continue_timedwait_locked(thread, 284 SEC_TO_TICK(seconds)); 285 mutex_exit(&thread->sth_mtx); 286 287 return (result); 288 } 289 290 /* 291 * smb_thread_continue_timedwait_locked 292 * 293 * Internal only. Ticks==-1 means don't block, Ticks == 0 means wait 294 * indefinitely 295 */ 296 static boolean_t 297 smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks) 298 { 299 boolean_t result; 300 301 /* -1 means don't block */ 302 if (ticks != -1 && !thread->sth_kill) { 303 if (ticks == 0) { 304 cv_wait(&thread->sth_cv, &thread->sth_mtx); 305 } else { 306 (void) cv_reltimedwait(&thread->sth_cv, 307 &thread->sth_mtx, (clock_t)ticks, TR_CLOCK_TICK); 308 } 309 } 310 result = (thread->sth_kill == 0); 311 312 return (result); 313 } 314