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