1 /* $OpenBSD: kern_subr.c,v 1.26 2003/10/31 11:10:41 markus 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/malloc.h>
44 #include <sys/queue.h>
45 #include <sys/kernel.h>
46 #include <sys/resourcevar.h>
47
48 int
uiomove(cp,n,uio)49 uiomove(cp, n, uio)
50 register void *cp;
51 register int n;
52 register struct uio *uio;
53 {
54 register struct iovec *iov;
55 u_int cnt;
56 int error = 0;
57 struct proc *p;
58
59 p = uio->uio_procp;
60
61 #ifdef DIAGNOSTIC
62 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
63 panic("uiomove: mode");
64 if (uio->uio_segflg == UIO_USERSPACE && p != curproc)
65 panic("uiomove: proc");
66 #endif
67 while (n > 0 && uio->uio_resid) {
68 iov = uio->uio_iov;
69 cnt = iov->iov_len;
70 if (cnt == 0) {
71 uio->uio_iov++;
72 uio->uio_iovcnt--;
73 continue;
74 }
75 if (cnt > n)
76 cnt = n;
77 switch (uio->uio_segflg) {
78
79 case UIO_USERSPACE:
80 if (p->p_schedflags & PSCHED_SHOULDYIELD)
81 preempt(NULL);
82 if (uio->uio_rw == UIO_READ)
83 error = copyout(cp, iov->iov_base, cnt);
84 else
85 error = copyin(iov->iov_base, cp, cnt);
86 if (error)
87 return (error);
88 break;
89
90 case UIO_SYSSPACE:
91 if (uio->uio_rw == UIO_READ)
92 error = kcopy(cp, iov->iov_base, cnt);
93 else
94 error = kcopy(iov->iov_base, cp, cnt);
95 if (error)
96 return(error);
97 }
98 iov->iov_base = (caddr_t)iov->iov_base + cnt;
99 iov->iov_len -= cnt;
100 uio->uio_resid -= cnt;
101 uio->uio_offset += cnt;
102 cp = (caddr_t)cp + cnt;
103 n -= cnt;
104 }
105 return (error);
106 }
107
108 /*
109 * Give next character to user as result of read.
110 */
111 int
ureadc(c,uio)112 ureadc(c, uio)
113 register int c;
114 register struct uio *uio;
115 {
116 register struct iovec *iov;
117
118 if (uio->uio_resid == 0)
119 #ifdef DIAGNOSTIC
120 panic("ureadc: zero resid");
121 #else
122 return (EINVAL);
123 #endif
124 again:
125 if (uio->uio_iovcnt <= 0)
126 #ifdef DIAGNOSTIC
127 panic("ureadc: non-positive iovcnt");
128 #else
129 return (EINVAL);
130 #endif
131 iov = uio->uio_iov;
132 if (iov->iov_len <= 0) {
133 uio->uio_iovcnt--;
134 uio->uio_iov++;
135 goto again;
136 }
137 switch (uio->uio_segflg) {
138
139 case UIO_USERSPACE:
140 {
141 char tmp = c;
142
143 if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0)
144 return (EFAULT);
145 }
146 break;
147
148 case UIO_SYSSPACE:
149 *(char *)iov->iov_base = c;
150 break;
151 }
152 iov->iov_base = (caddr_t)iov->iov_base + 1;
153 iov->iov_len--;
154 uio->uio_resid--;
155 uio->uio_offset++;
156 return (0);
157 }
158
159 /*
160 * General routine to allocate a hash table.
161 */
162 void *
hashinit(elements,type,flags,hashmask)163 hashinit(elements, type, flags, hashmask)
164 int elements, type, flags;
165 u_long *hashmask;
166 {
167 u_long hashsize, i;
168 LIST_HEAD(generic, generic) *hashtbl;
169
170 if (elements <= 0)
171 panic("hashinit: bad cnt");
172 for (hashsize = 1; hashsize < elements; hashsize <<= 1)
173 continue;
174 hashtbl = malloc(hashsize * sizeof(*hashtbl), type, flags);
175 if (hashtbl == NULL)
176 return NULL;
177 for (i = 0; i < hashsize; i++)
178 LIST_INIT(&hashtbl[i]);
179 *hashmask = hashsize - 1;
180 return (hashtbl);
181 }
182
183 /*
184 * "Shutdown/startup hook" types, functions, and variables.
185 */
186
187 struct hook_desc_head startuphook_list =
188 TAILQ_HEAD_INITIALIZER(startuphook_list);
189 struct hook_desc_head shutdownhook_list =
190 TAILQ_HEAD_INITIALIZER(shutdownhook_list);
191
192 void *
hook_establish(head,tail,fn,arg)193 hook_establish(head, tail, fn, arg)
194 struct hook_desc_head *head;
195 int tail;
196 void (*fn)(void *);
197 void *arg;
198 {
199 struct hook_desc *hdp;
200
201 hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT);
202 if (hdp == NULL)
203 return (NULL);
204
205 hdp->hd_fn = fn;
206 hdp->hd_arg = arg;
207 if (tail)
208 TAILQ_INSERT_TAIL(head, hdp, hd_list);
209 else
210 TAILQ_INSERT_HEAD(head, hdp, hd_list);
211
212 return (hdp);
213 }
214
215 void
hook_disestablish(head,vhook)216 hook_disestablish(head, vhook)
217 struct hook_desc_head *head;
218 void *vhook;
219 {
220 struct hook_desc *hdp;
221
222 #ifdef DIAGNOSTIC
223 for (hdp = TAILQ_FIRST(head); hdp != NULL;
224 hdp = TAILQ_NEXT(hdp, hd_list))
225 if (hdp == vhook)
226 break;
227 if (hdp == NULL)
228 panic("hook_disestablish: hook not established");
229 #endif
230 hdp = vhook;
231 TAILQ_REMOVE(head, hdp, hd_list);
232 free(hdp, M_DEVBUF);
233 }
234
235 /*
236 * Run hooks. Startup hooks are invoked right after scheduler_start but
237 * before root is mounted. Shutdown hooks are invoked immediately before the
238 * system is halted or rebooted, i.e. after file systems unmounted,
239 * after crash dump done, etc.
240 */
241 void
dohooks(struct hook_desc_head * head,int flags)242 dohooks(struct hook_desc_head *head, int flags)
243 {
244 struct hook_desc *hdp;
245
246 if ((flags & HOOK_REMOVE) == 0) {
247 TAILQ_FOREACH(hdp, head, hd_list) {
248 (*hdp->hd_fn)(hdp->hd_arg);
249 }
250 } else {
251 while ((hdp = TAILQ_FIRST(head)) != NULL) {
252 TAILQ_REMOVE(head, hdp, hd_list);
253 (*hdp->hd_fn)(hdp->hd_arg);
254 if ((flags & HOOK_FREE) != 0)
255 free(hdp, M_DEVBUF);
256 }
257 }
258 }
259
260 /*
261 * "Power hook" types, functions, and variables.
262 */
263
264 struct powerhook_desc {
265 CIRCLEQ_ENTRY(powerhook_desc) sfd_list;
266 void (*sfd_fn)(int, void *);
267 void *sfd_arg;
268 };
269
270 CIRCLEQ_HEAD(, powerhook_desc) powerhook_list =
271 CIRCLEQ_HEAD_INITIALIZER(powerhook_list);
272
273 void *
274 powerhook_establish(fn, arg)
275 void (*fn)(int, void *);
276 void *arg;
277 {
278 struct powerhook_desc *ndp;
279
280 ndp = (struct powerhook_desc *)
281 malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
282 if (ndp == NULL)
283 return NULL;
284
285 ndp->sfd_fn = fn;
286 ndp->sfd_arg = arg;
287 CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
288
289 return (ndp);
290 }
291
292 void
powerhook_disestablish(vhook)293 powerhook_disestablish(vhook)
294 void *vhook;
295 {
296 #ifdef DIAGNOSTIC
297 struct powerhook_desc *dp;
298
299 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list)
300 if (dp == vhook)
301 break;
302 if (dp == NULL)
303 panic("powerhook_disestablish: hook not established");
304 #endif
305
306 CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
307 sfd_list);
308 free(vhook, M_DEVBUF);
309 }
310
311 /*
312 * Run power hooks.
313 */
314 void
dopowerhooks(why)315 dopowerhooks(why)
316 int why;
317 {
318 struct powerhook_desc *dp;
319 int s;
320
321 s = splhigh();
322 if (why == PWR_RESUME) {
323 CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) {
324 (*dp->sfd_fn)(why, dp->sfd_arg);
325 }
326 } else {
327 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) {
328 (*dp->sfd_fn)(why, dp->sfd_arg);
329 }
330 }
331 splx(s);
332 }
333