1 /* $OpenBSD: kern_subr.c,v 1.25 2003/07/21 22:44:50 tedu 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 long hashsize; 168 LIST_HEAD(generic, generic) *hashtbl; 169 int i; 170 171 if (elements <= 0) 172 panic("hashinit: bad cnt"); 173 for (hashsize = 1; hashsize <= elements; hashsize <<= 1) 174 continue; 175 hashsize >>= 1; 176 hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, flags); 177 if (hashtbl == NULL) 178 return NULL; 179 for (i = 0; i < hashsize; i++) 180 LIST_INIT(&hashtbl[i]); 181 *hashmask = hashsize - 1; 182 return (hashtbl); 183 } 184 185 /* 186 * "Shutdown/startup hook" types, functions, and variables. 187 */ 188 189 struct hook_desc_head startuphook_list = 190 TAILQ_HEAD_INITIALIZER(startuphook_list); 191 struct hook_desc_head shutdownhook_list = 192 TAILQ_HEAD_INITIALIZER(shutdownhook_list); 193 194 void * 195 hook_establish(head, tail, fn, arg) 196 struct hook_desc_head *head; 197 int tail; 198 void (*fn)(void *); 199 void *arg; 200 { 201 struct hook_desc *hdp; 202 203 hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT); 204 if (hdp == NULL) 205 return (NULL); 206 207 hdp->hd_fn = fn; 208 hdp->hd_arg = arg; 209 if (tail) 210 TAILQ_INSERT_TAIL(head, hdp, hd_list); 211 else 212 TAILQ_INSERT_HEAD(head, hdp, hd_list); 213 214 return (hdp); 215 } 216 217 void 218 hook_disestablish(head, vhook) 219 struct hook_desc_head *head; 220 void *vhook; 221 { 222 struct hook_desc *hdp; 223 224 #ifdef DIAGNOSTIC 225 for (hdp = TAILQ_FIRST(head); hdp != NULL; 226 hdp = TAILQ_NEXT(hdp, hd_list)) 227 if (hdp == vhook) 228 break; 229 if (hdp == NULL) 230 panic("hook_disestablish: hook not established"); 231 #endif 232 hdp = vhook; 233 TAILQ_REMOVE(head, hdp, hd_list); 234 free(hdp, M_DEVBUF); 235 } 236 237 /* 238 * Run hooks. Startup hooks are invoked right after scheduler_start but 239 * before root is mounted. Shutdown hooks are invoked immediately before the 240 * system is halted or rebooted, i.e. after file systems unmounted, 241 * after crash dump done, etc. 242 */ 243 void 244 dohooks(struct hook_desc_head *head, int flags) 245 { 246 struct hook_desc *hdp; 247 248 if ((flags & HOOK_REMOVE) == 0) { 249 TAILQ_FOREACH(hdp, head, hd_list) { 250 (*hdp->hd_fn)(hdp->hd_arg); 251 } 252 } else { 253 while ((hdp = TAILQ_FIRST(head)) != NULL) { 254 TAILQ_REMOVE(head, hdp, hd_list); 255 (*hdp->hd_fn)(hdp->hd_arg); 256 if ((flags & HOOK_FREE) != 0) 257 free(hdp, M_DEVBUF); 258 } 259 } 260 } 261 262 /* 263 * "Power hook" types, functions, and variables. 264 */ 265 266 struct powerhook_desc { 267 CIRCLEQ_ENTRY(powerhook_desc) sfd_list; 268 void (*sfd_fn)(int, void *); 269 void *sfd_arg; 270 }; 271 272 CIRCLEQ_HEAD(, powerhook_desc) powerhook_list = 273 CIRCLEQ_HEAD_INITIALIZER(powerhook_list); 274 275 void * 276 powerhook_establish(fn, arg) 277 void (*fn)(int, void *); 278 void *arg; 279 { 280 struct powerhook_desc *ndp; 281 282 ndp = (struct powerhook_desc *) 283 malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT); 284 if (ndp == NULL) 285 return NULL; 286 287 ndp->sfd_fn = fn; 288 ndp->sfd_arg = arg; 289 CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list); 290 291 return (ndp); 292 } 293 294 void 295 powerhook_disestablish(vhook) 296 void *vhook; 297 { 298 #ifdef DIAGNOSTIC 299 struct powerhook_desc *dp; 300 301 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) 302 if (dp == vhook) 303 break; 304 if (dp == NULL) 305 panic("powerhook_disestablish: hook not established"); 306 #endif 307 308 CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook, 309 sfd_list); 310 free(vhook, M_DEVBUF); 311 } 312 313 /* 314 * Run power hooks. 315 */ 316 void 317 dopowerhooks(why) 318 int why; 319 { 320 struct powerhook_desc *dp; 321 int s; 322 323 s = splhigh(); 324 if (why == PWR_RESUME) { 325 CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) { 326 (*dp->sfd_fn)(why, dp->sfd_arg); 327 } 328 } else { 329 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) { 330 (*dp->sfd_fn)(why, dp->sfd_arg); 331 } 332 } 333 splx(s); 334 } 335