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 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 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 * 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 * 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 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 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 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 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