1 /* $OpenBSD: kern_subr.c,v 1.45 2015/12/11 16:07:02 mpi 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/resourcevar.h> 47 48 int 49 uiomove(void *cp, size_t n, struct uio *uio) 50 { 51 struct iovec *iov; 52 size_t cnt; 53 int error = 0; 54 struct proc *p; 55 56 p = uio->uio_procp; 57 58 #ifdef DIAGNOSTIC 59 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) 60 panic("uiomove: mode"); 61 if (uio->uio_segflg == UIO_USERSPACE && p != curproc) 62 panic("uiomove: proc"); 63 #endif 64 while (n > 0 && uio->uio_resid) { 65 iov = uio->uio_iov; 66 cnt = iov->iov_len; 67 if (cnt == 0) { 68 uio->uio_iov++; 69 uio->uio_iovcnt--; 70 continue; 71 } 72 if (cnt > n) 73 cnt = n; 74 switch (uio->uio_segflg) { 75 76 case UIO_USERSPACE: 77 if (curcpu()->ci_schedstate.spc_schedflags & 78 SPCF_SHOULDYIELD) 79 preempt(NULL); 80 if (uio->uio_rw == UIO_READ) 81 error = copyout(cp, iov->iov_base, cnt); 82 else 83 error = copyin(iov->iov_base, cp, cnt); 84 if (error) 85 return (error); 86 break; 87 88 case UIO_SYSSPACE: 89 if (uio->uio_rw == UIO_READ) 90 error = kcopy(cp, iov->iov_base, cnt); 91 else 92 error = kcopy(iov->iov_base, cp, cnt); 93 if (error) 94 return(error); 95 } 96 iov->iov_base = (caddr_t)iov->iov_base + cnt; 97 iov->iov_len -= cnt; 98 uio->uio_resid -= cnt; 99 uio->uio_offset += cnt; 100 cp = (caddr_t)cp + cnt; 101 n -= cnt; 102 } 103 return (error); 104 } 105 106 int 107 uiomovei(void *cp, int n, struct uio *uio) 108 { 109 if (n < 0) 110 return 0; 111 112 return uiomove(cp, (size_t)n, uio); 113 } 114 115 /* 116 * Give next character to user as result of read. 117 */ 118 int 119 ureadc(int c, struct uio *uio) 120 { 121 struct iovec *iov; 122 123 if (uio->uio_resid == 0) 124 #ifdef DIAGNOSTIC 125 panic("ureadc: zero resid"); 126 #else 127 return (EINVAL); 128 #endif 129 again: 130 if (uio->uio_iovcnt <= 0) 131 #ifdef DIAGNOSTIC 132 panic("ureadc: non-positive iovcnt"); 133 #else 134 return (EINVAL); 135 #endif 136 iov = uio->uio_iov; 137 if (iov->iov_len <= 0) { 138 uio->uio_iovcnt--; 139 uio->uio_iov++; 140 goto again; 141 } 142 switch (uio->uio_segflg) { 143 144 case UIO_USERSPACE: 145 { 146 char tmp = c; 147 148 if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0) 149 return (EFAULT); 150 } 151 break; 152 153 case UIO_SYSSPACE: 154 *(char *)iov->iov_base = c; 155 break; 156 } 157 iov->iov_base = (caddr_t)iov->iov_base + 1; 158 iov->iov_len--; 159 uio->uio_resid--; 160 uio->uio_offset++; 161 return (0); 162 } 163 164 /* 165 * General routine to allocate a hash table. 166 */ 167 void * 168 hashinit(int elements, int type, int flags, u_long *hashmask) 169 { 170 u_long hashsize, i; 171 LIST_HEAD(generic, generic) *hashtbl; 172 173 if (elements <= 0) 174 panic("hashinit: bad cnt"); 175 for (hashsize = 1; hashsize < elements; hashsize <<= 1) 176 continue; 177 hashtbl = mallocarray(hashsize, sizeof(*hashtbl), type, flags); 178 if (hashtbl == NULL) 179 return NULL; 180 for (i = 0; i < hashsize; i++) 181 LIST_INIT(&hashtbl[i]); 182 *hashmask = hashsize - 1; 183 return (hashtbl); 184 } 185 186 /* 187 * "startup hook" types, functions, and variables. 188 */ 189 190 struct hook_desc_head startuphook_list = 191 TAILQ_HEAD_INITIALIZER(startuphook_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 = 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 return; 225 #endif 226 hdp = vhook; 227 TAILQ_REMOVE(head, hdp, hd_list); 228 free(hdp, M_DEVBUF, sizeof(*hdp)); 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, *hdp_temp; 241 242 if ((flags & HOOK_REMOVE) == 0) { 243 TAILQ_FOREACH_SAFE(hdp, head, hd_list, hdp_temp) { 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, sizeof(*hdp)); 252 } 253 } 254 } 255