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