pseudofs_fileno.c revision 75295
1/*-
2 * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 *      $FreeBSD: head/sys/fs/pseudofs/pseudofs_fileno.c 75295 2001-04-07 19:51:12Z des $
29 */
30
31#include <sys/param.h>
32#include <sys/kernel.h>
33#include <sys/systm.h>
34#include <sys/malloc.h>
35#include <sys/mount.h>
36#include <sys/proc.h>
37#include <sys/sbuf.h>
38#include <sys/sysctl.h>
39
40#include <machine/limits.h>
41
42#include <fs/pseudofs/pseudofs.h>
43#include <fs/pseudofs/pseudofs_internal.h>
44
45static MALLOC_DEFINE(M_PFSFILENO, "pseudofs_fileno", "pseudofs fileno bitmap");
46
47static struct mtx pfs_fileno_mutex;
48
49#define PFS_BITMAP_SIZE	4096
50#define PFS_SLOT_BITS	(sizeof(unsigned int) * CHAR_BIT)
51#define PFS_BITMAP_BITS	(PFS_BITMAP_SIZE * PFS_SLOT_BITS)
52struct pfs_bitmap {
53	u_int32_t		 pb_offset;
54	int			 pb_used;
55	unsigned int		 pb_bitmap[PFS_BITMAP_SIZE];
56	struct pfs_bitmap	*pb_next;
57};
58
59/*
60 * Initialization
61 */
62void
63pfs_fileno_load(void)
64{
65	mtx_init(&pfs_fileno_mutex, "pseudofs_fileno", MTX_DEF);
66}
67
68/*
69 * Teardown
70 */
71void
72pfs_fileno_unload(void)
73{
74	mtx_destroy(&pfs_fileno_mutex);
75}
76
77/*
78 * Initialize fileno bitmap
79 */
80void
81pfs_fileno_init(struct pfs_info *pi)
82{
83	struct pfs_bitmap *pb;
84
85	MALLOC(pb, struct pfs_bitmap *, sizeof *pb,
86	    M_PFSFILENO, M_WAITOK|M_ZERO);
87
88	mtx_lock(&pi->pi_mutex);
89
90	pb->pb_bitmap[0] = 07;
91	pb->pb_used = 3;
92	pi->pi_bitmap = pb;
93	pi->pi_root->pn_fileno = 2;
94
95	mtx_unlock(&pi->pi_mutex);
96}
97
98/*
99 * Tear down fileno bitmap
100 */
101void
102pfs_fileno_uninit(struct pfs_info *pi)
103{
104	struct pfs_bitmap *pb, *npb;
105	int used;
106
107	mtx_lock(&pi->pi_mutex);
108
109	pb = pi->pi_bitmap;
110	pi->pi_bitmap = NULL;
111
112	mtx_unlock(&pi->pi_mutex);
113
114	for (used = 0; pb; pb = npb) {
115		npb = pb->pb_next;
116		used += pb->pb_used;
117		FREE(pb, M_PFSFILENO);
118	}
119	if (used > 2)
120		printf("WARNING: %d file numbers still in use\n", used);
121}
122
123/*
124 * Get the next available file number
125 */
126static u_int32_t
127pfs_get_fileno(struct pfs_info *pi)
128{
129	struct pfs_bitmap *pb, *ppb;
130	u_int32_t fileno;
131	unsigned int *p;
132	int i;
133
134	mtx_lock(&pi->pi_mutex);
135
136	/* look for the first page with free bits */
137	for (ppb = NULL, pb = pi->pi_bitmap; pb; ppb = pb, pb = pb->pb_next)
138		if (pb->pb_used != PFS_BITMAP_BITS)
139			break;
140
141	/* out of pages? */
142	if (pb == NULL) {
143		mtx_unlock(&pi->pi_mutex);
144		MALLOC(pb, struct pfs_bitmap *, sizeof *pb,
145		    M_PFSFILENO, M_WAITOK|M_ZERO);
146		mtx_lock(&pi->pi_mutex);
147		/* protect against possible race */
148		while (ppb->pb_next)
149			ppb = ppb->pb_next;
150		pb->pb_offset = ppb->pb_offset + PFS_BITMAP_BITS;
151		ppb->pb_next = pb;
152	}
153
154	/* find the first free slot */
155	for (i = 0; i < PFS_BITMAP_SIZE; ++i)
156		if (pb->pb_bitmap[i] != UINT_MAX)
157			break;
158
159	/* find the first available bit and flip it */
160	fileno = pb->pb_offset + i * PFS_SLOT_BITS;
161	p = &pb->pb_bitmap[i];
162	for (i = 0; i < PFS_SLOT_BITS; ++i, ++fileno)
163		if ((*p & (unsigned int)(1 << i)) == 0)
164			break;
165	KASSERT(i < PFS_SLOT_BITS,
166	    ("slot has free bits, yet doesn't"));
167	*p |= (unsigned int)(1 << i);
168	++pb->pb_used;
169
170	mtx_unlock(&pi->pi_mutex);
171
172	return fileno;
173}
174
175/*
176 * Free a file number
177 */
178static void
179pfs_free_fileno(struct pfs_info *pi, u_int32_t fileno)
180{
181	struct pfs_bitmap *pb;
182	unsigned int *p;
183	int i;
184
185	mtx_lock(&pi->pi_mutex);
186
187	/* find the right page */
188	for (pb = pi->pi_bitmap;
189	     pb && fileno >= PFS_BITMAP_BITS;
190	     pb = pb->pb_next, fileno -= PFS_BITMAP_BITS)
191		/* nothing */ ;
192	KASSERT(pb,
193	    ("fileno isn't in any bitmap"));
194
195	/* find the right bit in the right slot and flip it */
196	p = &pb->pb_bitmap[fileno / PFS_SLOT_BITS];
197	i = fileno % PFS_SLOT_BITS;
198	KASSERT(*p & (unsigned int)(1 << i),
199	    ("fileno is already free"));
200	*p &= ~((unsigned int)(1 << i));
201	--pb->pb_used;
202
203	mtx_unlock(&pi->pi_mutex);
204}
205
206/*
207 * Allocate a file number
208 */
209void
210pfs_fileno_alloc(struct pfs_info *pi, struct pfs_node *pn)
211{
212	/* make sure our parent has a file number */
213	if (pn->pn_parent && !pn->pn_parent->pn_fileno)
214		pfs_fileno_alloc(pi, pn->pn_parent);
215
216	switch (pn->pn_type) {
217	case pfstype_root:
218	case pfstype_dir:
219	case pfstype_file:
220	case pfstype_symlink:
221		pn->pn_fileno = pfs_get_fileno(pi);
222		break;
223	case pfstype_this:
224		KASSERT(pn->pn_parent != NULL,
225		    ("pfstype_this node has no parent"));
226		pn->pn_fileno = pn->pn_parent->pn_fileno;
227		break;
228	case pfstype_parent:
229		KASSERT(pn->pn_parent != NULL,
230		    ("pfstype_parent node has no parent"));
231		if (pn->pn_parent == pi->pi_root) {
232			pn->pn_fileno = pn->pn_parent->pn_fileno;
233			break;
234		}
235		KASSERT(pn->pn_parent->pn_parent != NULL,
236		    ("pfstype_parent node has no grandparent"));
237		pn->pn_fileno = pn->pn_parent->pn_parent->pn_fileno;
238		break;
239	case pfstype_procdep:
240		KASSERT(1,
241		    ("pfs_fileno_alloc() called for pfstype_procdep node"));
242		break;
243	case pfstype_none:
244		KASSERT(1,
245		    ("pfs_fileno_alloc() called for pfstype_none node"));
246		break;
247 	}
248
249	printf("pfs_fileno_alloc(): %s: ", pi->pi_name);
250	if (pn->pn_parent) {
251		if (pn->pn_parent->pn_parent) {
252			printf("%s/", pn->pn_parent->pn_parent->pn_name);
253		}
254		printf("%s/", pn->pn_parent->pn_name);
255	}
256	printf("%s -> %d\n", pn->pn_name, pn->pn_fileno);
257}
258
259/*
260 * Release a file number
261 */
262void
263pfs_fileno_free(struct pfs_info *pi, struct pfs_node *pn)
264{
265	switch (pn->pn_type) {
266	case pfstype_root:
267	case pfstype_dir:
268	case pfstype_file:
269	case pfstype_symlink:
270		pfs_free_fileno(pi, pn->pn_fileno);
271		break;
272	case pfstype_this:
273	case pfstype_parent:
274		/* ignore these, as they don't "own" their file number */
275		break;
276	case pfstype_procdep:
277		KASSERT(1,
278		    ("pfs_fileno_free() called for pfstype_procdep node"));
279		break;
280	case pfstype_none:
281		KASSERT(1,
282		    ("pfs_fileno_free() called for pfstype_none node"));
283		break;
284	}
285}
286