jcs's openbsd hax
openbsd
1/* $OpenBSD: tmpfs_mem.c,v 1.11 2025/11/21 09:49:33 mvs Exp $ */
2/* $NetBSD: tmpfs_mem.c,v 1.4 2011/05/24 01:09:47 rmind Exp $ */
3
4/*
5 * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Mindaugas Rasiukevicius.
10 *
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.
19 *
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.
31 */
32
33/*
34 * tmpfs memory allocation routines.
35 * Implements memory usage accounting and limiting.
36 */
37
38#include <sys/param.h>
39#include <sys/namei.h>
40#include <sys/pool.h>
41#include <sys/vnode.h>
42#include <sys/malloc.h>
43
44#include <tmpfs/tmpfs.h>
45
46extern struct pool tmpfs_dirent_pool;
47extern struct pool tmpfs_node_pool;
48
49uint64_t tmpfs_bytes_limit;
50uint64_t tmpfs_bytes_used = 0;
51
52void
53tmpfs_mntmem_init(struct tmpfs_mount *mp, uint64_t memlimit)
54{
55
56 rw_init(&mp->tm_acc_lock, "tacclk");
57 mp->tm_mem_limit = memlimit;
58 mp->tm_bytes_used = 0;
59}
60
61void
62tmpfs_mntmem_destroy(struct tmpfs_mount *mp)
63{
64
65 KASSERT(mp->tm_bytes_used == 0);
66 /* mutex_destroy(&mp->tm_acc_lock); */
67}
68
69uint64_t
70tmpfs_pages_total(struct tmpfs_mount *mp)
71{
72 uint64_t total;
73
74 if (mp->tm_mem_limit)
75 total = mp->tm_mem_limit;
76 else {
77 total = tmpfs_bytes_limit - tmpfs_bytes_used +
78 mp->tm_bytes_used;
79 }
80
81 return (total >> PAGE_SHIFT);
82}
83
84uint64_t
85tmpfs_pages_avail(struct tmpfs_mount *mp)
86{
87 uint64_t free;
88
89 rw_assert_anylock(&mp->tm_acc_lock);
90
91 if (mp->tm_mem_limit)
92 free = mp->tm_mem_limit - mp->tm_bytes_used;
93 else
94 free = tmpfs_bytes_limit - tmpfs_bytes_used;
95
96 return (free >> PAGE_SHIFT);
97}
98
99int
100tmpfs_mem_incr(struct tmpfs_mount *mp, size_t sz)
101{
102 int ret = 0;
103
104 rw_enter_write(&mp->tm_acc_lock);
105
106 if (mp->tm_mem_limit) {
107 if ((mp->tm_mem_limit - mp->tm_bytes_used) < sz)
108 goto out;
109 } else {
110 if ((tmpfs_bytes_limit - tmpfs_bytes_used) < sz)
111 goto out;
112 tmpfs_bytes_used += sz;
113 }
114
115 mp->tm_bytes_used += sz;
116
117 ret = 1;
118out:
119 rw_exit_write(&mp->tm_acc_lock);
120
121 return ret;
122}
123
124void
125tmpfs_mem_decr(struct tmpfs_mount *mp, size_t sz)
126{
127 rw_enter_write(&mp->tm_acc_lock);
128 KASSERT(mp->tm_bytes_used >= sz);
129 if (mp->tm_mem_limit == 0)
130 tmpfs_bytes_used -= sz;
131 mp->tm_bytes_used -= sz;
132 rw_exit_write(&mp->tm_acc_lock);
133}
134
135struct tmpfs_dirent *
136tmpfs_dirent_get(struct tmpfs_mount *mp)
137{
138
139 if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_dirent))) {
140 return NULL;
141 }
142 return pool_get(&tmpfs_dirent_pool, PR_ZERO|PR_WAITOK);
143}
144
145void
146tmpfs_dirent_put(struct tmpfs_mount *mp, struct tmpfs_dirent *de)
147{
148
149 tmpfs_mem_decr(mp, sizeof(struct tmpfs_dirent));
150 pool_put(&tmpfs_dirent_pool, de);
151}
152
153struct tmpfs_node *
154tmpfs_node_get(struct tmpfs_mount *mp)
155{
156
157 mp->tm_nodes_cnt++;
158 if (mp->tm_nodes_cnt > mp->tm_nodes_max) {
159 mp->tm_nodes_cnt--;
160 return NULL;
161 }
162 if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_node))) {
163 mp->tm_nodes_cnt--;
164 return NULL;
165 }
166 return pool_get(&tmpfs_node_pool, PR_WAITOK);
167}
168
169void
170tmpfs_node_put(struct tmpfs_mount *mp, struct tmpfs_node *tn)
171{
172
173 mp->tm_nodes_cnt--;
174 tmpfs_mem_decr(mp, sizeof(struct tmpfs_node));
175 pool_put(&tmpfs_node_pool, tn);
176}
177
178/*
179 * Quantum size to round-up the tmpfs names in order to reduce re-allocations.
180 */
181
182#define TMPFS_NAME_QUANTUM (32)
183#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
184
185char *
186tmpfs_strname_alloc(struct tmpfs_mount *mp, size_t len)
187{
188 const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);
189
190 KASSERT(sz > 0 && sz <= 1024);
191 if (!tmpfs_mem_incr(mp, sz)) {
192 return NULL;
193 }
194 return malloc(sz, M_TEMP, M_WAITOK); /* XXX */
195}
196
197void
198tmpfs_strname_free(struct tmpfs_mount *mp, char *str, size_t len)
199{
200 const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);
201
202 KASSERT(sz > 0 && sz <= 1024);
203 tmpfs_mem_decr(mp, sz);
204 free(str, M_TEMP, sz);
205}
206
207int
208tmpfs_strname_neqlen(struct componentname *fcnp, struct componentname *tcnp)
209{
210 const size_t fln = roundup2(fcnp->cn_namelen, TMPFS_NAME_QUANTUM);
211 const size_t tln = roundup2(tcnp->cn_namelen, TMPFS_NAME_QUANTUM);
212
213 return (fln != tln) || memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fln);
214}