tmpfs_mem.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /* $OpenBSD: tmpfs_mem.c,v 1.7 2015/03/14 03:38:52 jsg Exp $ */
  2. /* $NetBSD: tmpfs_mem.c,v 1.4 2011/05/24 01:09:47 rmind Exp $ */
  3. /*
  4. * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
  5. * All rights reserved.
  6. *
  7. * This code is derived from software contributed to The NetBSD Foundation
  8. * by Mindaugas Rasiukevicius.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  21. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  23. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. * POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /*
  32. * tmpfs memory allocation routines.
  33. * Implements memory usage accounting and limiting.
  34. */
  35. #include <sys/param.h>
  36. #include <sys/namei.h>
  37. #include <sys/pool.h>
  38. #include <sys/vnode.h>
  39. #include <sys/malloc.h>
  40. #include <tmpfs/tmpfs.h>
  41. extern struct pool tmpfs_dirent_pool;
  42. extern struct pool tmpfs_node_pool;
  43. void
  44. tmpfs_mntmem_init(struct tmpfs_mount *mp, uint64_t memlimit)
  45. {
  46. rw_init(&mp->tm_acc_lock, "tacclk");
  47. mp->tm_mem_limit = memlimit;
  48. mp->tm_bytes_used = 0;
  49. }
  50. void
  51. tmpfs_mntmem_destroy(struct tmpfs_mount *mp)
  52. {
  53. KASSERT(mp->tm_bytes_used == 0);
  54. /* mutex_destroy(&mp->tm_acc_lock); */
  55. }
  56. /*
  57. * tmpfs_mem_info: return the number of available memory pages.
  58. *
  59. * => If 'total' is true, then return _total_ amount of pages.
  60. * => If false, then return the amount of _free_ memory pages.
  61. *
  62. * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
  63. * excessive memory usage.
  64. */
  65. size_t
  66. tmpfs_mem_info(int total)
  67. {
  68. int size = 0;
  69. /* XXX: unlocked */
  70. size += uvmexp.swpages;
  71. if (!total) {
  72. size -= uvmexp.swpgonly;
  73. }
  74. size += uvmexp.free;
  75. /* size += uvmexp.filepages; */
  76. if (size > uvmexp.wired) {
  77. size -= uvmexp.wired;
  78. } else {
  79. size = 0;
  80. }
  81. KASSERT(size >= 0);
  82. return (size_t)size;
  83. }
  84. uint64_t
  85. tmpfs_bytes_max(struct tmpfs_mount *mp)
  86. {
  87. size_t freepages = tmpfs_mem_info(0);
  88. uint64_t avail_mem;
  89. if (freepages < TMPFS_PAGES_RESERVED) {
  90. freepages = 0;
  91. } else {
  92. freepages -= TMPFS_PAGES_RESERVED;
  93. }
  94. avail_mem = round_page(mp->tm_bytes_used) + (freepages << PAGE_SHIFT);
  95. return MIN(mp->tm_mem_limit, avail_mem);
  96. }
  97. uint64_t
  98. tmpfs_pages_avail(struct tmpfs_mount *mp)
  99. {
  100. return (tmpfs_bytes_max(mp) - mp->tm_bytes_used) >> PAGE_SHIFT;
  101. }
  102. int
  103. tmpfs_mem_incr(struct tmpfs_mount *mp, size_t sz)
  104. {
  105. uint64_t lim;
  106. rw_enter_write(&mp->tm_acc_lock);
  107. lim = tmpfs_bytes_max(mp);
  108. if (mp->tm_bytes_used + sz >= lim) {
  109. rw_exit_write(&mp->tm_acc_lock);
  110. return 0;
  111. }
  112. mp->tm_bytes_used += sz;
  113. rw_exit_write(&mp->tm_acc_lock);
  114. return 1;
  115. }
  116. void
  117. tmpfs_mem_decr(struct tmpfs_mount *mp, size_t sz)
  118. {
  119. rw_enter_write(&mp->tm_acc_lock);
  120. KASSERT(mp->tm_bytes_used >= sz);
  121. mp->tm_bytes_used -= sz;
  122. rw_exit_write(&mp->tm_acc_lock);
  123. }
  124. struct tmpfs_dirent *
  125. tmpfs_dirent_get(struct tmpfs_mount *mp)
  126. {
  127. if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_dirent))) {
  128. return NULL;
  129. }
  130. return pool_get(&tmpfs_dirent_pool, PR_WAITOK);
  131. }
  132. void
  133. tmpfs_dirent_put(struct tmpfs_mount *mp, struct tmpfs_dirent *de)
  134. {
  135. tmpfs_mem_decr(mp, sizeof(struct tmpfs_dirent));
  136. pool_put(&tmpfs_dirent_pool, de);
  137. }
  138. struct tmpfs_node *
  139. tmpfs_node_get(struct tmpfs_mount *mp)
  140. {
  141. mp->tm_nodes_cnt++;
  142. if (mp->tm_nodes_cnt > mp->tm_nodes_max) {
  143. mp->tm_nodes_cnt--;
  144. return NULL;
  145. }
  146. if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_node))) {
  147. return NULL;
  148. }
  149. return pool_get(&tmpfs_node_pool, PR_WAITOK);
  150. }
  151. void
  152. tmpfs_node_put(struct tmpfs_mount *mp, struct tmpfs_node *tn)
  153. {
  154. mp->tm_nodes_cnt--;
  155. tmpfs_mem_decr(mp, sizeof(struct tmpfs_node));
  156. pool_put(&tmpfs_node_pool, tn);
  157. }
  158. /*
  159. * Quantum size to round-up the tmpfs names in order to reduce re-allocations.
  160. */
  161. #define TMPFS_NAME_QUANTUM (32)
  162. #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
  163. char *
  164. tmpfs_strname_alloc(struct tmpfs_mount *mp, size_t len)
  165. {
  166. const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);
  167. KASSERT(sz > 0 && sz <= 1024);
  168. if (!tmpfs_mem_incr(mp, sz)) {
  169. return NULL;
  170. }
  171. return malloc(sz, M_TEMP, M_WAITOK); /* XXX */
  172. }
  173. void
  174. tmpfs_strname_free(struct tmpfs_mount *mp, char *str, size_t len)
  175. {
  176. const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);
  177. KASSERT(sz > 0 && sz <= 1024);
  178. tmpfs_mem_decr(mp, sz);
  179. free(str, M_TEMP, sz);
  180. }
  181. int
  182. tmpfs_strname_neqlen(struct componentname *fcnp, struct componentname *tcnp)
  183. {
  184. const size_t fln = roundup2(fcnp->cn_namelen, TMPFS_NAME_QUANTUM);
  185. const size_t tln = roundup2(tcnp->cn_namelen, TMPFS_NAME_QUANTUM);
  186. return (fln != tln) || memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fln);
  187. }