xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_thread.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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
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
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
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
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
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
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
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
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
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
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