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