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
smb_thread_entry_point(smb_thread_t * thread)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
smb_thread_init(smb_thread_t * thread,char * name,smb_thread_ep_t ep,void * ep_arg,pri_t pri,smb_server_t * sv)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
smb_thread_destroy(smb_thread_t * thread)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
smb_thread_start(smb_thread_t * sth)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
smb_thread_stop(smb_thread_t * thread)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
smb_thread_signal(smb_thread_t * thread)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
smb_thread_continue(smb_thread_t * thread)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
smb_thread_continue_nowait(smb_thread_t * thread)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
smb_thread_continue_timedwait(smb_thread_t * thread,int seconds)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
smb_thread_continue_timedwait_locked(smb_thread_t * thread,int ticks)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