xref: /openbsd-src/sys/kern/kern_subr.c (revision 54f690d2b51fe3791beab539a1014f978081139b)
1 /*	$OpenBSD: kern_subr.c,v 1.29 2004/11/28 02:11:33 deraadt Exp $	*/
2 /*	$NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1991, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  * (c) UNIX System Laboratories, Inc.
8  * All or some portions of this file are derived from material licensed
9  * to the University of California by American Telephone and Telegraph
10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11  * the permission of UNIX System Laboratories, Inc.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)kern_subr.c	8.3 (Berkeley) 1/21/94
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/proc.h>
43 #include <sys/sched.h>
44 #include <sys/malloc.h>
45 #include <sys/queue.h>
46 #include <sys/kernel.h>
47 #include <sys/resourcevar.h>
48 
49 int
50 uiomove(cp, n, uio)
51 	register void *cp;
52 	register int n;
53 	register struct uio *uio;
54 {
55 	register struct iovec *iov;
56 	u_int cnt;
57 	int error = 0;
58 	struct proc *p;
59 
60 	p = uio->uio_procp;
61 
62 #ifdef DIAGNOSTIC
63 	if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
64 		panic("uiomove: mode");
65 	if (uio->uio_segflg == UIO_USERSPACE && p != curproc)
66 		panic("uiomove: proc");
67 #endif
68 	while (n > 0 && uio->uio_resid) {
69 		iov = uio->uio_iov;
70 		cnt = iov->iov_len;
71 		if (cnt == 0) {
72 			uio->uio_iov++;
73 			uio->uio_iovcnt--;
74 			continue;
75 		}
76 		if (cnt > n)
77 			cnt = n;
78 		switch (uio->uio_segflg) {
79 
80 		case UIO_USERSPACE:
81 #ifdef __HAVE_CPUINFO
82 			if (curcpu()->ci_schedstate.spc_schedflags &
83 			    SPCF_SHOULDYIELD)
84 #else
85 			if (p->p_schedflags & PSCHED_SHOULDYIELD)
86 #endif
87 				preempt(NULL);
88 			if (uio->uio_rw == UIO_READ)
89 				error = copyout(cp, iov->iov_base, cnt);
90 			else
91 				error = copyin(iov->iov_base, cp, cnt);
92 			if (error)
93 				return (error);
94 			break;
95 
96 		case UIO_SYSSPACE:
97 			if (uio->uio_rw == UIO_READ)
98 				error = kcopy(cp, iov->iov_base, cnt);
99 			else
100 				error = kcopy(iov->iov_base, cp, cnt);
101 			if (error)
102 				return(error);
103 		}
104 		iov->iov_base = (caddr_t)iov->iov_base + cnt;
105 		iov->iov_len -= cnt;
106 		uio->uio_resid -= cnt;
107 		uio->uio_offset += cnt;
108 		cp = (caddr_t)cp + cnt;
109 		n -= cnt;
110 	}
111 	return (error);
112 }
113 
114 /*
115  * Give next character to user as result of read.
116  */
117 int
118 ureadc(c, uio)
119 	register int c;
120 	register struct uio *uio;
121 {
122 	register struct iovec *iov;
123 
124 	if (uio->uio_resid == 0)
125 #ifdef DIAGNOSTIC
126 		panic("ureadc: zero resid");
127 #else
128 		return (EINVAL);
129 #endif
130 again:
131 	if (uio->uio_iovcnt <= 0)
132 #ifdef DIAGNOSTIC
133 		panic("ureadc: non-positive iovcnt");
134 #else
135 		return (EINVAL);
136 #endif
137 	iov = uio->uio_iov;
138 	if (iov->iov_len <= 0) {
139 		uio->uio_iovcnt--;
140 		uio->uio_iov++;
141 		goto again;
142 	}
143 	switch (uio->uio_segflg) {
144 
145 	case UIO_USERSPACE:
146 	{
147 		char tmp = c;
148 
149 		if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0)
150 			return (EFAULT);
151 	}
152 		break;
153 
154 	case UIO_SYSSPACE:
155 		*(char *)iov->iov_base = c;
156 		break;
157 	}
158 	iov->iov_base = (caddr_t)iov->iov_base + 1;
159 	iov->iov_len--;
160 	uio->uio_resid--;
161 	uio->uio_offset++;
162 	return (0);
163 }
164 
165 /*
166  * General routine to allocate a hash table.
167  */
168 void *
169 hashinit(elements, type, flags, hashmask)
170 	int elements, type, flags;
171 	u_long *hashmask;
172 {
173 	u_long hashsize, i;
174 	LIST_HEAD(generic, generic) *hashtbl;
175 
176 	if (elements <= 0)
177 		panic("hashinit: bad cnt");
178 	for (hashsize = 1; hashsize < elements; hashsize <<= 1)
179 		continue;
180 	hashtbl = malloc(hashsize * sizeof(*hashtbl), type, flags);
181 	if (hashtbl == NULL)
182 		return NULL;
183 	for (i = 0; i < hashsize; i++)
184 		LIST_INIT(&hashtbl[i]);
185 	*hashmask = hashsize - 1;
186 	return (hashtbl);
187 }
188 
189 /*
190  * "Shutdown/startup hook" types, functions, and variables.
191  */
192 
193 struct hook_desc_head startuphook_list =
194     TAILQ_HEAD_INITIALIZER(startuphook_list);
195 struct hook_desc_head shutdownhook_list =
196     TAILQ_HEAD_INITIALIZER(shutdownhook_list);
197 struct hook_desc_head mountroothook_list =
198     TAILQ_HEAD_INITIALIZER(mountroothook_list);
199 
200 void *
201 hook_establish(head, tail, fn, arg)
202 	struct hook_desc_head *head;
203 	int tail;
204 	void (*fn)(void *);
205 	void *arg;
206 {
207 	struct hook_desc *hdp;
208 
209 	hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT);
210 	if (hdp == NULL)
211 		return (NULL);
212 
213 	hdp->hd_fn = fn;
214 	hdp->hd_arg = arg;
215 	if (tail)
216 		TAILQ_INSERT_TAIL(head, hdp, hd_list);
217 	else
218 		TAILQ_INSERT_HEAD(head, hdp, hd_list);
219 
220 	return (hdp);
221 }
222 
223 void
224 hook_disestablish(head, vhook)
225 	struct hook_desc_head *head;
226 	void *vhook;
227 {
228 	struct hook_desc *hdp;
229 
230 #ifdef DIAGNOSTIC
231 	for (hdp = TAILQ_FIRST(head); hdp != NULL;
232 	    hdp = TAILQ_NEXT(hdp, hd_list))
233                 if (hdp == vhook)
234 			break;
235 	if (hdp == NULL)
236 		panic("hook_disestablish: hook not established");
237 #endif
238 	hdp = vhook;
239 	TAILQ_REMOVE(head, hdp, hd_list);
240 	free(hdp, M_DEVBUF);
241 }
242 
243 /*
244  * Run hooks.  Startup hooks are invoked right after scheduler_start but
245  * before root is mounted.  Shutdown hooks are invoked immediately before the
246  * system is halted or rebooted, i.e. after file systems unmounted,
247  * after crash dump done, etc.
248  */
249 void
250 dohooks(struct hook_desc_head *head, int flags)
251 {
252 	struct hook_desc *hdp;
253 
254 	if ((flags & HOOK_REMOVE) == 0) {
255 		TAILQ_FOREACH(hdp, head, hd_list) {
256 			(*hdp->hd_fn)(hdp->hd_arg);
257 		}
258 	} else {
259 		while ((hdp = TAILQ_FIRST(head)) != NULL) {
260 			TAILQ_REMOVE(head, hdp, hd_list);
261 			(*hdp->hd_fn)(hdp->hd_arg);
262 			if ((flags & HOOK_FREE) != 0)
263 				free(hdp, M_DEVBUF);
264 		}
265 	}
266 }
267 
268 /*
269  * "Power hook" types, functions, and variables.
270  */
271 
272 struct powerhook_desc {
273 	CIRCLEQ_ENTRY(powerhook_desc) sfd_list;
274 	void	(*sfd_fn)(int, void *);
275 	void	*sfd_arg;
276 };
277 
278 CIRCLEQ_HEAD(, powerhook_desc) powerhook_list =
279 	CIRCLEQ_HEAD_INITIALIZER(powerhook_list);
280 
281 void *
282 powerhook_establish(fn, arg)
283 	void (*fn)(int, void *);
284 	void *arg;
285 {
286 	struct powerhook_desc *ndp;
287 
288 	ndp = (struct powerhook_desc *)
289 	    malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
290 	if (ndp == NULL)
291 		return NULL;
292 
293 	ndp->sfd_fn = fn;
294 	ndp->sfd_arg = arg;
295 	CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
296 
297 	return (ndp);
298 }
299 
300 void
301 powerhook_disestablish(vhook)
302 	void *vhook;
303 {
304 #ifdef DIAGNOSTIC
305 	struct powerhook_desc *dp;
306 
307 	CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list)
308                 if (dp == vhook)
309 			break;
310 	if (dp == NULL)
311 		panic("powerhook_disestablish: hook not established");
312 #endif
313 
314 	CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
315 		sfd_list);
316 	free(vhook, M_DEVBUF);
317 }
318 
319 /*
320  * Run power hooks.
321  */
322 void
323 dopowerhooks(why)
324 	int why;
325 {
326 	struct powerhook_desc *dp;
327 	int s;
328 
329 	s = splhigh();
330 	if (why == PWR_RESUME) {
331 		CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) {
332 			(*dp->sfd_fn)(why, dp->sfd_arg);
333 		}
334 	} else {
335 		CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) {
336 			(*dp->sfd_fn)(why, dp->sfd_arg);
337 		}
338 	}
339 	splx(s);
340 }
341