kern_subr.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* $OpenBSD: kern_subr.c,v 1.44 2015/03/14 03:38:50 jsg Exp $ */
  2. /* $NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $ */
  3. /*
  4. * Copyright (c) 1982, 1986, 1991, 1993
  5. * The Regents of the University of California. All rights reserved.
  6. * (c) UNIX System Laboratories, Inc.
  7. * All or some portions of this file are derived from material licensed
  8. * to the University of California by American Telephone and Telegraph
  9. * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  10. * the permission of UNIX System Laboratories, Inc.
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. * 1. Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in the
  19. * documentation and/or other materials provided with the distribution.
  20. * 3. Neither the name of the University nor the names of its contributors
  21. * may be used to endorse or promote products derived from this software
  22. * without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34. * SUCH DAMAGE.
  35. *
  36. * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
  37. */
  38. #include <sys/param.h>
  39. #include <sys/systm.h>
  40. #include <sys/proc.h>
  41. #include <sys/sched.h>
  42. #include <sys/malloc.h>
  43. #include <sys/queue.h>
  44. #include <sys/resourcevar.h>
  45. int
  46. uiomove(void *cp, size_t n, struct uio *uio)
  47. {
  48. struct iovec *iov;
  49. size_t cnt;
  50. int error = 0;
  51. struct proc *p;
  52. p = uio->uio_procp;
  53. #ifdef DIAGNOSTIC
  54. if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
  55. panic("uiomove: mode");
  56. if (uio->uio_segflg == UIO_USERSPACE && p != curproc)
  57. panic("uiomove: proc");
  58. #endif
  59. while (n > 0 && uio->uio_resid) {
  60. iov = uio->uio_iov;
  61. cnt = iov->iov_len;
  62. if (cnt == 0) {
  63. uio->uio_iov++;
  64. uio->uio_iovcnt--;
  65. continue;
  66. }
  67. if (cnt > n)
  68. cnt = n;
  69. switch (uio->uio_segflg) {
  70. case UIO_USERSPACE:
  71. if (curcpu()->ci_schedstate.spc_schedflags &
  72. SPCF_SHOULDYIELD)
  73. preempt(NULL);
  74. if (uio->uio_rw == UIO_READ)
  75. error = copyout(cp, iov->iov_base, cnt);
  76. else
  77. error = copyin(iov->iov_base, cp, cnt);
  78. if (error)
  79. return (error);
  80. break;
  81. case UIO_SYSSPACE:
  82. if (uio->uio_rw == UIO_READ)
  83. error = kcopy(cp, iov->iov_base, cnt);
  84. else
  85. error = kcopy(iov->iov_base, cp, cnt);
  86. if (error)
  87. return(error);
  88. }
  89. iov->iov_base = (caddr_t)iov->iov_base + cnt;
  90. iov->iov_len -= cnt;
  91. uio->uio_resid -= cnt;
  92. uio->uio_offset += cnt;
  93. cp = (caddr_t)cp + cnt;
  94. n -= cnt;
  95. }
  96. return (error);
  97. }
  98. int
  99. uiomovei(void *cp, int n, struct uio *uio)
  100. {
  101. if (n < 0)
  102. return 0;
  103. return uiomove(cp, (size_t)n, uio);
  104. }
  105. /*
  106. * Give next character to user as result of read.
  107. */
  108. int
  109. ureadc(int c, struct uio *uio)
  110. {
  111. struct iovec *iov;
  112. if (uio->uio_resid == 0)
  113. #ifdef DIAGNOSTIC
  114. panic("ureadc: zero resid");
  115. #else
  116. return (EINVAL);
  117. #endif
  118. again:
  119. if (uio->uio_iovcnt <= 0)
  120. #ifdef DIAGNOSTIC
  121. panic("ureadc: non-positive iovcnt");
  122. #else
  123. return (EINVAL);
  124. #endif
  125. iov = uio->uio_iov;
  126. if (iov->iov_len <= 0) {
  127. uio->uio_iovcnt--;
  128. uio->uio_iov++;
  129. goto again;
  130. }
  131. switch (uio->uio_segflg) {
  132. case UIO_USERSPACE:
  133. {
  134. char tmp = c;
  135. if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0)
  136. return (EFAULT);
  137. }
  138. break;
  139. case UIO_SYSSPACE:
  140. *(char *)iov->iov_base = c;
  141. break;
  142. }
  143. iov->iov_base = (caddr_t)iov->iov_base + 1;
  144. iov->iov_len--;
  145. uio->uio_resid--;
  146. uio->uio_offset++;
  147. return (0);
  148. }
  149. /*
  150. * General routine to allocate a hash table.
  151. */
  152. void *
  153. hashinit(int elements, int type, int flags, u_long *hashmask)
  154. {
  155. u_long hashsize, i;
  156. LIST_HEAD(generic, generic) *hashtbl;
  157. if (elements <= 0)
  158. panic("hashinit: bad cnt");
  159. for (hashsize = 1; hashsize < elements; hashsize <<= 1)
  160. continue;
  161. hashtbl = mallocarray(hashsize, sizeof(*hashtbl), type, flags);
  162. if (hashtbl == NULL)
  163. return NULL;
  164. for (i = 0; i < hashsize; i++)
  165. LIST_INIT(&hashtbl[i]);
  166. *hashmask = hashsize - 1;
  167. return (hashtbl);
  168. }
  169. /*
  170. * "Mountroot/startup hook" types, functions, and variables.
  171. */
  172. struct hook_desc_head startuphook_list =
  173. TAILQ_HEAD_INITIALIZER(startuphook_list);
  174. struct hook_desc_head mountroothook_list =
  175. TAILQ_HEAD_INITIALIZER(mountroothook_list);
  176. void *
  177. hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *),
  178. void *arg)
  179. {
  180. struct hook_desc *hdp;
  181. hdp = malloc(sizeof(*hdp), M_DEVBUF, M_NOWAIT);
  182. if (hdp == NULL)
  183. return (NULL);
  184. hdp->hd_fn = fn;
  185. hdp->hd_arg = arg;
  186. if (tail)
  187. TAILQ_INSERT_TAIL(head, hdp, hd_list);
  188. else
  189. TAILQ_INSERT_HEAD(head, hdp, hd_list);
  190. return (hdp);
  191. }
  192. void
  193. hook_disestablish(struct hook_desc_head *head, void *vhook)
  194. {
  195. struct hook_desc *hdp;
  196. #ifdef DIAGNOSTIC
  197. for (hdp = TAILQ_FIRST(head); hdp != NULL;
  198. hdp = TAILQ_NEXT(hdp, hd_list))
  199. if (hdp == vhook)
  200. break;
  201. if (hdp == NULL)
  202. return;
  203. #endif
  204. hdp = vhook;
  205. TAILQ_REMOVE(head, hdp, hd_list);
  206. free(hdp, M_DEVBUF, sizeof(*hdp));
  207. }
  208. /*
  209. * Run hooks. Startup hooks are invoked right after scheduler_start but
  210. * before root is mounted. Shutdown hooks are invoked immediately before the
  211. * system is halted or rebooted, i.e. after file systems unmounted,
  212. * after crash dump done, etc.
  213. */
  214. void
  215. dohooks(struct hook_desc_head *head, int flags)
  216. {
  217. struct hook_desc *hdp, *hdp_temp;
  218. if ((flags & HOOK_REMOVE) == 0) {
  219. TAILQ_FOREACH_SAFE(hdp, head, hd_list, hdp_temp) {
  220. (*hdp->hd_fn)(hdp->hd_arg);
  221. }
  222. } else {
  223. while ((hdp = TAILQ_FIRST(head)) != NULL) {
  224. TAILQ_REMOVE(head, hdp, hd_list);
  225. (*hdp->hd_fn)(hdp->hd_arg);
  226. if ((flags & HOOK_FREE) != 0)
  227. free(hdp, M_DEVBUF, sizeof(*hdp));
  228. }
  229. }
  230. }