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