xref: /freebsd/sys/fs/pseudofs/pseudofs_fileno.c (revision 21ceb6efa2572847dfcb49302f2d2e2c1fb005a6)
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>
3421ceb6efSDag-Erling Smørgrav #include <sys/lock.h>
359733a808SDag-Erling Smørgrav #include <sys/malloc.h>
369733a808SDag-Erling Smørgrav #include <sys/mount.h>
3749fa664fSDag-Erling Smørgrav #include <sys/mutex.h>
389733a808SDag-Erling Smørgrav #include <sys/proc.h>
399733a808SDag-Erling Smørgrav #include <sys/sbuf.h>
409733a808SDag-Erling Smørgrav #include <sys/sysctl.h>
419733a808SDag-Erling Smørgrav 
429733a808SDag-Erling Smørgrav #include <machine/limits.h>
439733a808SDag-Erling Smørgrav 
449733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs.h>
459733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs_internal.h>
469733a808SDag-Erling Smørgrav 
47649ad985SDag-Erling Smørgrav static MALLOC_DEFINE(M_PFSFILENO, "pfs_fileno", "pseudofs fileno bitmap");
489733a808SDag-Erling Smørgrav 
499733a808SDag-Erling Smørgrav static struct mtx pfs_fileno_mutex;
509733a808SDag-Erling Smørgrav 
519733a808SDag-Erling Smørgrav #define PFS_BITMAP_SIZE	4096
52649ad985SDag-Erling Smørgrav #define PFS_SLOT_BITS	(int)(sizeof(unsigned int) * CHAR_BIT)
539733a808SDag-Erling Smørgrav #define PFS_BITMAP_BITS	(PFS_BITMAP_SIZE * PFS_SLOT_BITS)
549733a808SDag-Erling Smørgrav struct pfs_bitmap {
559733a808SDag-Erling Smørgrav 	u_int32_t		 pb_offset;
569733a808SDag-Erling Smørgrav 	int			 pb_used;
579733a808SDag-Erling Smørgrav 	unsigned int		 pb_bitmap[PFS_BITMAP_SIZE];
589733a808SDag-Erling Smørgrav 	struct pfs_bitmap	*pb_next;
599733a808SDag-Erling Smørgrav };
609733a808SDag-Erling Smørgrav 
619733a808SDag-Erling Smørgrav /*
629733a808SDag-Erling Smørgrav  * Initialization
639733a808SDag-Erling Smørgrav  */
649733a808SDag-Erling Smørgrav void
659733a808SDag-Erling Smørgrav pfs_fileno_load(void)
669733a808SDag-Erling Smørgrav {
679733a808SDag-Erling Smørgrav 	mtx_init(&pfs_fileno_mutex, "pseudofs_fileno", MTX_DEF);
689733a808SDag-Erling Smørgrav }
699733a808SDag-Erling Smørgrav 
709733a808SDag-Erling Smørgrav /*
719733a808SDag-Erling Smørgrav  * Teardown
729733a808SDag-Erling Smørgrav  */
739733a808SDag-Erling Smørgrav void
749733a808SDag-Erling Smørgrav pfs_fileno_unload(void)
759733a808SDag-Erling Smørgrav {
769733a808SDag-Erling Smørgrav 	mtx_destroy(&pfs_fileno_mutex);
779733a808SDag-Erling Smørgrav }
789733a808SDag-Erling Smørgrav 
799733a808SDag-Erling Smørgrav /*
809733a808SDag-Erling Smørgrav  * Initialize fileno bitmap
819733a808SDag-Erling Smørgrav  */
829733a808SDag-Erling Smørgrav void
839733a808SDag-Erling Smørgrav pfs_fileno_init(struct pfs_info *pi)
849733a808SDag-Erling Smørgrav {
859733a808SDag-Erling Smørgrav 	struct pfs_bitmap *pb;
869733a808SDag-Erling Smørgrav 
879733a808SDag-Erling Smørgrav 	MALLOC(pb, struct pfs_bitmap *, sizeof *pb,
889733a808SDag-Erling Smørgrav 	    M_PFSFILENO, M_WAITOK|M_ZERO);
899733a808SDag-Erling Smørgrav 
909733a808SDag-Erling Smørgrav 	mtx_lock(&pi->pi_mutex);
919733a808SDag-Erling Smørgrav 
929733a808SDag-Erling Smørgrav 	pb->pb_bitmap[0] = 07;
939733a808SDag-Erling Smørgrav 	pb->pb_used = 3;
949733a808SDag-Erling Smørgrav 	pi->pi_bitmap = pb;
959733a808SDag-Erling Smørgrav 	pi->pi_root->pn_fileno = 2;
969733a808SDag-Erling Smørgrav 
979733a808SDag-Erling Smørgrav 	mtx_unlock(&pi->pi_mutex);
989733a808SDag-Erling Smørgrav }
999733a808SDag-Erling Smørgrav 
1009733a808SDag-Erling Smørgrav /*
1019733a808SDag-Erling Smørgrav  * Tear down fileno bitmap
1029733a808SDag-Erling Smørgrav  */
1039733a808SDag-Erling Smørgrav void
1049733a808SDag-Erling Smørgrav pfs_fileno_uninit(struct pfs_info *pi)
1059733a808SDag-Erling Smørgrav {
1069733a808SDag-Erling Smørgrav 	struct pfs_bitmap *pb, *npb;
1079733a808SDag-Erling Smørgrav 	int used;
1089733a808SDag-Erling Smørgrav 
1099733a808SDag-Erling Smørgrav 	mtx_lock(&pi->pi_mutex);
1109733a808SDag-Erling Smørgrav 
1119733a808SDag-Erling Smørgrav 	pb = pi->pi_bitmap;
1129733a808SDag-Erling Smørgrav 	pi->pi_bitmap = NULL;
1139733a808SDag-Erling Smørgrav 
1149733a808SDag-Erling Smørgrav 	mtx_unlock(&pi->pi_mutex);
1159733a808SDag-Erling Smørgrav 
1169733a808SDag-Erling Smørgrav 	for (used = 0; pb; pb = npb) {
1179733a808SDag-Erling Smørgrav 		npb = pb->pb_next;
1189733a808SDag-Erling Smørgrav 		used += pb->pb_used;
1199733a808SDag-Erling Smørgrav 		FREE(pb, M_PFSFILENO);
1209733a808SDag-Erling Smørgrav 	}
121649ad985SDag-Erling Smørgrav #if 0
122649ad985SDag-Erling Smørgrav 	/* we currently don't reclaim filenos */
1239733a808SDag-Erling Smørgrav 	if (used > 2)
1249733a808SDag-Erling Smørgrav 		printf("WARNING: %d file numbers still in use\n", used);
125649ad985SDag-Erling Smørgrav #endif
1269733a808SDag-Erling Smørgrav }
1279733a808SDag-Erling Smørgrav 
1289733a808SDag-Erling Smørgrav /*
1299733a808SDag-Erling Smørgrav  * Get the next available file number
1309733a808SDag-Erling Smørgrav  */
1319733a808SDag-Erling Smørgrav static u_int32_t
1329733a808SDag-Erling Smørgrav pfs_get_fileno(struct pfs_info *pi)
1339733a808SDag-Erling Smørgrav {
1349733a808SDag-Erling Smørgrav 	struct pfs_bitmap *pb, *ppb;
1359733a808SDag-Erling Smørgrav 	u_int32_t fileno;
1369733a808SDag-Erling Smørgrav 	unsigned int *p;
1379733a808SDag-Erling Smørgrav 	int i;
1389733a808SDag-Erling Smørgrav 
1399733a808SDag-Erling Smørgrav 	mtx_lock(&pi->pi_mutex);
1409733a808SDag-Erling Smørgrav 
1419733a808SDag-Erling Smørgrav 	/* look for the first page with free bits */
1429733a808SDag-Erling Smørgrav 	for (ppb = NULL, pb = pi->pi_bitmap; pb; ppb = pb, pb = pb->pb_next)
1439733a808SDag-Erling Smørgrav 		if (pb->pb_used != PFS_BITMAP_BITS)
1449733a808SDag-Erling Smørgrav 			break;
1459733a808SDag-Erling Smørgrav 
1469733a808SDag-Erling Smørgrav 	/* out of pages? */
1479733a808SDag-Erling Smørgrav 	if (pb == NULL) {
1489733a808SDag-Erling Smørgrav 		mtx_unlock(&pi->pi_mutex);
1499733a808SDag-Erling Smørgrav 		MALLOC(pb, struct pfs_bitmap *, sizeof *pb,
1509733a808SDag-Erling Smørgrav 		    M_PFSFILENO, M_WAITOK|M_ZERO);
1519733a808SDag-Erling Smørgrav 		mtx_lock(&pi->pi_mutex);
1529733a808SDag-Erling Smørgrav 		/* protect against possible race */
1539733a808SDag-Erling Smørgrav 		while (ppb->pb_next)
1549733a808SDag-Erling Smørgrav 			ppb = ppb->pb_next;
1559733a808SDag-Erling Smørgrav 		pb->pb_offset = ppb->pb_offset + PFS_BITMAP_BITS;
1569733a808SDag-Erling Smørgrav 		ppb->pb_next = pb;
1579733a808SDag-Erling Smørgrav 	}
1589733a808SDag-Erling Smørgrav 
1599733a808SDag-Erling Smørgrav 	/* find the first free slot */
1609733a808SDag-Erling Smørgrav 	for (i = 0; i < PFS_BITMAP_SIZE; ++i)
1619733a808SDag-Erling Smørgrav 		if (pb->pb_bitmap[i] != UINT_MAX)
1629733a808SDag-Erling Smørgrav 			break;
1639733a808SDag-Erling Smørgrav 
1649733a808SDag-Erling Smørgrav 	/* find the first available bit and flip it */
1659733a808SDag-Erling Smørgrav 	fileno = pb->pb_offset + i * PFS_SLOT_BITS;
1669733a808SDag-Erling Smørgrav 	p = &pb->pb_bitmap[i];
1679733a808SDag-Erling Smørgrav 	for (i = 0; i < PFS_SLOT_BITS; ++i, ++fileno)
1689733a808SDag-Erling Smørgrav 		if ((*p & (unsigned int)(1 << i)) == 0)
1699733a808SDag-Erling Smørgrav 			break;
1709733a808SDag-Erling Smørgrav 	KASSERT(i < PFS_SLOT_BITS,
1719733a808SDag-Erling Smørgrav 	    ("slot has free bits, yet doesn't"));
1729733a808SDag-Erling Smørgrav 	*p |= (unsigned int)(1 << i);
1739733a808SDag-Erling Smørgrav 	++pb->pb_used;
1749733a808SDag-Erling Smørgrav 
1759733a808SDag-Erling Smørgrav 	mtx_unlock(&pi->pi_mutex);
1769733a808SDag-Erling Smørgrav 
1779733a808SDag-Erling Smørgrav 	return fileno;
1789733a808SDag-Erling Smørgrav }
1799733a808SDag-Erling Smørgrav 
1809733a808SDag-Erling Smørgrav /*
1819733a808SDag-Erling Smørgrav  * Free a file number
1829733a808SDag-Erling Smørgrav  */
1839733a808SDag-Erling Smørgrav static void
1849733a808SDag-Erling Smørgrav pfs_free_fileno(struct pfs_info *pi, u_int32_t fileno)
1859733a808SDag-Erling Smørgrav {
1869733a808SDag-Erling Smørgrav 	struct pfs_bitmap *pb;
1879733a808SDag-Erling Smørgrav 	unsigned int *p;
1889733a808SDag-Erling Smørgrav 	int i;
1899733a808SDag-Erling Smørgrav 
1909733a808SDag-Erling Smørgrav 	mtx_lock(&pi->pi_mutex);
1919733a808SDag-Erling Smørgrav 
1929733a808SDag-Erling Smørgrav 	/* find the right page */
1939733a808SDag-Erling Smørgrav 	for (pb = pi->pi_bitmap;
1949733a808SDag-Erling Smørgrav 	     pb && fileno >= PFS_BITMAP_BITS;
1959733a808SDag-Erling Smørgrav 	     pb = pb->pb_next, fileno -= PFS_BITMAP_BITS)
1969733a808SDag-Erling Smørgrav 		/* nothing */ ;
1979733a808SDag-Erling Smørgrav 	KASSERT(pb,
1989733a808SDag-Erling Smørgrav 	    ("fileno isn't in any bitmap"));
1999733a808SDag-Erling Smørgrav 
2009733a808SDag-Erling Smørgrav 	/* find the right bit in the right slot and flip it */
2019733a808SDag-Erling Smørgrav 	p = &pb->pb_bitmap[fileno / PFS_SLOT_BITS];
2029733a808SDag-Erling Smørgrav 	i = fileno % PFS_SLOT_BITS;
2039733a808SDag-Erling Smørgrav 	KASSERT(*p & (unsigned int)(1 << i),
2049733a808SDag-Erling Smørgrav 	    ("fileno is already free"));
2059733a808SDag-Erling Smørgrav 	*p &= ~((unsigned int)(1 << i));
2069733a808SDag-Erling Smørgrav 	--pb->pb_used;
2079733a808SDag-Erling Smørgrav 
2089733a808SDag-Erling Smørgrav 	mtx_unlock(&pi->pi_mutex);
209649ad985SDag-Erling Smørgrav 	printf("pfs_free_fileno(): reclaimed %d\n", fileno);
2109733a808SDag-Erling Smørgrav }
2119733a808SDag-Erling Smørgrav 
2129733a808SDag-Erling Smørgrav /*
2139733a808SDag-Erling Smørgrav  * Allocate a file number
2149733a808SDag-Erling Smørgrav  */
2159733a808SDag-Erling Smørgrav void
2169733a808SDag-Erling Smørgrav pfs_fileno_alloc(struct pfs_info *pi, struct pfs_node *pn)
2179733a808SDag-Erling Smørgrav {
2189733a808SDag-Erling Smørgrav 	/* make sure our parent has a file number */
2199733a808SDag-Erling Smørgrav 	if (pn->pn_parent && !pn->pn_parent->pn_fileno)
2209733a808SDag-Erling Smørgrav 		pfs_fileno_alloc(pi, pn->pn_parent);
2219733a808SDag-Erling Smørgrav 
2229733a808SDag-Erling Smørgrav 	switch (pn->pn_type) {
2239733a808SDag-Erling Smørgrav 	case pfstype_root:
2249733a808SDag-Erling Smørgrav 	case pfstype_dir:
2259733a808SDag-Erling Smørgrav 	case pfstype_file:
2269733a808SDag-Erling Smørgrav 	case pfstype_symlink:
227649ad985SDag-Erling Smørgrav 	case pfstype_procdir:
2289733a808SDag-Erling Smørgrav 		pn->pn_fileno = pfs_get_fileno(pi);
2299733a808SDag-Erling Smørgrav 		break;
2309733a808SDag-Erling Smørgrav 	case pfstype_this:
2319733a808SDag-Erling Smørgrav 		KASSERT(pn->pn_parent != NULL,
2329733a808SDag-Erling Smørgrav 		    ("pfstype_this node has no parent"));
2339733a808SDag-Erling Smørgrav 		pn->pn_fileno = pn->pn_parent->pn_fileno;
2349733a808SDag-Erling Smørgrav 		break;
2359733a808SDag-Erling Smørgrav 	case pfstype_parent:
2369733a808SDag-Erling Smørgrav 		KASSERT(pn->pn_parent != NULL,
2379733a808SDag-Erling Smørgrav 		    ("pfstype_parent node has no parent"));
2389733a808SDag-Erling Smørgrav 		if (pn->pn_parent == pi->pi_root) {
2399733a808SDag-Erling Smørgrav 			pn->pn_fileno = pn->pn_parent->pn_fileno;
2409733a808SDag-Erling Smørgrav 			break;
2419733a808SDag-Erling Smørgrav 		}
2429733a808SDag-Erling Smørgrav 		KASSERT(pn->pn_parent->pn_parent != NULL,
2439733a808SDag-Erling Smørgrav 		    ("pfstype_parent node has no grandparent"));
2449733a808SDag-Erling Smørgrav 		pn->pn_fileno = pn->pn_parent->pn_parent->pn_fileno;
2459733a808SDag-Erling Smørgrav 		break;
2469733a808SDag-Erling Smørgrav 	case pfstype_none:
247649ad985SDag-Erling Smørgrav 		KASSERT(0,
2489733a808SDag-Erling Smørgrav 		    ("pfs_fileno_alloc() called for pfstype_none node"));
2499733a808SDag-Erling Smørgrav 		break;
2509733a808SDag-Erling Smørgrav  	}
2519733a808SDag-Erling Smørgrav 
252649ad985SDag-Erling Smørgrav #if 0
2539733a808SDag-Erling Smørgrav 	printf("pfs_fileno_alloc(): %s: ", pi->pi_name);
2549733a808SDag-Erling Smørgrav 	if (pn->pn_parent) {
2559733a808SDag-Erling Smørgrav 		if (pn->pn_parent->pn_parent) {
2569733a808SDag-Erling Smørgrav 			printf("%s/", pn->pn_parent->pn_parent->pn_name);
2579733a808SDag-Erling Smørgrav 		}
2589733a808SDag-Erling Smørgrav 		printf("%s/", pn->pn_parent->pn_name);
2599733a808SDag-Erling Smørgrav 	}
2609733a808SDag-Erling Smørgrav 	printf("%s -> %d\n", pn->pn_name, pn->pn_fileno);
261649ad985SDag-Erling Smørgrav #endif
2629733a808SDag-Erling Smørgrav }
2639733a808SDag-Erling Smørgrav 
2649733a808SDag-Erling Smørgrav /*
2659733a808SDag-Erling Smørgrav  * Release a file number
2669733a808SDag-Erling Smørgrav  */
2679733a808SDag-Erling Smørgrav void
2689733a808SDag-Erling Smørgrav pfs_fileno_free(struct pfs_info *pi, struct pfs_node *pn)
2699733a808SDag-Erling Smørgrav {
2709733a808SDag-Erling Smørgrav 	switch (pn->pn_type) {
2719733a808SDag-Erling Smørgrav 	case pfstype_root:
2729733a808SDag-Erling Smørgrav 	case pfstype_dir:
2739733a808SDag-Erling Smørgrav 	case pfstype_file:
2749733a808SDag-Erling Smørgrav 	case pfstype_symlink:
275649ad985SDag-Erling Smørgrav 	case pfstype_procdir:
2769733a808SDag-Erling Smørgrav 		pfs_free_fileno(pi, pn->pn_fileno);
2779733a808SDag-Erling Smørgrav 		break;
2789733a808SDag-Erling Smørgrav 	case pfstype_this:
2799733a808SDag-Erling Smørgrav 	case pfstype_parent:
2809733a808SDag-Erling Smørgrav 		/* ignore these, as they don't "own" their file number */
2819733a808SDag-Erling Smørgrav 		break;
2829733a808SDag-Erling Smørgrav 	case pfstype_none:
283649ad985SDag-Erling Smørgrav 		KASSERT(0,
2849733a808SDag-Erling Smørgrav 		    ("pfs_fileno_free() called for pfstype_none node"));
2859733a808SDag-Erling Smørgrav 		break;
2869733a808SDag-Erling Smørgrav 	}
2879733a808SDag-Erling Smørgrav }
288