xref: /openbsd-src/sys/tmpfs/tmpfs_mem.c (revision 6eefdf9f5856092cb525eeecba307869e8fd6234)
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