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