No empty .Rs/.Re
[netbsd-mini2440.git] / sys / fs / tmpfs / tmpfs_pool.c
blobf9e8a0cec278a2cbc5bc91a12b79b8c0e4e86889
1 /* $NetBSD: tmpfs_pool.c,v 1.13 2008/02/06 11:23:54 jmmv Exp $ */
3 /*
4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 * 2005 program.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Pool allocator and convenience routines for tmpfs.
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: tmpfs_pool.c,v 1.13 2008/02/06 11:23:54 jmmv Exp $");
40 #include <sys/param.h>
41 #include <sys/pool.h>
42 #include <sys/atomic.h>
44 #include <uvm/uvm.h>
46 #include <fs/tmpfs/tmpfs.h>
48 /* --------------------------------------------------------------------- */
50 void * tmpfs_pool_page_alloc(struct pool *, int);
51 void tmpfs_pool_page_free(struct pool *, void *);
53 /* XXX: Will go away when our pool allocator does what it has to do by
54 * itself. */
55 extern void* pool_page_alloc_nointr(struct pool *, int);
56 extern void pool_page_free_nointr(struct pool *, void *);
58 /* --------------------------------------------------------------------- */
61 * tmpfs provides a custom pool allocator mostly to exactly keep track of
62 * how many memory is used for each file system instance. These pools are
63 * never shared across multiple mount points for the reasons described
64 * below:
66 * - It is very easy to control how many memory is associated with a
67 * given file system. tmpfs provides a custom pool allocator that
68 * controls memory usage according to previously specified usage
69 * limits, by simply increasing or decreasing a counter when pages
70 * are allocated or released, respectively.
72 * If the pools were shared, we could easily end up with unaccounted
73 * memory, thus taking incorrect decisions on the amount of memory
74 * use. As an example to prove this point, consider two mounted
75 * instances of tmpfs, one mounted on A and another one on B. Assume
76 * that each memory page can hold up to four directory entries and
77 * that, for each entry you create on A, you create three on B
78 * afterwards. After doing this, each memory page will be holding an
79 * entry from A and three for B. If you sum up all the space taken by
80 * the total amount of allocated entries, rounded up to a page
81 * boundary, that number will match the number of allocated pages, so
82 * everything is fine.
84 * Now suppose we unmount B. Given that the file system has to
85 * disappear, we have to delete all the directory entries attached to
86 * it. But the problem is that freeing those entries will not release
87 * any memory page. Instead, each page will be filled up to a 25%,
88 * and the rest, a 75%, will be lost. Not lost in a strict term,
89 * because the memory can be reused by new entries, but lost in the
90 * sense that it is not accounted by any file system. Despite A will
91 * think it is using an amount 'X' of memory, it will be really using
92 * fourth times that number, thus causing mistakes when it comes to
93 * decide if there is more free space for that specific instance of
94 * tmpfs.
96 * - The number of page faults and cache misses is reduced given that all
97 * entries of a given file system are stored in less pages. Note that
98 * this is true because it is common to allocate and/or access many
99 * entries at once on a specific file system.
101 * Following the example given above, listing a directory on file system
102 * A could result, in the worst case scenario, in fourth times more page
103 * faults if we shared the pools.
105 struct pool_allocator tmpfs_pool_allocator = {
106 .pa_alloc = tmpfs_pool_page_alloc,
107 .pa_free = tmpfs_pool_page_free,
110 /* --------------------------------------------------------------------- */
113 * Initializes the pool pointed to by tpp and associates it to the mount
114 * point tmp. The size of its elements is set to size. Its wait channel
115 * is derived from the string given in what and the mount point given in
116 * 'tmp', which should result in a unique string among all existing pools.
118 void
119 tmpfs_pool_init(struct tmpfs_pool *tpp, size_t size, const char *what,
120 struct tmpfs_mount *tmp)
122 int cnt;
124 cnt = snprintf(tpp->tp_name, sizeof(tpp->tp_name),
125 "%s_tmpfs_%p", what, tmp);
126 KASSERT(cnt < sizeof(tpp->tp_name));
128 pool_init(&tpp->tp_pool, size, 0, 0, 0, tpp->tp_name,
129 &tmpfs_pool_allocator, IPL_NONE);
130 tpp->tp_mount = tmp;
133 /* --------------------------------------------------------------------- */
136 * Destroys the pool pointed to by 'tpp'.
138 void
139 tmpfs_pool_destroy(struct tmpfs_pool *tpp)
142 pool_destroy((struct pool *)tpp);
145 /* --------------------------------------------------------------------- */
147 void *
148 tmpfs_pool_page_alloc(struct pool *pp, int flags)
150 struct tmpfs_pool *tpp;
151 struct tmpfs_mount *tmp;
152 unsigned int pages;
153 void *page;
155 tpp = (struct tmpfs_pool *)pp;
156 tmp = tpp->tp_mount;
158 pages = atomic_inc_uint_nv(&tmp->tm_pages_used);
159 if (pages >= TMPFS_PAGES_MAX(tmp)) {
160 atomic_dec_uint(&tmp->tm_pages_used);
161 return NULL;
164 * tmpfs never specifies PR_WAITOK as we enforce local limits
165 * on memory allocation. However, we should wait for memory
166 * to become available if under our limit. XXX The result of
167 * the TMPFS_PAGES_MAX() check is stale.
169 page = pool_page_alloc_nointr(pp, flags | PR_WAITOK);
170 if (page == NULL) {
171 atomic_dec_uint(&tmp->tm_pages_used);
174 return page;
177 /* --------------------------------------------------------------------- */
179 void
180 tmpfs_pool_page_free(struct pool *pp, void *v)
182 struct tmpfs_pool *tpp;
183 struct tmpfs_mount *tmp;
185 tpp = (struct tmpfs_pool *)pp;
186 tmp = tpp->tp_mount;
188 atomic_dec_uint(&tmp->tm_pages_used);
189 pool_page_free_nointr(pp, v);
192 /* --------------------------------------------------------------------- */
195 * Initialize the string pool pointed to by 'tsp' and attach it to the
196 * 'tmp' mount point.
198 void
199 tmpfs_str_pool_init(struct tmpfs_str_pool *tsp, struct tmpfs_mount *tmp)
202 tmpfs_pool_init(&tsp->tsp_pool_16, 16, "str", tmp);
203 tmpfs_pool_init(&tsp->tsp_pool_32, 32, "str", tmp);
204 tmpfs_pool_init(&tsp->tsp_pool_64, 64, "str", tmp);
205 tmpfs_pool_init(&tsp->tsp_pool_128, 128, "str", tmp);
206 tmpfs_pool_init(&tsp->tsp_pool_256, 256, "str", tmp);
207 tmpfs_pool_init(&tsp->tsp_pool_512, 512, "str", tmp);
208 tmpfs_pool_init(&tsp->tsp_pool_1024, 1024, "str", tmp);
211 /* --------------------------------------------------------------------- */
214 * Destroy the given string pool.
216 void
217 tmpfs_str_pool_destroy(struct tmpfs_str_pool *tsp)
220 tmpfs_pool_destroy(&tsp->tsp_pool_16);
221 tmpfs_pool_destroy(&tsp->tsp_pool_32);
222 tmpfs_pool_destroy(&tsp->tsp_pool_64);
223 tmpfs_pool_destroy(&tsp->tsp_pool_128);
224 tmpfs_pool_destroy(&tsp->tsp_pool_256);
225 tmpfs_pool_destroy(&tsp->tsp_pool_512);
226 tmpfs_pool_destroy(&tsp->tsp_pool_1024);
229 /* --------------------------------------------------------------------- */
232 * Allocate a new string with a minimum length of len from the 'tsp'
233 * string pool. The pool can return a bigger string, but the caller must
234 * not make any assumptions about the real object size.
236 char *
237 tmpfs_str_pool_get(struct tmpfs_str_pool *tsp, size_t len, int flags)
239 struct tmpfs_pool *p;
241 KASSERT(len <= 1024);
243 if (len <= 16) p = &tsp->tsp_pool_16;
244 else if (len <= 32) p = &tsp->tsp_pool_32;
245 else if (len <= 64) p = &tsp->tsp_pool_64;
246 else if (len <= 128) p = &tsp->tsp_pool_128;
247 else if (len <= 256) p = &tsp->tsp_pool_256;
248 else if (len <= 512) p = &tsp->tsp_pool_512;
249 else if (len <= 1024) p = &tsp->tsp_pool_1024;
250 else {
251 KASSERT(0);
252 p = NULL; /* Silence compiler warnings */
255 return (char *)TMPFS_POOL_GET(p, flags);
258 /* --------------------------------------------------------------------- */
261 * Destroy the str string, which was allocated from the 'tsp' string pool
262 * with a length of 'len'. The length must match the one given during
263 * allocation.
265 void
266 tmpfs_str_pool_put(struct tmpfs_str_pool *tsp, char *str, size_t len)
268 struct tmpfs_pool *p;
270 KASSERT(len <= 1024);
272 if (len <= 16) p = &tsp->tsp_pool_16;
273 else if (len <= 32) p = &tsp->tsp_pool_32;
274 else if (len <= 64) p = &tsp->tsp_pool_64;
275 else if (len <= 128) p = &tsp->tsp_pool_128;
276 else if (len <= 256) p = &tsp->tsp_pool_256;
277 else if (len <= 512) p = &tsp->tsp_pool_512;
278 else if (len <= 1024) p = &tsp->tsp_pool_1024;
279 else {
280 KASSERT(0);
281 p = NULL; /* Silence compiler warnings */
284 TMPFS_POOL_PUT(p, str);