1*6eefdf9fSbeck /* $OpenBSD: tmpfs_mem.c,v 1.8 2015/12/11 22:34:34 beck Exp $ */
27013b092Sespie /* $NetBSD: tmpfs_mem.c,v 1.4 2011/05/24 01:09:47 rmind Exp $ */
37013b092Sespie
47013b092Sespie /*
57013b092Sespie * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
67013b092Sespie * All rights reserved.
77013b092Sespie *
87013b092Sespie * This code is derived from software contributed to The NetBSD Foundation
97013b092Sespie * by Mindaugas Rasiukevicius.
107013b092Sespie *
117013b092Sespie * Redistribution and use in source and binary forms, with or without
127013b092Sespie * modification, are permitted provided that the following conditions
137013b092Sespie * are met:
147013b092Sespie * 1. Redistributions of source code must retain the above copyright
157013b092Sespie * notice, this list of conditions and the following disclaimer.
167013b092Sespie * 2. Redistributions in binary form must reproduce the above copyright
177013b092Sespie * notice, this list of conditions and the following disclaimer in the
187013b092Sespie * documentation and/or other materials provided with the distribution.
197013b092Sespie *
207013b092Sespie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
217013b092Sespie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
227013b092Sespie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
237013b092Sespie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
247013b092Sespie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
257013b092Sespie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
267013b092Sespie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
277013b092Sespie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
287013b092Sespie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
297013b092Sespie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
307013b092Sespie * POSSIBILITY OF SUCH DAMAGE.
317013b092Sespie */
327013b092Sespie
337013b092Sespie /*
347013b092Sespie * tmpfs memory allocation routines.
357013b092Sespie * Implements memory usage accounting and limiting.
367013b092Sespie */
377013b092Sespie
387013b092Sespie #include <sys/param.h>
397013b092Sespie #include <sys/namei.h>
407013b092Sespie #include <sys/pool.h>
417013b092Sespie #include <sys/vnode.h>
427013b092Sespie #include <sys/malloc.h>
437013b092Sespie
447013b092Sespie #include <tmpfs/tmpfs.h>
457013b092Sespie
467013b092Sespie extern struct pool tmpfs_dirent_pool;
477013b092Sespie extern struct pool tmpfs_node_pool;
487013b092Sespie
497013b092Sespie void
tmpfs_mntmem_init(struct tmpfs_mount * mp,uint64_t memlimit)507013b092Sespie tmpfs_mntmem_init(struct tmpfs_mount *mp, uint64_t memlimit)
517013b092Sespie {
527013b092Sespie
537013b092Sespie rw_init(&mp->tm_acc_lock, "tacclk");
547013b092Sespie mp->tm_mem_limit = memlimit;
557013b092Sespie mp->tm_bytes_used = 0;
567013b092Sespie }
577013b092Sespie
587013b092Sespie void
tmpfs_mntmem_destroy(struct tmpfs_mount * mp)597013b092Sespie tmpfs_mntmem_destroy(struct tmpfs_mount *mp)
607013b092Sespie {
617013b092Sespie
627013b092Sespie KASSERT(mp->tm_bytes_used == 0);
637013b092Sespie /* mutex_destroy(&mp->tm_acc_lock); */
647013b092Sespie }
657013b092Sespie
667013b092Sespie /*
677013b092Sespie * tmpfs_mem_info: return the number of available memory pages.
687013b092Sespie *
697013b092Sespie * => If 'total' is true, then return _total_ amount of pages.
707013b092Sespie * => If false, then return the amount of _free_ memory pages.
717013b092Sespie *
727013b092Sespie * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
737013b092Sespie * excessive memory usage.
747013b092Sespie */
757013b092Sespie size_t
tmpfs_mem_info(int total)767013b092Sespie tmpfs_mem_info(int total)
777013b092Sespie {
787013b092Sespie int size = 0;
797013b092Sespie
807013b092Sespie /* XXX: unlocked */
817013b092Sespie size += uvmexp.swpages;
827013b092Sespie if (!total) {
837013b092Sespie size -= uvmexp.swpgonly;
847013b092Sespie }
857013b092Sespie
867013b092Sespie size += uvmexp.free;
877013b092Sespie /* size += uvmexp.filepages; */
887013b092Sespie if (size > uvmexp.wired) {
897013b092Sespie size -= uvmexp.wired;
907013b092Sespie } else {
917013b092Sespie size = 0;
927013b092Sespie }
937013b092Sespie
947013b092Sespie KASSERT(size >= 0);
957013b092Sespie
967013b092Sespie return (size_t)size;
977013b092Sespie }
987013b092Sespie
997013b092Sespie uint64_t
tmpfs_bytes_max(struct tmpfs_mount * mp)1007013b092Sespie tmpfs_bytes_max(struct tmpfs_mount *mp)
1017013b092Sespie {
1027013b092Sespie size_t freepages = tmpfs_mem_info(0);
1037013b092Sespie uint64_t avail_mem;
1047013b092Sespie
1057013b092Sespie if (freepages < TMPFS_PAGES_RESERVED) {
1067013b092Sespie freepages = 0;
1077013b092Sespie } else {
1087013b092Sespie freepages -= TMPFS_PAGES_RESERVED;
1097013b092Sespie }
1107013b092Sespie avail_mem = round_page(mp->tm_bytes_used) + (freepages << PAGE_SHIFT);
1117013b092Sespie return MIN(mp->tm_mem_limit, avail_mem);
1127013b092Sespie }
1137013b092Sespie
1147013b092Sespie uint64_t
tmpfs_pages_avail(struct tmpfs_mount * mp)1157013b092Sespie tmpfs_pages_avail(struct tmpfs_mount *mp)
1167013b092Sespie {
1177013b092Sespie
1187013b092Sespie return (tmpfs_bytes_max(mp) - mp->tm_bytes_used) >> PAGE_SHIFT;
1197013b092Sespie }
1207013b092Sespie
1217013b092Sespie int
tmpfs_mem_incr(struct tmpfs_mount * mp,size_t sz)1227013b092Sespie tmpfs_mem_incr(struct tmpfs_mount *mp, size_t sz)
1237013b092Sespie {
1247013b092Sespie uint64_t lim;
1257013b092Sespie
1267013b092Sespie rw_enter_write(&mp->tm_acc_lock);
1277013b092Sespie lim = tmpfs_bytes_max(mp);
1287013b092Sespie if (mp->tm_bytes_used + sz >= lim) {
1297013b092Sespie rw_exit_write(&mp->tm_acc_lock);
1307013b092Sespie return 0;
1317013b092Sespie }
1327013b092Sespie mp->tm_bytes_used += sz;
1337013b092Sespie rw_exit_write(&mp->tm_acc_lock);
1347013b092Sespie return 1;
1357013b092Sespie }
1367013b092Sespie
1377013b092Sespie void
tmpfs_mem_decr(struct tmpfs_mount * mp,size_t sz)1387013b092Sespie tmpfs_mem_decr(struct tmpfs_mount *mp, size_t sz)
1397013b092Sespie {
1407013b092Sespie
1417013b092Sespie rw_enter_write(&mp->tm_acc_lock);
1427013b092Sespie KASSERT(mp->tm_bytes_used >= sz);
1437013b092Sespie mp->tm_bytes_used -= sz;
1447013b092Sespie rw_exit_write(&mp->tm_acc_lock);
1457013b092Sespie }
1467013b092Sespie
1477013b092Sespie struct tmpfs_dirent *
tmpfs_dirent_get(struct tmpfs_mount * mp)1487013b092Sespie tmpfs_dirent_get(struct tmpfs_mount *mp)
1497013b092Sespie {
1507013b092Sespie
1517013b092Sespie if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_dirent))) {
1527013b092Sespie return NULL;
1537013b092Sespie }
154*6eefdf9fSbeck return pool_get(&tmpfs_dirent_pool, PR_ZERO|PR_WAITOK);
1557013b092Sespie }
1567013b092Sespie
1577013b092Sespie void
tmpfs_dirent_put(struct tmpfs_mount * mp,struct tmpfs_dirent * de)1587013b092Sespie tmpfs_dirent_put(struct tmpfs_mount *mp, struct tmpfs_dirent *de)
1597013b092Sespie {
1607013b092Sespie
1617013b092Sespie tmpfs_mem_decr(mp, sizeof(struct tmpfs_dirent));
1627013b092Sespie pool_put(&tmpfs_dirent_pool, de);
1637013b092Sespie }
1647013b092Sespie
1657013b092Sespie struct tmpfs_node *
tmpfs_node_get(struct tmpfs_mount * mp)1667013b092Sespie tmpfs_node_get(struct tmpfs_mount *mp)
1677013b092Sespie {
1687013b092Sespie
1697013b092Sespie mp->tm_nodes_cnt++;
1707013b092Sespie if (mp->tm_nodes_cnt > mp->tm_nodes_max) {
1717013b092Sespie mp->tm_nodes_cnt--;
1727013b092Sespie return NULL;
1737013b092Sespie }
1747013b092Sespie if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_node))) {
1757013b092Sespie return NULL;
1767013b092Sespie }
1777013b092Sespie return pool_get(&tmpfs_node_pool, PR_WAITOK);
1787013b092Sespie }
1797013b092Sespie
1807013b092Sespie void
tmpfs_node_put(struct tmpfs_mount * mp,struct tmpfs_node * tn)1817013b092Sespie tmpfs_node_put(struct tmpfs_mount *mp, struct tmpfs_node *tn)
1827013b092Sespie {
1837013b092Sespie
1847013b092Sespie mp->tm_nodes_cnt--;
1857013b092Sespie tmpfs_mem_decr(mp, sizeof(struct tmpfs_node));
1867013b092Sespie pool_put(&tmpfs_node_pool, tn);
1877013b092Sespie }
1887013b092Sespie
1897013b092Sespie /*
1907013b092Sespie * Quantum size to round-up the tmpfs names in order to reduce re-allocations.
1917013b092Sespie */
1927013b092Sespie
1937013b092Sespie #define TMPFS_NAME_QUANTUM (32)
1947013b092Sespie #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
1957013b092Sespie
1967013b092Sespie char *
tmpfs_strname_alloc(struct tmpfs_mount * mp,size_t len)1977013b092Sespie tmpfs_strname_alloc(struct tmpfs_mount *mp, size_t len)
1987013b092Sespie {
1997013b092Sespie const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);
2007013b092Sespie
2017013b092Sespie KASSERT(sz > 0 && sz <= 1024);
2027013b092Sespie if (!tmpfs_mem_incr(mp, sz)) {
2037013b092Sespie return NULL;
2047013b092Sespie }
2057013b092Sespie return malloc(sz, M_TEMP, M_WAITOK); /* XXX */
2067013b092Sespie }
2077013b092Sespie
2087013b092Sespie void
tmpfs_strname_free(struct tmpfs_mount * mp,char * str,size_t len)2097013b092Sespie tmpfs_strname_free(struct tmpfs_mount *mp, char *str, size_t len)
2107013b092Sespie {
2117013b092Sespie const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);
2127013b092Sespie
2137013b092Sespie KASSERT(sz > 0 && sz <= 1024);
2147013b092Sespie tmpfs_mem_decr(mp, sz);
21537742db1Stedu free(str, M_TEMP, sz);
2167013b092Sespie }
2177013b092Sespie
2187013b092Sespie int
tmpfs_strname_neqlen(struct componentname * fcnp,struct componentname * tcnp)2197013b092Sespie tmpfs_strname_neqlen(struct componentname *fcnp, struct componentname *tcnp)
2207013b092Sespie {
2217013b092Sespie const size_t fln = roundup2(fcnp->cn_namelen, TMPFS_NAME_QUANTUM);
2227013b092Sespie const size_t tln = roundup2(tcnp->cn_namelen, TMPFS_NAME_QUANTUM);
2237013b092Sespie
2247013b092Sespie return (fln != tln) || memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fln);
2257013b092Sespie }
226