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