xref: /freebsd/sys/fs/pseudofs/pseudofs_fileno.c (revision 104a9b7e3edbd88cdda0698c5c77a2ad6dafcc16)
19733a808SDag-Erling Smørgrav /*-
29733a808SDag-Erling Smørgrav  * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
39733a808SDag-Erling Smørgrav  * All rights reserved.
49733a808SDag-Erling Smørgrav  *
59733a808SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
69733a808SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
79733a808SDag-Erling Smørgrav  * are met:
89733a808SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
99733a808SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer
109733a808SDag-Erling Smørgrav  *    in this position and unchanged.
119733a808SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
129733a808SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
139733a808SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
149733a808SDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote products
159733a808SDag-Erling Smørgrav  *    derived from this software without specific prior written permission.
169733a808SDag-Erling Smørgrav  *
179733a808SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189733a808SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199733a808SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209733a808SDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219733a808SDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229733a808SDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239733a808SDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249733a808SDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259733a808SDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269733a808SDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279733a808SDag-Erling Smørgrav  *
289733a808SDag-Erling Smørgrav  *      $FreeBSD$
299733a808SDag-Erling Smørgrav  */
309733a808SDag-Erling Smørgrav 
319733a808SDag-Erling Smørgrav #include <sys/param.h>
329733a808SDag-Erling Smørgrav #include <sys/kernel.h>
339733a808SDag-Erling Smørgrav #include <sys/systm.h>
34104a9b7eSAlexander Kabaev #include <sys/limits.h>
3521ceb6efSDag-Erling Smørgrav #include <sys/lock.h>
369733a808SDag-Erling Smørgrav #include <sys/malloc.h>
3749fa664fSDag-Erling Smørgrav #include <sys/mutex.h>
389733a808SDag-Erling Smørgrav #include <sys/sysctl.h>
399733a808SDag-Erling Smørgrav 
409733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs.h>
419733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs_internal.h>
429733a808SDag-Erling Smørgrav 
43649ad985SDag-Erling Smørgrav static MALLOC_DEFINE(M_PFSFILENO, "pfs_fileno", "pseudofs fileno bitmap");
449733a808SDag-Erling Smørgrav 
459733a808SDag-Erling Smørgrav static struct mtx pfs_fileno_mutex;
469733a808SDag-Erling Smørgrav 
479733a808SDag-Erling Smørgrav #define PFS_BITMAP_SIZE	4096
48649ad985SDag-Erling Smørgrav #define PFS_SLOT_BITS	(int)(sizeof(unsigned int) * CHAR_BIT)
499733a808SDag-Erling Smørgrav #define PFS_BITMAP_BITS	(PFS_BITMAP_SIZE * PFS_SLOT_BITS)
509733a808SDag-Erling Smørgrav struct pfs_bitmap {
519733a808SDag-Erling Smørgrav 	u_int32_t		 pb_offset;
529733a808SDag-Erling Smørgrav 	int			 pb_used;
539733a808SDag-Erling Smørgrav 	unsigned int		 pb_bitmap[PFS_BITMAP_SIZE];
549733a808SDag-Erling Smørgrav 	struct pfs_bitmap	*pb_next;
559733a808SDag-Erling Smørgrav };
569733a808SDag-Erling Smørgrav 
579733a808SDag-Erling Smørgrav /*
589733a808SDag-Erling Smørgrav  * Initialization
599733a808SDag-Erling Smørgrav  */
609733a808SDag-Erling Smørgrav void
619733a808SDag-Erling Smørgrav pfs_fileno_load(void)
629733a808SDag-Erling Smørgrav {
636008862bSJohn Baldwin 	mtx_init(&pfs_fileno_mutex, "pseudofs_fileno", NULL, MTX_DEF);
649733a808SDag-Erling Smørgrav }
659733a808SDag-Erling Smørgrav 
669733a808SDag-Erling Smørgrav /*
679733a808SDag-Erling Smørgrav  * Teardown
689733a808SDag-Erling Smørgrav  */
699733a808SDag-Erling Smørgrav void
709733a808SDag-Erling Smørgrav pfs_fileno_unload(void)
719733a808SDag-Erling Smørgrav {
729733a808SDag-Erling Smørgrav 	mtx_destroy(&pfs_fileno_mutex);
739733a808SDag-Erling Smørgrav }
749733a808SDag-Erling Smørgrav 
759733a808SDag-Erling Smørgrav /*
769733a808SDag-Erling Smørgrav  * Initialize fileno bitmap
779733a808SDag-Erling Smørgrav  */
789733a808SDag-Erling Smørgrav void
799733a808SDag-Erling Smørgrav pfs_fileno_init(struct pfs_info *pi)
809733a808SDag-Erling Smørgrav {
819733a808SDag-Erling Smørgrav 	struct pfs_bitmap *pb;
829733a808SDag-Erling Smørgrav 
839733a808SDag-Erling Smørgrav 	MALLOC(pb, struct pfs_bitmap *, sizeof *pb,
84a163d034SWarner Losh 	    M_PFSFILENO, M_WAITOK|M_ZERO);
859733a808SDag-Erling Smørgrav 
869733a808SDag-Erling Smørgrav 	mtx_lock(&pi->pi_mutex);
879733a808SDag-Erling Smørgrav 
889733a808SDag-Erling Smørgrav 	pb->pb_bitmap[0] = 07;
899733a808SDag-Erling Smørgrav 	pb->pb_used = 3;
909733a808SDag-Erling Smørgrav 	pi->pi_bitmap = pb;
919733a808SDag-Erling Smørgrav 	pi->pi_root->pn_fileno = 2;
929733a808SDag-Erling Smørgrav 
939733a808SDag-Erling Smørgrav 	mtx_unlock(&pi->pi_mutex);
949733a808SDag-Erling Smørgrav }
959733a808SDag-Erling Smørgrav 
969733a808SDag-Erling Smørgrav /*
979733a808SDag-Erling Smørgrav  * Tear down fileno bitmap
989733a808SDag-Erling Smørgrav  */
999733a808SDag-Erling Smørgrav void
1009733a808SDag-Erling Smørgrav pfs_fileno_uninit(struct pfs_info *pi)
1019733a808SDag-Erling Smørgrav {
1029733a808SDag-Erling Smørgrav 	struct pfs_bitmap *pb, *npb;
1039733a808SDag-Erling Smørgrav 	int used;
1049733a808SDag-Erling Smørgrav 
1059733a808SDag-Erling Smørgrav 	mtx_lock(&pi->pi_mutex);
1069733a808SDag-Erling Smørgrav 
1079733a808SDag-Erling Smørgrav 	pb = pi->pi_bitmap;
1089733a808SDag-Erling Smørgrav 	pi->pi_bitmap = NULL;
1099733a808SDag-Erling Smørgrav 
1109733a808SDag-Erling Smørgrav 	mtx_unlock(&pi->pi_mutex);
1119733a808SDag-Erling Smørgrav 
1129733a808SDag-Erling Smørgrav 	for (used = 0; pb; pb = npb) {
1139733a808SDag-Erling Smørgrav 		npb = pb->pb_next;
1149733a808SDag-Erling Smørgrav 		used += pb->pb_used;
1159733a808SDag-Erling Smørgrav 		FREE(pb, M_PFSFILENO);
1169733a808SDag-Erling Smørgrav 	}
117649ad985SDag-Erling Smørgrav #if 0
118649ad985SDag-Erling Smørgrav 	/* we currently don't reclaim filenos */
1199733a808SDag-Erling Smørgrav 	if (used > 2)
1209733a808SDag-Erling Smørgrav 		printf("WARNING: %d file numbers still in use\n", used);
121649ad985SDag-Erling Smørgrav #endif
1229733a808SDag-Erling Smørgrav }
1239733a808SDag-Erling Smørgrav 
1249733a808SDag-Erling Smørgrav /*
1259733a808SDag-Erling Smørgrav  * Get the next available file number
1269733a808SDag-Erling Smørgrav  */
1279733a808SDag-Erling Smørgrav static u_int32_t
1289733a808SDag-Erling Smørgrav pfs_get_fileno(struct pfs_info *pi)
1299733a808SDag-Erling Smørgrav {
1309733a808SDag-Erling Smørgrav 	struct pfs_bitmap *pb, *ppb;
1319733a808SDag-Erling Smørgrav 	u_int32_t fileno;
1329733a808SDag-Erling Smørgrav 	unsigned int *p;
1339733a808SDag-Erling Smørgrav 	int i;
1349733a808SDag-Erling Smørgrav 
1359733a808SDag-Erling Smørgrav 	mtx_lock(&pi->pi_mutex);
1369733a808SDag-Erling Smørgrav 
1379733a808SDag-Erling Smørgrav 	/* look for the first page with free bits */
1389733a808SDag-Erling Smørgrav 	for (ppb = NULL, pb = pi->pi_bitmap; pb; ppb = pb, pb = pb->pb_next)
1399733a808SDag-Erling Smørgrav 		if (pb->pb_used != PFS_BITMAP_BITS)
1409733a808SDag-Erling Smørgrav 			break;
1419733a808SDag-Erling Smørgrav 
1429733a808SDag-Erling Smørgrav 	/* out of pages? */
1439733a808SDag-Erling Smørgrav 	if (pb == NULL) {
1449733a808SDag-Erling Smørgrav 		mtx_unlock(&pi->pi_mutex);
1459733a808SDag-Erling Smørgrav 		MALLOC(pb, struct pfs_bitmap *, sizeof *pb,
146a163d034SWarner Losh 		    M_PFSFILENO, M_WAITOK|M_ZERO);
1479733a808SDag-Erling Smørgrav 		mtx_lock(&pi->pi_mutex);
1489733a808SDag-Erling Smørgrav 		/* protect against possible race */
1499733a808SDag-Erling Smørgrav 		while (ppb->pb_next)
1509733a808SDag-Erling Smørgrav 			ppb = ppb->pb_next;
1519733a808SDag-Erling Smørgrav 		pb->pb_offset = ppb->pb_offset + PFS_BITMAP_BITS;
1529733a808SDag-Erling Smørgrav 		ppb->pb_next = pb;
1539733a808SDag-Erling Smørgrav 	}
1549733a808SDag-Erling Smørgrav 
1559733a808SDag-Erling Smørgrav 	/* find the first free slot */
1569733a808SDag-Erling Smørgrav 	for (i = 0; i < PFS_BITMAP_SIZE; ++i)
1579733a808SDag-Erling Smørgrav 		if (pb->pb_bitmap[i] != UINT_MAX)
1589733a808SDag-Erling Smørgrav 			break;
1599733a808SDag-Erling Smørgrav 
1609733a808SDag-Erling Smørgrav 	/* find the first available bit and flip it */
1619733a808SDag-Erling Smørgrav 	fileno = pb->pb_offset + i * PFS_SLOT_BITS;
1629733a808SDag-Erling Smørgrav 	p = &pb->pb_bitmap[i];
1639733a808SDag-Erling Smørgrav 	for (i = 0; i < PFS_SLOT_BITS; ++i, ++fileno)
1649733a808SDag-Erling Smørgrav 		if ((*p & (unsigned int)(1 << i)) == 0)
1659733a808SDag-Erling Smørgrav 			break;
1669733a808SDag-Erling Smørgrav 	KASSERT(i < PFS_SLOT_BITS,
1679733a808SDag-Erling Smørgrav 	    ("slot has free bits, yet doesn't"));
1689733a808SDag-Erling Smørgrav 	*p |= (unsigned int)(1 << i);
1699733a808SDag-Erling Smørgrav 	++pb->pb_used;
1709733a808SDag-Erling Smørgrav 
1719733a808SDag-Erling Smørgrav 	mtx_unlock(&pi->pi_mutex);
1729733a808SDag-Erling Smørgrav 
1739733a808SDag-Erling Smørgrav 	return fileno;
1749733a808SDag-Erling Smørgrav }
1759733a808SDag-Erling Smørgrav 
1769733a808SDag-Erling Smørgrav /*
1779733a808SDag-Erling Smørgrav  * Free a file number
1789733a808SDag-Erling Smørgrav  */
1799733a808SDag-Erling Smørgrav static void
1809733a808SDag-Erling Smørgrav pfs_free_fileno(struct pfs_info *pi, u_int32_t fileno)
1819733a808SDag-Erling Smørgrav {
1829733a808SDag-Erling Smørgrav 	struct pfs_bitmap *pb;
1839733a808SDag-Erling Smørgrav 	unsigned int *p;
1849733a808SDag-Erling Smørgrav 	int i;
1859733a808SDag-Erling Smørgrav 
1869733a808SDag-Erling Smørgrav 	mtx_lock(&pi->pi_mutex);
1879733a808SDag-Erling Smørgrav 
1889733a808SDag-Erling Smørgrav 	/* find the right page */
1899733a808SDag-Erling Smørgrav 	for (pb = pi->pi_bitmap;
1909733a808SDag-Erling Smørgrav 	     pb && fileno >= PFS_BITMAP_BITS;
1919733a808SDag-Erling Smørgrav 	     pb = pb->pb_next, fileno -= PFS_BITMAP_BITS)
1929733a808SDag-Erling Smørgrav 		/* nothing */ ;
1939733a808SDag-Erling Smørgrav 	KASSERT(pb,
1949733a808SDag-Erling Smørgrav 	    ("fileno isn't in any bitmap"));
1959733a808SDag-Erling Smørgrav 
1969733a808SDag-Erling Smørgrav 	/* find the right bit in the right slot and flip it */
1979733a808SDag-Erling Smørgrav 	p = &pb->pb_bitmap[fileno / PFS_SLOT_BITS];
1989733a808SDag-Erling Smørgrav 	i = fileno % PFS_SLOT_BITS;
1999733a808SDag-Erling Smørgrav 	KASSERT(*p & (unsigned int)(1 << i),
2009733a808SDag-Erling Smørgrav 	    ("fileno is already free"));
2019733a808SDag-Erling Smørgrav 	*p &= ~((unsigned int)(1 << i));
2029733a808SDag-Erling Smørgrav 	--pb->pb_used;
2039733a808SDag-Erling Smørgrav 
2049733a808SDag-Erling Smørgrav 	mtx_unlock(&pi->pi_mutex);
205649ad985SDag-Erling Smørgrav 	printf("pfs_free_fileno(): reclaimed %d\n", fileno);
2069733a808SDag-Erling Smørgrav }
2079733a808SDag-Erling Smørgrav 
2089733a808SDag-Erling Smørgrav /*
2099733a808SDag-Erling Smørgrav  * Allocate a file number
2109733a808SDag-Erling Smørgrav  */
2119733a808SDag-Erling Smørgrav void
2129733a808SDag-Erling Smørgrav pfs_fileno_alloc(struct pfs_info *pi, struct pfs_node *pn)
2139733a808SDag-Erling Smørgrav {
2149733a808SDag-Erling Smørgrav 	/* make sure our parent has a file number */
2159733a808SDag-Erling Smørgrav 	if (pn->pn_parent && !pn->pn_parent->pn_fileno)
2169733a808SDag-Erling Smørgrav 		pfs_fileno_alloc(pi, pn->pn_parent);
2179733a808SDag-Erling Smørgrav 
2189733a808SDag-Erling Smørgrav 	switch (pn->pn_type) {
2199733a808SDag-Erling Smørgrav 	case pfstype_root:
2209733a808SDag-Erling Smørgrav 	case pfstype_dir:
2219733a808SDag-Erling Smørgrav 	case pfstype_file:
2229733a808SDag-Erling Smørgrav 	case pfstype_symlink:
223649ad985SDag-Erling Smørgrav 	case pfstype_procdir:
2249733a808SDag-Erling Smørgrav 		pn->pn_fileno = pfs_get_fileno(pi);
2259733a808SDag-Erling Smørgrav 		break;
2269733a808SDag-Erling Smørgrav 	case pfstype_this:
2279733a808SDag-Erling Smørgrav 		KASSERT(pn->pn_parent != NULL,
2289733a808SDag-Erling Smørgrav 		    ("pfstype_this node has no parent"));
2299733a808SDag-Erling Smørgrav 		pn->pn_fileno = pn->pn_parent->pn_fileno;
2309733a808SDag-Erling Smørgrav 		break;
2319733a808SDag-Erling Smørgrav 	case pfstype_parent:
2329733a808SDag-Erling Smørgrav 		KASSERT(pn->pn_parent != NULL,
2339733a808SDag-Erling Smørgrav 		    ("pfstype_parent node has no parent"));
2349733a808SDag-Erling Smørgrav 		if (pn->pn_parent == pi->pi_root) {
2359733a808SDag-Erling Smørgrav 			pn->pn_fileno = pn->pn_parent->pn_fileno;
2369733a808SDag-Erling Smørgrav 			break;
2379733a808SDag-Erling Smørgrav 		}
2389733a808SDag-Erling Smørgrav 		KASSERT(pn->pn_parent->pn_parent != NULL,
2399733a808SDag-Erling Smørgrav 		    ("pfstype_parent node has no grandparent"));
2409733a808SDag-Erling Smørgrav 		pn->pn_fileno = pn->pn_parent->pn_parent->pn_fileno;
2419733a808SDag-Erling Smørgrav 		break;
2429733a808SDag-Erling Smørgrav 	case pfstype_none:
243649ad985SDag-Erling Smørgrav 		KASSERT(0,
2449733a808SDag-Erling Smørgrav 		    ("pfs_fileno_alloc() called for pfstype_none node"));
2459733a808SDag-Erling Smørgrav 		break;
2469733a808SDag-Erling Smørgrav 	}
2479733a808SDag-Erling Smørgrav 
248649ad985SDag-Erling Smørgrav #if 0
2499733a808SDag-Erling Smørgrav 	printf("pfs_fileno_alloc(): %s: ", pi->pi_name);
2509733a808SDag-Erling Smørgrav 	if (pn->pn_parent) {
2519733a808SDag-Erling Smørgrav 		if (pn->pn_parent->pn_parent) {
2529733a808SDag-Erling Smørgrav 			printf("%s/", pn->pn_parent->pn_parent->pn_name);
2539733a808SDag-Erling Smørgrav 		}
2549733a808SDag-Erling Smørgrav 		printf("%s/", pn->pn_parent->pn_name);
2559733a808SDag-Erling Smørgrav 	}
2569733a808SDag-Erling Smørgrav 	printf("%s -> %d\n", pn->pn_name, pn->pn_fileno);
257649ad985SDag-Erling Smørgrav #endif
2589733a808SDag-Erling Smørgrav }
2599733a808SDag-Erling Smørgrav 
2609733a808SDag-Erling Smørgrav /*
2619733a808SDag-Erling Smørgrav  * Release a file number
2629733a808SDag-Erling Smørgrav  */
2639733a808SDag-Erling Smørgrav void
2649733a808SDag-Erling Smørgrav pfs_fileno_free(struct pfs_info *pi, struct pfs_node *pn)
2659733a808SDag-Erling Smørgrav {
2669733a808SDag-Erling Smørgrav 	switch (pn->pn_type) {
2679733a808SDag-Erling Smørgrav 	case pfstype_root:
2689733a808SDag-Erling Smørgrav 	case pfstype_dir:
2699733a808SDag-Erling Smørgrav 	case pfstype_file:
2709733a808SDag-Erling Smørgrav 	case pfstype_symlink:
271649ad985SDag-Erling Smørgrav 	case pfstype_procdir:
2729733a808SDag-Erling Smørgrav 		pfs_free_fileno(pi, pn->pn_fileno);
2739733a808SDag-Erling Smørgrav 		break;
2749733a808SDag-Erling Smørgrav 	case pfstype_this:
2759733a808SDag-Erling Smørgrav 	case pfstype_parent:
2769733a808SDag-Erling Smørgrav 		/* ignore these, as they don't "own" their file number */
2779733a808SDag-Erling Smørgrav 		break;
2789733a808SDag-Erling Smørgrav 	case pfstype_none:
279649ad985SDag-Erling Smørgrav 		KASSERT(0,
2809733a808SDag-Erling Smørgrav 		    ("pfs_fileno_free() called for pfstype_none node"));
2819733a808SDag-Erling Smørgrav 		break;
2829733a808SDag-Erling Smørgrav 	}
2839733a808SDag-Erling Smørgrav }
284