xref: /csrg-svn/sys/ufs/lfs/lfs_alloc.c (revision 4359)
1*4359Smckusick /* Copyright (c) 1981 Regents of the University of California */
2*4359Smckusick 
3*4359Smckusick static char version[] = "@(#)lfs_alloc.c 1.1 09/09/81";
4*4359Smckusick 
5*4359Smckusick /*	alloc.c	4.8	81/03/08	*/
6*4359Smckusick 
7*4359Smckusick #include "../h/param.h"
8*4359Smckusick #include "../h/systm.h"
9*4359Smckusick #include "../h/mount.h"
10*4359Smckusick #include "../h/fs.h"
11*4359Smckusick #include "../h/conf.h"
12*4359Smckusick #include "../h/buf.h"
13*4359Smckusick #include "../h/inode.h"
14*4359Smckusick #include "../h/dir.h"
15*4359Smckusick #include "../h/user.h"
16*4359Smckusick 
17*4359Smckusick long	hashalloc();
18*4359Smckusick long	alloccg();
19*4359Smckusick long	ialloccg();
20*4359Smckusick 
21*4359Smckusick struct buf *
22*4359Smckusick alloc(dev, ip, bpref, size)
23*4359Smckusick 	dev_t dev;
24*4359Smckusick 	struct inode *ip;
25*4359Smckusick 	daddr_t bpref;
26*4359Smckusick 	int size;
27*4359Smckusick {
28*4359Smckusick 	daddr_t bno;
29*4359Smckusick 	register struct fs *fs;
30*4359Smckusick 	struct buf *bp;
31*4359Smckusick 	int cg;
32*4359Smckusick 
33*4359Smckusick 	fs = getfs(dev);
34*4359Smckusick 	if (fs->fs_nbfree == 0 && size == BSIZE)
35*4359Smckusick 		goto nospace;
36*4359Smckusick 	if (bpref == 0)
37*4359Smckusick 		cg = itog(ip->i_number, fs);
38*4359Smckusick 	else
39*4359Smckusick 		cg = dtog(bpref, fs);
40*4359Smckusick 	bno = hashalloc(dev, fs, cg, (long)bpref, size, alloccg);
41*4359Smckusick 	if (bno == 0)
42*4359Smckusick 		goto nospace;
43*4359Smckusick 	bp = getblk(dev, bno);
44*4359Smckusick 	clrbuf(bp);
45*4359Smckusick 	return (bp);
46*4359Smckusick nospace:
47*4359Smckusick 	fserr(fs, "file system full");
48*4359Smckusick 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
49*4359Smckusick 	u.u_error = ENOSPC;
50*4359Smckusick 	return (NULL);
51*4359Smckusick }
52*4359Smckusick 
53*4359Smckusick struct inode *
54*4359Smckusick ialloc(dev, ipref, mode)
55*4359Smckusick 	dev_t dev;
56*4359Smckusick 	ino_t ipref;
57*4359Smckusick 	int mode;
58*4359Smckusick {
59*4359Smckusick 	daddr_t ino;
60*4359Smckusick 	register struct fs *fs;
61*4359Smckusick 	register struct inode *ip;
62*4359Smckusick 	int cg;
63*4359Smckusick 
64*4359Smckusick 	fs = getfs(dev);
65*4359Smckusick 	if (fs->fs_nifree == 0)
66*4359Smckusick 		goto noinodes;
67*4359Smckusick 	cg = itog(ipref, fs);
68*4359Smckusick 	ino = hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg);
69*4359Smckusick 	if (ino == 0)
70*4359Smckusick 		goto noinodes;
71*4359Smckusick 	ip = iget(dev, ino);
72*4359Smckusick 	if (ip == NULL) {
73*4359Smckusick 		ifree(dev, ino);
74*4359Smckusick 		return (NULL);
75*4359Smckusick 	}
76*4359Smckusick 	if (ip->i_mode)
77*4359Smckusick 		panic("ialloc: dup alloc");
78*4359Smckusick 	return (ip);
79*4359Smckusick noinodes:
80*4359Smckusick 	fserr(fs, "out of inodes");
81*4359Smckusick 	uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt);
82*4359Smckusick 	u.u_error = ENOSPC;
83*4359Smckusick 	return (NULL);
84*4359Smckusick }
85*4359Smckusick 
86*4359Smckusick dipref(dev)
87*4359Smckusick 	dev_t dev;
88*4359Smckusick {
89*4359Smckusick 	register struct fs *fs;
90*4359Smckusick 	int cg, minndir, mincg;
91*4359Smckusick 
92*4359Smckusick 	fs = getfs(dev);
93*4359Smckusick 	minndir = fs->fs_cs[0].cs_ndir;
94*4359Smckusick 	mincg = 0;
95*4359Smckusick 	for (cg = 1; cg < fs->fs_ncg; cg++)
96*4359Smckusick 		if (fs->fs_cs[cg].cs_ndir < minndir) {
97*4359Smckusick 			mincg = cg;
98*4359Smckusick 			minndir = fs->fs_cs[cg].cs_ndir;
99*4359Smckusick 			if (minndir == 0)
100*4359Smckusick 				break;
101*4359Smckusick 		}
102*4359Smckusick 	return (fs->fs_ipg * mincg);
103*4359Smckusick }
104*4359Smckusick 
105*4359Smckusick long
106*4359Smckusick hashalloc(dev, fs, cg, pref, size, allocator)
107*4359Smckusick 	dev_t dev;
108*4359Smckusick 	register struct fs *fs;
109*4359Smckusick 	int cg;
110*4359Smckusick 	long pref;
111*4359Smckusick 	int size;	/* size for data blocks, mode for inodes */
112*4359Smckusick 	long (*allocator)();
113*4359Smckusick {
114*4359Smckusick 	long result;
115*4359Smckusick 	int i, icg = cg;
116*4359Smckusick 
117*4359Smckusick 	/*
118*4359Smckusick 	 * 1: preferred cylinder group
119*4359Smckusick 	 */
120*4359Smckusick 	result = (*allocator)(dev, fs, cg, pref, size);
121*4359Smckusick 	if (result)
122*4359Smckusick 		return (result);
123*4359Smckusick 	/*
124*4359Smckusick 	 * 2: quadratic rehash
125*4359Smckusick 	 */
126*4359Smckusick 	for (i = 1; i < fs->fs_ncg; i *= 2) {
127*4359Smckusick 		cg += i;
128*4359Smckusick 		if (cg >= fs->fs_ncg)
129*4359Smckusick 			cg -= fs->fs_ncg;
130*4359Smckusick 		result = (*allocator)(dev, fs, cg, 0, size);
131*4359Smckusick 		if (result)
132*4359Smckusick 			return (result);
133*4359Smckusick 	}
134*4359Smckusick 	/*
135*4359Smckusick 	 * 3: brute force search
136*4359Smckusick 	 */
137*4359Smckusick 	cg = icg;
138*4359Smckusick 	for (i = 0; i < fs->fs_ncg; i++) {
139*4359Smckusick 		result = (*allocator)(dev, fs, cg, 0, size);
140*4359Smckusick 		if (result)
141*4359Smckusick 			return (result);
142*4359Smckusick 		cg++;
143*4359Smckusick 		if (cg == fs->fs_ncg)
144*4359Smckusick 			cg = 0;
145*4359Smckusick 	}
146*4359Smckusick 	return (0);
147*4359Smckusick }
148*4359Smckusick 
149*4359Smckusick daddr_t
150*4359Smckusick alloccg(dev, fs, cg, bpref, size)
151*4359Smckusick 	dev_t dev;
152*4359Smckusick 	struct fs *fs;
153*4359Smckusick 	int cg;
154*4359Smckusick 	daddr_t bpref;
155*4359Smckusick 	int size;
156*4359Smckusick {
157*4359Smckusick 	struct buf *bp;
158*4359Smckusick 	struct cg *cgp;
159*4359Smckusick 	int i;
160*4359Smckusick 
161*4359Smckusick 	if (size != BSIZE)
162*4359Smckusick 		panic("alloccg: size != BSIZE is too hard!");
163*4359Smckusick 	bp = bread(dev, cgtod(cg, fs));
164*4359Smckusick 	if (bp->b_flags & B_ERROR)
165*4359Smckusick 		return (0);
166*4359Smckusick 	cgp = bp->b_un.b_cg;
167*4359Smckusick 	if (bpref) {
168*4359Smckusick 		bpref %= fs->fs_fpg;
169*4359Smckusick 		if (isblock(cgp->cg_free, bpref/FRAG))
170*4359Smckusick 			goto gotit;
171*4359Smckusick 	} else
172*4359Smckusick 		bpref = cgp->cg_rotor;
173*4359Smckusick 	for (i = 0; i < cgp->cg_ndblk; i += FRAG) {
174*4359Smckusick 		bpref += FRAG;
175*4359Smckusick 		if (bpref >= cgp->cg_ndblk)
176*4359Smckusick 			bpref = 0;
177*4359Smckusick 		if (isblock(cgp->cg_free, bpref/FRAG)) {
178*4359Smckusick 			cgp->cg_rotor = bpref;
179*4359Smckusick 			goto gotit;
180*4359Smckusick 		}
181*4359Smckusick 	}
182*4359Smckusick 	brelse(bp);
183*4359Smckusick 	return (0);
184*4359Smckusick gotit:
185*4359Smckusick 	clrblock(cgp->cg_free, bpref/FRAG);
186*4359Smckusick 	cgp->cg_nbfree--;
187*4359Smckusick 	fs->fs_nbfree--;
188*4359Smckusick 	fs->fs_cs[cg].cs_nbfree--;
189*4359Smckusick 	fs->fs_fmod++;
190*4359Smckusick 	i = bpref * NSPF;
191*4359Smckusick 	cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]--;
192*4359Smckusick 	bdwrite(bp);
193*4359Smckusick 	return (cg * fs->fs_fpg + bpref);
194*4359Smckusick }
195*4359Smckusick 
196*4359Smckusick long
197*4359Smckusick ialloccg(dev, fs, cg, ipref, mode)
198*4359Smckusick 	dev_t dev;
199*4359Smckusick 	struct fs *fs;
200*4359Smckusick 	int cg;
201*4359Smckusick 	daddr_t ipref;
202*4359Smckusick 	int mode;
203*4359Smckusick {
204*4359Smckusick 	struct buf *bp;
205*4359Smckusick 	struct cg *cgp;
206*4359Smckusick 	int i;
207*4359Smckusick 
208*4359Smckusick 	bp = bread(dev, cgtod(cg, fs));
209*4359Smckusick 	if (bp->b_flags & B_ERROR)
210*4359Smckusick 		return (0);
211*4359Smckusick 	cgp = bp->b_un.b_cg;
212*4359Smckusick 	if (cgp->cg_nifree == 0) {
213*4359Smckusick 		brelse(bp);
214*4359Smckusick 		return (0);
215*4359Smckusick 	}
216*4359Smckusick 	if (ipref) {
217*4359Smckusick 		ipref %= fs->fs_ipg;
218*4359Smckusick 		if (isclr(cgp->cg_iused, ipref))
219*4359Smckusick 			goto gotit;
220*4359Smckusick 	} else
221*4359Smckusick 		ipref = cgp->cg_irotor;
222*4359Smckusick 	for (i = 0; i < fs->fs_ipg; i++) {
223*4359Smckusick 		ipref++;
224*4359Smckusick 		if (ipref >= fs->fs_ipg)
225*4359Smckusick 			ipref = 0;
226*4359Smckusick 		if (isclr(cgp->cg_iused, ipref)) {
227*4359Smckusick 			cgp->cg_irotor = ipref;
228*4359Smckusick 			goto gotit;
229*4359Smckusick 		}
230*4359Smckusick 	}
231*4359Smckusick 	brelse(bp);
232*4359Smckusick 	return (0);
233*4359Smckusick gotit:
234*4359Smckusick 	setbit(cgp->cg_iused, ipref);
235*4359Smckusick 	cgp->cg_nifree--;
236*4359Smckusick 	fs->fs_nifree--;
237*4359Smckusick 	fs->fs_cs[cg].cs_nifree--;
238*4359Smckusick 	fs->fs_fmod++;
239*4359Smckusick 	if ((mode & IFMT) == IFDIR) {
240*4359Smckusick 		cgp->cg_ndir++;
241*4359Smckusick 		fs->fs_cs[cg].cs_ndir++;
242*4359Smckusick 	}
243*4359Smckusick 	bdwrite(bp);
244*4359Smckusick 	return (cg * fs->fs_ipg + ipref);
245*4359Smckusick }
246*4359Smckusick 
247*4359Smckusick fre(dev, bno, size)
248*4359Smckusick 	dev_t dev;
249*4359Smckusick 	daddr_t bno;
250*4359Smckusick 	int size;
251*4359Smckusick {
252*4359Smckusick 	register struct fs *fs;
253*4359Smckusick 	register struct cg *cgp;
254*4359Smckusick 	register struct buf *bp;
255*4359Smckusick 	int i;
256*4359Smckusick 	int cg;
257*4359Smckusick 
258*4359Smckusick 	if (size != BSIZE)
259*4359Smckusick 		panic("free: size != BSIZE is too hard!");
260*4359Smckusick 	fs = getfs(dev);
261*4359Smckusick 	cg = dtog(bno, fs);
262*4359Smckusick 	if (badblock(fs, bno))
263*4359Smckusick 		return;
264*4359Smckusick 	bp = bread(dev, cgtod(cg, fs));
265*4359Smckusick 	if (bp->b_flags & B_ERROR)
266*4359Smckusick 		return;
267*4359Smckusick 	cgp = bp->b_un.b_cg;
268*4359Smckusick 	bno %= fs->fs_fpg;
269*4359Smckusick 	if (isblock(cgp->cg_free, bno/FRAG))
270*4359Smckusick 		panic("free: freeing free block");
271*4359Smckusick 	setblock(cgp->cg_free, bno/FRAG);
272*4359Smckusick 	cgp->cg_nbfree++;
273*4359Smckusick 	fs->fs_nbfree++;
274*4359Smckusick 	fs->fs_cs[cg].cs_nbfree++;
275*4359Smckusick 	fs->fs_fmod++;
276*4359Smckusick 	i = bno * NSPF;
277*4359Smckusick 	cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]++;
278*4359Smckusick 	bdwrite(bp);
279*4359Smckusick }
280*4359Smckusick 
281*4359Smckusick ifree(dev, ino, mode)
282*4359Smckusick 	dev_t dev;
283*4359Smckusick 	ino_t ino;
284*4359Smckusick 	int mode;
285*4359Smckusick {
286*4359Smckusick 	register struct fs *fs;
287*4359Smckusick 	register struct cg *cgp;
288*4359Smckusick 	register struct buf *bp;
289*4359Smckusick 	int i;
290*4359Smckusick 	int cg;
291*4359Smckusick 
292*4359Smckusick 	fs = getfs(dev);
293*4359Smckusick 	if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
294*4359Smckusick 		panic("ifree: range");
295*4359Smckusick 	cg = itog(ino, fs);
296*4359Smckusick 	bp = bread(dev, cgtod(cg, fs));
297*4359Smckusick 	if (bp->b_flags & B_ERROR)
298*4359Smckusick 		return;
299*4359Smckusick 	cgp = bp->b_un.b_cg;
300*4359Smckusick 	ino %= fs->fs_ipg;
301*4359Smckusick 	if (isclr(cgp->cg_iused, ino))
302*4359Smckusick 		panic("ifree: freeing free inode");
303*4359Smckusick 	clrbit(cgp->cg_iused, ino);
304*4359Smckusick 	cgp->cg_nifree++;
305*4359Smckusick 	fs->fs_nifree++;
306*4359Smckusick 	fs->fs_cs[cg].cs_nifree++;
307*4359Smckusick 	if ((mode & IFMT) == IFDIR) {
308*4359Smckusick 		cgp->cg_ndir--;
309*4359Smckusick 		fs->fs_cs[cg].cs_ndir--;
310*4359Smckusick 	}
311*4359Smckusick 	fs->fs_fmod++;
312*4359Smckusick 	bdwrite(bp);
313*4359Smckusick }
314*4359Smckusick 
315*4359Smckusick badblock(fs, bn)
316*4359Smckusick 	register struct fs *fs;
317*4359Smckusick 	daddr_t bn;
318*4359Smckusick {
319*4359Smckusick 
320*4359Smckusick 	if ((unsigned)bn >= fs->fs_size || bn < cgdmin(dtog(bn, fs), fs)) {
321*4359Smckusick 		fserr(fs, "bad block");
322*4359Smckusick 		return (1);
323*4359Smckusick 	}
324*4359Smckusick 	return (0);
325*4359Smckusick }
326*4359Smckusick 
327*4359Smckusick /*
328*4359Smckusick  * getfs maps a device number into
329*4359Smckusick  * a pointer to the incore super
330*4359Smckusick  * block.  The algorithm is a linear
331*4359Smckusick  * search through the mount table.
332*4359Smckusick  * A consistency check of the
333*4359Smckusick  * in core free-block and i-node
334*4359Smckusick  * counts is performed.
335*4359Smckusick  *
336*4359Smckusick  * panic: no fs -- the device is not mounted.
337*4359Smckusick  *	this "cannot happen"
338*4359Smckusick  */
339*4359Smckusick struct fs *
340*4359Smckusick getfs(dev)
341*4359Smckusick 	dev_t dev;
342*4359Smckusick {
343*4359Smckusick 	register struct mount *mp;
344*4359Smckusick 	register struct fs *fs;
345*4359Smckusick 
346*4359Smckusick 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
347*4359Smckusick 		if (mp->m_bufp != NULL && mp->m_dev == dev) {
348*4359Smckusick 			fs = mp->m_bufp->b_un.b_fs;
349*4359Smckusick 			if (fs->fs_magic != FS_MAGIC)
350*4359Smckusick 				panic("getfs: bad magic");
351*4359Smckusick 			return (fs);
352*4359Smckusick 		}
353*4359Smckusick 	panic("getfs: no fs");
354*4359Smckusick 	return (NULL);
355*4359Smckusick }
356*4359Smckusick 
357*4359Smckusick /*
358*4359Smckusick  * Fserr prints the name of a file system
359*4359Smckusick  * with an error diagnostic, in the form
360*4359Smckusick  *	fs: error message
361*4359Smckusick  */
362*4359Smckusick fserr(fs, cp)
363*4359Smckusick 	struct fs *fs;
364*4359Smckusick 	char *cp;
365*4359Smckusick {
366*4359Smckusick 
367*4359Smckusick 	printf("%s: %s\n", fs->fs_fsmnt, cp);
368*4359Smckusick }
369*4359Smckusick 
370*4359Smckusick /*
371*4359Smckusick  * Getfsx returns the index in the file system
372*4359Smckusick  * table of the specified device.  The swap device
373*4359Smckusick  * is also assigned a pseudo-index.  The index may
374*4359Smckusick  * be used as a compressed indication of the location
375*4359Smckusick  * of a block, recording
376*4359Smckusick  *	<getfsx(dev),blkno>
377*4359Smckusick  * rather than
378*4359Smckusick  *	<dev, blkno>
379*4359Smckusick  * provided the information need remain valid only
380*4359Smckusick  * as long as the file system is mounted.
381*4359Smckusick  */
382*4359Smckusick getfsx(dev)
383*4359Smckusick 	dev_t dev;
384*4359Smckusick {
385*4359Smckusick 	register struct mount *mp;
386*4359Smckusick 
387*4359Smckusick 	if (dev == swapdev)
388*4359Smckusick 		return (MSWAPX);
389*4359Smckusick 	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
390*4359Smckusick 		if (mp->m_dev == dev)
391*4359Smckusick 			return (mp - &mount[0]);
392*4359Smckusick 	return (-1);
393*4359Smckusick }
394*4359Smckusick 
395*4359Smckusick /*
396*4359Smckusick  * Update is the internal name of 'sync'.  It goes through the disk
397*4359Smckusick  * queues to initiate sandbagged IO; goes through the inodes to write
398*4359Smckusick  * modified nodes; and it goes through the mount table to initiate modified
399*4359Smckusick  * super blocks.
400*4359Smckusick  */
401*4359Smckusick update()
402*4359Smckusick {
403*4359Smckusick 	register struct inode *ip;
404*4359Smckusick 	register struct mount *mp;
405*4359Smckusick 	register struct buf *bp;
406*4359Smckusick 	struct fs *fs;
407*4359Smckusick 	time_t tim;
408*4359Smckusick 	int i;
409*4359Smckusick 
410*4359Smckusick 	if (updlock)
411*4359Smckusick 		return;
412*4359Smckusick 	updlock++;
413*4359Smckusick 	/*
414*4359Smckusick 	 * Write back modified superblocks.
415*4359Smckusick 	 * Consistency check that the superblock
416*4359Smckusick 	 * of each file system is still in the buffer cache.
417*4359Smckusick 	 */
418*4359Smckusick 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
419*4359Smckusick 		if (mp->m_bufp != NULL) {
420*4359Smckusick 			fs = mp->m_bufp->b_un.b_fs;
421*4359Smckusick 			if (fs->fs_fmod == 0)
422*4359Smckusick 				continue;
423*4359Smckusick 			if (fs->fs_ronly != 0)
424*4359Smckusick 				panic("update: rofs mod");
425*4359Smckusick 			bp = getblk(mp->m_dev, SBLOCK);
426*4359Smckusick 			fs->fs_fmod = 0;
427*4359Smckusick 			fs->fs_time = TIME;
428*4359Smckusick 			if (bp->b_un.b_fs != fs)
429*4359Smckusick 				panic("update: bad b_fs");
430*4359Smckusick 			bwrite(bp);
431*4359Smckusick 			for (i = 0; i < cssize(fs); i += BSIZE) {
432*4359Smckusick 				bp = getblk(mp->m_dev, csaddr(fs) + i / FSIZE);
433*4359Smckusick 				bcopy(fs->fs_cs + i, bp->b_un.b_addr, BSIZE);
434*4359Smckusick 				bwrite(bp);
435*4359Smckusick 			}
436*4359Smckusick 		}
437*4359Smckusick 	/*
438*4359Smckusick 	 * Write back each (modified) inode.
439*4359Smckusick 	 */
440*4359Smckusick 	for (ip = inode; ip < inodeNINODE; ip++)
441*4359Smckusick 		if((ip->i_flag&ILOCK)==0 && ip->i_count) {
442*4359Smckusick 			ip->i_flag |= ILOCK;
443*4359Smckusick 			ip->i_count++;
444*4359Smckusick 			tim = TIME;
445*4359Smckusick 			iupdat(ip, &tim, &tim, 0);
446*4359Smckusick 			iput(ip);
447*4359Smckusick 		}
448*4359Smckusick 	updlock = 0;
449*4359Smckusick 	/*
450*4359Smckusick 	 * Force stale buffer cache information to be flushed,
451*4359Smckusick 	 * for all devices.
452*4359Smckusick 	 */
453*4359Smckusick 	bflush(NODEV);
454*4359Smckusick }
455