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