1 /* $OpenBSD: kern_subr.c,v 1.47 2016/03/15 04:19:26 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 /* 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 /* 180 * "startup hook" types, functions, and variables. 181 */ 182 183 struct hook_desc_head startuphook_list = 184 TAILQ_HEAD_INITIALIZER(startuphook_list); 185 186 void * 187 hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *), 188 void *arg) 189 { 190 struct hook_desc *hdp; 191 192 hdp = malloc(sizeof(*hdp), M_DEVBUF, M_NOWAIT); 193 if (hdp == NULL) 194 return (NULL); 195 196 hdp->hd_fn = fn; 197 hdp->hd_arg = arg; 198 if (tail) 199 TAILQ_INSERT_TAIL(head, hdp, hd_list); 200 else 201 TAILQ_INSERT_HEAD(head, hdp, hd_list); 202 203 return (hdp); 204 } 205 206 void 207 hook_disestablish(struct hook_desc_head *head, void *vhook) 208 { 209 struct hook_desc *hdp; 210 211 #ifdef DIAGNOSTIC 212 for (hdp = TAILQ_FIRST(head); hdp != NULL; 213 hdp = TAILQ_NEXT(hdp, hd_list)) 214 if (hdp == vhook) 215 break; 216 if (hdp == NULL) 217 return; 218 #endif 219 hdp = vhook; 220 TAILQ_REMOVE(head, hdp, hd_list); 221 free(hdp, M_DEVBUF, sizeof(*hdp)); 222 } 223 224 /* 225 * Run hooks. Startup hooks are invoked right after scheduler_start but 226 * before root is mounted. Shutdown hooks are invoked immediately before the 227 * system is halted or rebooted, i.e. after file systems unmounted, 228 * after crash dump done, etc. 229 */ 230 void 231 dohooks(struct hook_desc_head *head, int flags) 232 { 233 struct hook_desc *hdp, *hdp_temp; 234 235 if ((flags & HOOK_REMOVE) == 0) { 236 TAILQ_FOREACH_SAFE(hdp, head, hd_list, hdp_temp) { 237 (*hdp->hd_fn)(hdp->hd_arg); 238 } 239 } else { 240 while ((hdp = TAILQ_FIRST(head)) != NULL) { 241 TAILQ_REMOVE(head, hdp, hd_list); 242 (*hdp->hd_fn)(hdp->hd_arg); 243 if ((flags & HOOK_FREE) != 0) 244 free(hdp, M_DEVBUF, sizeof(*hdp)); 245 } 246 } 247 } 248