nfs_aiod.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /* $OpenBSD: nfs_aiod.c,v 1.6 2014/07/12 18:43:52 tedu Exp $ */
  2. /*
  3. * Copyright (c) 1989, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * This code is derived from software contributed to Berkeley by
  7. * Rick Macklem at The University of Guelph.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include <sys/param.h>
  34. #include <sys/systm.h>
  35. #include <sys/kernel.h>
  36. #include <sys/proc.h>
  37. #include <sys/malloc.h>
  38. #include <sys/mount.h>
  39. #include <sys/vnode.h>
  40. #include <sys/kthread.h>
  41. #include <sys/rwlock.h>
  42. #include <sys/signalvar.h>
  43. #include <sys/queue.h>
  44. #include <sys/mutex.h>
  45. #include <nfs/rpcv2.h>
  46. #include <nfs/nfsproto.h>
  47. #include <nfs/nfs.h>
  48. #include <nfs/nfsnode.h>
  49. #include <nfs/nfs_var.h>
  50. #include <nfs/nfsmount.h>
  51. /* The nfs_aiodl_mtx mutex protects the two lists. */
  52. struct mutex nfs_aiodl_mtx;
  53. struct nfs_aiodhead nfs_aiods_all;
  54. struct nfs_aiodhead nfs_aiods_idle;
  55. /* Current number of "running" aiods. Defaults to NFS_DEFASYNCDAEMON (4). */
  56. int nfs_numaiods = -1;
  57. /* Maximum # of buf to queue on an aiod. */
  58. int nfs_aiodbufqmax;
  59. /*
  60. * Asynchronous I/O threads for client nfs.
  61. * They do read-ahead and write-behind operations on the block I/O cache.
  62. * Never returns unless it fails or gets killed.
  63. */
  64. void
  65. nfs_aiod(void *arg)
  66. {
  67. struct nfs_aiod *aiod;
  68. struct nfsmount *nmp;
  69. struct buf *bp;
  70. aiod = malloc(sizeof(*aiod), M_TEMP, M_WAITOK|M_ZERO);
  71. mtx_enter(&nfs_aiodl_mtx);
  72. LIST_INSERT_HEAD(&nfs_aiods_all, aiod, nad_all);
  73. LIST_INSERT_HEAD(&nfs_aiods_idle, aiod, nad_idle);
  74. mtx_leave(&nfs_aiodl_mtx);
  75. nfs_numaiods++;
  76. /*
  77. * Enforce an upper limit on how many bufs we'll queue up for
  78. * a given aiod. This is arbitrarily chosen to be a quarter of
  79. * the number of bufs in the system, divided evenly between
  80. * the running aiods.
  81. *
  82. * Since the number of bufs in the system is dynamic, and the
  83. * aiods are usually started up very early (during boot), the
  84. * number of buffers available is pretty low, so the limit we
  85. * enforce is way to low: So, always allow a minimum of 64 bufs.
  86. * XXX: Footshooting.
  87. */
  88. nfs_aiodbufqmax = max((bcstats.numbufs / 4) / nfs_numaiods, 64);
  89. loop: /* Loop around until SIGKILL */
  90. if (aiod->nad_flags & NFSAIOD_WAKEUP) {
  91. mtx_enter(&nfs_aiodl_mtx);
  92. LIST_INSERT_HEAD(&nfs_aiods_idle, aiod, nad_idle);
  93. mtx_leave(&nfs_aiodl_mtx);
  94. aiod->nad_flags &= ~NFSAIOD_WAKEUP;
  95. }
  96. while (1) {
  97. nmp = aiod->nad_mnt;
  98. if (nmp) {
  99. aiod->nad_mnt = NULL;
  100. break;
  101. }
  102. while (!(aiod->nad_flags & NFSAIOD_WAKEUP))
  103. tsleep(aiod, PWAIT, "aiodidle", 0);
  104. /*
  105. * Wakeup for this aiod happens in one of the following
  106. * situations:
  107. * - The thread is being asked to exit by nfs_set_naiod(), or
  108. * - nfs_asyncio() has found work for this thread on a mount.
  109. *
  110. * In the former case, check to see if nfs_asyncio() has just
  111. * found some work for this thread, and if so, ignore it until
  112. * later.
  113. */
  114. if (aiod->nad_flags & NFSAIOD_EXIT) {
  115. if (aiod->nad_mnt == NULL)
  116. goto out1;
  117. else
  118. break;
  119. }
  120. }
  121. while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
  122. /* Take one off the front of the list */
  123. TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
  124. nmp->nm_bufqlen--;
  125. nfs_doio(bp, NULL);
  126. }
  127. KASSERT(nmp->nm_naiods > 0);
  128. nmp->nm_naiods--;
  129. if (aiod->nad_flags & NFSAIOD_EXIT)
  130. goto out1;
  131. goto loop;
  132. out1:
  133. free(aiod, M_TEMP, 0);
  134. nfs_numaiods--;
  135. KASSERT(nfs_numaiods >= 0);
  136. /* Rejust the limit of bufs to queue. See comment above. */
  137. if (nfs_numaiods > 0)
  138. nfs_aiodbufqmax = max((bcstats.numbufs / 4) / nfs_numaiods, 64);
  139. else
  140. nfs_aiodbufqmax = 0;
  141. kthread_exit(0);
  142. }
  143. int
  144. nfs_set_naiod(int howmany)
  145. {
  146. struct nfs_aiod *aiod;
  147. int want, error;
  148. KASSERT(howmany >= 0);
  149. error = 0;
  150. if (nfs_numaiods == -1)
  151. nfs_numaiods = 0;
  152. want = howmany - nfs_numaiods;
  153. if (want > 0) {
  154. /* Add more. */
  155. want = min(want, NFS_MAXASYNCDAEMON);
  156. while (want > 0) {
  157. error = kthread_create(nfs_aiod, NULL, NULL, "nfsaio");
  158. if (error)
  159. return (error);
  160. want--;
  161. }
  162. } else if (want < 0) {
  163. /* Get rid of some. */
  164. want = -want;
  165. want = min(want, nfs_numaiods);
  166. /* Favour idle aiod's. */
  167. mtx_enter(&nfs_aiodl_mtx);
  168. while (!LIST_EMPTY(&nfs_aiods_idle) && want > 0) {
  169. aiod = LIST_FIRST(&nfs_aiods_idle);
  170. LIST_REMOVE(aiod, nad_idle);
  171. LIST_REMOVE(aiod, nad_all); /* Yuck. */
  172. aiod->nad_flags |= NFSAIOD_QUIT;
  173. wakeup_one(aiod);
  174. want--;
  175. }
  176. while (!LIST_EMPTY(&nfs_aiods_all) && want > 0) {
  177. aiod = LIST_FIRST(&nfs_aiods_all);
  178. LIST_REMOVE(aiod, nad_all);
  179. aiod->nad_flags |= NFSAIOD_QUIT;
  180. wakeup_one(aiod);
  181. want--;
  182. }
  183. mtx_leave(&nfs_aiodl_mtx);
  184. }
  185. /* ignore the want == nfs_numaiods case, since it means no work */
  186. return (error);
  187. }