1 /* $OpenBSD: kern_subr.c,v 1.46 2016/02/11 18:59:15 stefan 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 55 #ifdef DIAGNOSTIC 56 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) 57 panic("uiomove: mode"); 58 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 59 panic("uiomove: proc"); 60 #endif 61 62 if (n > uio->uio_resid) 63 n = uio->uio_resid; 64 65 while (n > 0) { 66 iov = uio->uio_iov; 67 cnt = iov->iov_len; 68 if (cnt == 0) { 69 KASSERT(uio->uio_iovcnt > 0); 70 uio->uio_iov++; 71 uio->uio_iovcnt--; 72 continue; 73 } 74 if (cnt > n) 75 cnt = n; 76 switch (uio->uio_segflg) { 77 78 case UIO_USERSPACE: 79 if (curcpu()->ci_schedstate.spc_schedflags & 80 SPCF_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 int 109 uiomovei(void *cp, int n, struct uio *uio) 110 { 111 if (n < 0) 112 return 0; 113 114 return uiomove(cp, (size_t)n, uio); 115 } 116 117 /* 118 * Give next character to user as result of read. 119 */ 120 int 121 ureadc(int c, struct uio *uio) 122 { 123 struct iovec *iov; 124 125 if (uio->uio_resid == 0) 126 #ifdef DIAGNOSTIC 127 panic("ureadc: zero resid"); 128 #else 129 return (EINVAL); 130 #endif 131 again: 132 if (uio->uio_iovcnt <= 0) 133 #ifdef DIAGNOSTIC 134 panic("ureadc: non-positive iovcnt"); 135 #else 136 return (EINVAL); 137 #endif 138 iov = uio->uio_iov; 139 if (iov->iov_len <= 0) { 140 uio->uio_iovcnt--; 141 uio->uio_iov++; 142 goto again; 143 } 144 switch (uio->uio_segflg) { 145 146 case UIO_USERSPACE: 147 { 148 char tmp = c; 149 150 if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0) 151 return (EFAULT); 152 } 153 break; 154 155 case UIO_SYSSPACE: 156 *(char *)iov->iov_base = c; 157 break; 158 } 159 iov->iov_base = (caddr_t)iov->iov_base + 1; 160 iov->iov_len--; 161 uio->uio_resid--; 162 uio->uio_offset++; 163 return (0); 164 } 165 166 /* 167 * General routine to allocate a hash table. 168 */ 169 void * 170 hashinit(int elements, int type, int flags, u_long *hashmask) 171 { 172 u_long hashsize, i; 173 LIST_HEAD(generic, generic) *hashtbl; 174 175 if (elements <= 0) 176 panic("hashinit: bad cnt"); 177 for (hashsize = 1; hashsize < elements; hashsize <<= 1) 178 continue; 179 hashtbl = mallocarray(hashsize, sizeof(*hashtbl), type, flags); 180 if (hashtbl == NULL) 181 return NULL; 182 for (i = 0; i < hashsize; i++) 183 LIST_INIT(&hashtbl[i]); 184 *hashmask = hashsize - 1; 185 return (hashtbl); 186 } 187 188 /* 189 * "startup hook" types, functions, and variables. 190 */ 191 192 struct hook_desc_head startuphook_list = 193 TAILQ_HEAD_INITIALIZER(startuphook_list); 194 195 void * 196 hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *), 197 void *arg) 198 { 199 struct hook_desc *hdp; 200 201 hdp = 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(struct hook_desc_head *head, void *vhook) 217 { 218 struct hook_desc *hdp; 219 220 #ifdef DIAGNOSTIC 221 for (hdp = TAILQ_FIRST(head); hdp != NULL; 222 hdp = TAILQ_NEXT(hdp, hd_list)) 223 if (hdp == vhook) 224 break; 225 if (hdp == NULL) 226 return; 227 #endif 228 hdp = vhook; 229 TAILQ_REMOVE(head, hdp, hd_list); 230 free(hdp, M_DEVBUF, sizeof(*hdp)); 231 } 232 233 /* 234 * Run hooks. Startup hooks are invoked right after scheduler_start but 235 * before root is mounted. Shutdown hooks are invoked immediately before the 236 * system is halted or rebooted, i.e. after file systems unmounted, 237 * after crash dump done, etc. 238 */ 239 void 240 dohooks(struct hook_desc_head *head, int flags) 241 { 242 struct hook_desc *hdp, *hdp_temp; 243 244 if ((flags & HOOK_REMOVE) == 0) { 245 TAILQ_FOREACH_SAFE(hdp, head, hd_list, hdp_temp) { 246 (*hdp->hd_fn)(hdp->hd_arg); 247 } 248 } else { 249 while ((hdp = TAILQ_FIRST(head)) != NULL) { 250 TAILQ_REMOVE(head, hdp, hd_list); 251 (*hdp->hd_fn)(hdp->hd_arg); 252 if ((flags & HOOK_FREE) != 0) 253 free(hdp, M_DEVBUF, sizeof(*hdp)); 254 } 255 } 256 } 257