1 /* $OpenBSD: kern_subr.c,v 1.48 2016/09/24 18:35:52 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/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 /* 109 * Give next character to user as result of read. 110 */ 111 int 112 ureadc(int c, struct uio *uio) 113 { 114 struct iovec *iov; 115 116 if (uio->uio_resid == 0) 117 #ifdef DIAGNOSTIC 118 panic("ureadc: zero resid"); 119 #else 120 return (EINVAL); 121 #endif 122 again: 123 if (uio->uio_iovcnt <= 0) 124 #ifdef DIAGNOSTIC 125 panic("ureadc: non-positive iovcnt"); 126 #else 127 return (EINVAL); 128 #endif 129 iov = uio->uio_iov; 130 if (iov->iov_len <= 0) { 131 uio->uio_iovcnt--; 132 uio->uio_iov++; 133 goto again; 134 } 135 switch (uio->uio_segflg) { 136 137 case UIO_USERSPACE: 138 { 139 char tmp = c; 140 141 if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0) 142 return (EFAULT); 143 } 144 break; 145 146 case UIO_SYSSPACE: 147 *(char *)iov->iov_base = c; 148 break; 149 } 150 iov->iov_base = (caddr_t)iov->iov_base + 1; 151 iov->iov_len--; 152 uio->uio_resid--; 153 uio->uio_offset++; 154 return (0); 155 } 156 157 /* 158 * General routine to allocate a hash table. 159 */ 160 void * 161 hashinit(int elements, int type, int flags, u_long *hashmask) 162 { 163 u_long hashsize, i; 164 LIST_HEAD(generic, generic) *hashtbl; 165 166 if (elements <= 0) 167 panic("hashinit: bad cnt"); 168 for (hashsize = 1; hashsize < elements; hashsize <<= 1) 169 continue; 170 hashtbl = mallocarray(hashsize, sizeof(*hashtbl), type, flags); 171 if (hashtbl == NULL) 172 return NULL; 173 for (i = 0; i < hashsize; i++) 174 LIST_INIT(&hashtbl[i]); 175 *hashmask = hashsize - 1; 176 return (hashtbl); 177 } 178 179 void 180 hashfree(void *hash, int elements, int type) 181 { 182 u_long hashsize; 183 LIST_HEAD(generic, generic) *hashtbl = hash; 184 185 if (elements <= 0) 186 panic("hashfree: bad cnt"); 187 for (hashsize = 1; hashsize < elements; hashsize <<= 1) 188 continue; 189 190 free(hashtbl, type, sizeof(*hashtbl) * hashsize); 191 } 192 193 /* 194 * "startup hook" types, functions, and variables. 195 */ 196 197 struct hook_desc_head startuphook_list = 198 TAILQ_HEAD_INITIALIZER(startuphook_list); 199 200 void * 201 hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *), 202 void *arg) 203 { 204 struct hook_desc *hdp; 205 206 hdp = malloc(sizeof(*hdp), M_DEVBUF, M_NOWAIT); 207 if (hdp == NULL) 208 return (NULL); 209 210 hdp->hd_fn = fn; 211 hdp->hd_arg = arg; 212 if (tail) 213 TAILQ_INSERT_TAIL(head, hdp, hd_list); 214 else 215 TAILQ_INSERT_HEAD(head, hdp, hd_list); 216 217 return (hdp); 218 } 219 220 void 221 hook_disestablish(struct hook_desc_head *head, void *vhook) 222 { 223 struct hook_desc *hdp; 224 225 #ifdef DIAGNOSTIC 226 for (hdp = TAILQ_FIRST(head); hdp != NULL; 227 hdp = TAILQ_NEXT(hdp, hd_list)) 228 if (hdp == vhook) 229 break; 230 if (hdp == NULL) 231 return; 232 #endif 233 hdp = vhook; 234 TAILQ_REMOVE(head, hdp, hd_list); 235 free(hdp, M_DEVBUF, sizeof(*hdp)); 236 } 237 238 /* 239 * Run hooks. Startup hooks are invoked right after scheduler_start but 240 * before root is mounted. Shutdown hooks are invoked immediately before the 241 * system is halted or rebooted, i.e. after file systems unmounted, 242 * after crash dump done, etc. 243 */ 244 void 245 dohooks(struct hook_desc_head *head, int flags) 246 { 247 struct hook_desc *hdp, *hdp_temp; 248 249 if ((flags & HOOK_REMOVE) == 0) { 250 TAILQ_FOREACH_SAFE(hdp, head, hd_list, hdp_temp) { 251 (*hdp->hd_fn)(hdp->hd_arg); 252 } 253 } else { 254 while ((hdp = TAILQ_FIRST(head)) != NULL) { 255 TAILQ_REMOVE(head, hdp, hd_list); 256 (*hdp->hd_fn)(hdp->hd_arg); 257 if ((flags & HOOK_FREE) != 0) 258 free(hdp, M_DEVBUF, sizeof(*hdp)); 259 } 260 } 261 } 262