|
|
1.1 root 1: /* alloc.c 4.8 81/03/08 */
2:
3: #include "../h/param.h"
4: #include "../h/systm.h"
5: #include "../h/mount.h"
6: #include "../h/filsys.h"
7: #include "../h/fblk.h"
8: #include "../h/conf.h"
9: #include "../h/buf.h"
10: #include "../h/inode.h"
11: #include "../h/ino.h"
12: #include "../h/dir.h"
13: #include "../h/user.h"
14: #include "../h/trace.h"
15: typedef struct fblk *FP;
16:
17: /*
18: * alloc will obtain the next available
19: * free disk block from the free list of
20: * the specified filsys.
21: * The super block has up to NICFREE remembered
22: * free blocks; the last of these is read to
23: * obtain NICFREE more . . .
24: */
25: struct buf *
26: alloc(fip, prev)
27: struct inode *fip;
28: daddr_t prev;
29: {
30: daddr_t bno;
31: register struct filsys *fp;
32: register struct buf *bp;
33: register int i, j;
34: register long *p;
35:
36: fp = getfs(fip);
37: while (fp->s_flock)
38: sleep((caddr_t)&fp->s_flock, PINOD);
39: if(BITFS(fip->i_dev)) { /* unfortunately device dependent */
40: /* this code is UGLY, fix it */
41: if(prev < fp->s_isize)
42: goto scan;
43: /* try for an acceptable free block in next
44: * three cylinders, then start over at the beginning */
45: bno = 0;
46: j = prev/(4*10);
47: j *= 4 * 10;
48: if(j < fp->s_isize)
49: j = fp->s_isize;
50: j -= fp->s_isize;
51: for(i = 0; i < 3 * 4 * 10; i++, j++) {
52: if(j >= fp->s_fsize - fp->s_isize)
53: break;
54: if(!(fp->s_bfree[j>>5] & (1 << (j&31))))
55: continue;
56: /* same cylinder? */
57: if((j+fp->s_isize)/(4*10) != prev/(4*10)) { /* take best */
58: if(bno == 0)
59: bno = j;
60: fp->s_bfree[bno>>5] &= ~(1 << (bno&31));
61: bno += fp->s_isize;
62: goto found;
63: }
64: bno = j;
65: p = fp->s_bfree + (j>>5);
66: /* same sector or next, continue */
67: if((j+fp->s_isize)%4 != prev%4 && (j+fp->s_isize)%4 != (prev+1)%4) {
68: *p &= ~(1 << (j&31));
69: bno += fp->s_isize;
70: goto found;
71: }
72: }
73: /* did we find anything? */
74: if(bno != 0) {
75: fp->s_bfree[bno>>5] &= ~(1 << (bno&31));
76: bno += fp->s_isize;
77: goto found;
78: }
79: scan:
80: p = fp->s_bfree;
81: for(i = 0; i < BITMAP && !*p; i++, p++)
82: ;
83: if(i >= BITMAP)
84: goto nospace;
85: bno = fp->s_isize + 32 * i;
86: for(j = 0; j < 32; j++) /* BITS PER LONG */
87: if(*p & (1 << j))
88: break;
89: if(j >= 32)
90: panic("alloc bitmap");
91: bno += j;
92: if(bno >= fp->s_fsize)
93: goto nospace;
94: *p &= ~(1 << j);
95: if(fp->s_valid) { /* was valid, isn't anymore */
96: fp->s_valid = 0;
97: update(); /* GROSS, but safe */
98: }
99: }
100: else {
101: do {
102: if (fp->s_nfree <= 0)
103: goto nospace;
104: if (fp->s_nfree > NICFREE) {
105: fserr(fp, "bad free count");
106: goto nospace;
107: }
108: bno = fp->s_free[--fp->s_nfree];
109: if (bno == 0)
110: goto nospace;
111: } while (badblock(fp, bno));
112: if (fp->s_nfree <= 0) {
113: fp->s_flock++;
114: bp = bread(fip->i_dev, bno);
115: if ((bp->b_flags&B_ERROR) == 0) {
116: fp->s_nfree = ((FP)(bp->b_un.b_addr))->df_nfree;
117: bcopy((caddr_t)((FP)(bp->b_un.b_addr))->df_free,
118: (caddr_t)fp->s_free, sizeof(fp->s_free));
119: }
120: brelse(bp);
121: fp->s_flock = 0;
122: wakeup((caddr_t)&fp->s_flock);
123: if (fp->s_nfree <= 0)
124: goto nospace;
125: }
126: }
127: found:
128: bp = getblk(fip->i_dev, bno);
129: clrbuf(bp);
130: fp->s_fmod = 1;
131: fp->s_tfree--;
132: return (bp);
133:
134: nospace:
135: fp->s_nfree = 0;
136: fp->s_tfree = 0;
137: fserr(fp, "file system full");
138: /* THIS IS A KLUDGE... */
139: /* SHOULD RATHER SEND A SIGNAL AND SUSPEND THE PROCESS IN A */
140: /* STATE FROM WHICH THE SYSTEM CALL WILL RESTART */
141: uprintf("\n%s: write failed, file system is full\n", fp->s_fsmnt);
142: for (i = 0; i < 5; i++)
143: sleep((caddr_t)&lbolt, PRIBIO);
144: /* END KLUDGE */
145: u.u_error = ENOSPC;
146: return (NULL);
147: }
148:
149: /*
150: * place the specified disk block
151: * back on the free list of the
152: * specified device.
153: */
154: free(fip, bno)
155: struct inode *fip;
156: daddr_t bno;
157: {
158: register struct filsys *fp;
159: register struct buf *bp;
160:
161: fp = getfs(fip);
162: fp->s_fmod = 1;
163: while (fp->s_flock)
164: sleep((caddr_t)&fp->s_flock, PINOD);
165: if (badblock(fp, bno))
166: return;
167: if(BITFS(fip->i_dev)) {
168: bno -= fp->s_isize;
169: fp->s_bfree[bno/32] |= (1 << (bno % 32));
170: if(fp->s_valid) { /* not any more */
171: fp->s_valid = 0;
172: update(); /* even GROSSER */
173: }
174: }
175: else {
176: if (fp->s_nfree <= 0) {
177: fp->s_nfree = 1;
178: fp->s_free[0] = 0;
179: }
180: if (fp->s_nfree >= NICFREE) {
181: fp->s_flock++;
182: bp = getblk(fip->i_dev, bno);
183: ((FP)(bp->b_un.b_addr))->df_nfree = fp->s_nfree;
184: bcopy((caddr_t)fp->s_free,
185: (caddr_t)((FP)(bp->b_un.b_addr))->df_free,
186: sizeof(fp->s_free));
187: fp->s_nfree = 0;
188: bwrite(bp);
189: fp->s_flock = 0;
190: wakeup((caddr_t)&fp->s_flock);
191: }
192: fp->s_free[fp->s_nfree++] = bno;
193: }
194: fp->s_tfree++;
195: fp->s_fmod = 1;
196: }
197:
198: /*
199: * Check that a block number is in the
200: * range between the I list and the size
201: * of the device.
202: * This is used mainly to check that a
203: * garbage file system has not been mounted.
204: */
205: badblock(fp, bn)
206: register struct filsys *fp;
207: daddr_t bn;
208: {
209:
210: if (bn < fp->s_isize || bn >= fp->s_fsize) {
211: fserr(fp, "bad block");
212: return(1);
213: }
214: return(0);
215: }
216:
217: /*
218: * Allocate an unused inode on the specified device.
219: * Used with file creation. The algorithm keeps up to
220: * NICINOD spare inodes in the super block. When this runs out,
221: * the inodes are searched to pick up more. We keep searching
222: * foreward on the device, remembering the number of inodes
223: * which are freed behind our search point for which there is no
224: * room in the in-core table. When this number passes a threshold
225: * (or if we search to the end of the ilist without finding any inodes)
226: * we restart the search from the beginning.
227: */
228:
229: struct inode *
230: ialloc(fip)
231: struct inode *fip;
232: {
233: register struct filsys *fp;
234: register struct buf *bp;
235: register struct inode *ip;
236: register int i;
237: struct dinode *dp;
238: ino_t ino, inobas;
239: int first;
240: daddr_t adr;
241:
242: fp = getfs(fip);
243: while (fp->s_ilock)
244: sleep((caddr_t)&fp->s_ilock, PINOD);
245: fp->s_ilock++;
246: loop:
247: if (fp->s_ninode > 0) {
248: ino = fp->s_inode[--fp->s_ninode];
249: ip = iget(fip, fip->i_dev, ino);
250: if (ip == NULL) {
251: fp->s_ilock = 0;
252: wakeup((caddr_t)&fp->s_ilock);
253: return(NULL);
254: }
255: if (ip->i_mode == 0 && ip->i_number > ROOTINO) {
256: for (i=0; i<NADDR; i++)
257: ip->i_un.i_addr[i] = 0;
258: fp->s_tinode--;
259: fp->s_fmod = 1;
260: fp->s_ilock = 0;
261: wakeup((caddr_t)&fp->s_ilock);
262: return(ip);
263: }
264: /*
265: * Inode was allocated after all.
266: * Look some more.
267: */
268: iput(ip);
269: goto loop;
270: }
271: /*
272: * If less than 4*NICINOD inodes are known
273: * to be free behind the current search point,
274: * then search forward; else search from beginning.
275: */
276: if (fp->s_nbehind < 4 * NICINOD) {
277: first = 1;
278: ino = fp->s_lasti;
279: if(ino <= ROOTINO)
280: goto fromtop;
281: if (itod(fip->i_dev, ino) >= fp->s_isize)
282: panic("ialloc");
283: adr = itod(fip->i_dev, ino);
284: } else {
285: fromtop:
286: first = 0;
287: ino = 1;
288: adr = SUPERB+1;
289: fp->s_nbehind = 0;
290: }
291: /*
292: * This is the search for free inodes.
293: */
294: for(; adr < fp->s_isize; adr++) {
295: inobas = ino;
296: bp = bread(fip->i_dev, adr);
297: if ((bp->b_flags&B_CACHE) == 0)
298: u.u_vm.vm_inblk--; /* no charge! */
299: if (bp->b_flags & B_ERROR) {
300: brelse(bp);
301: ino += INOPB(fip->i_dev);
302: continue;
303: }
304: dp = bp->b_un.b_dino;
305: for (i=0; i<INOPB(fip->i_dev); i++, ino++, dp++) {
306: if (dp->di_mode != 0 || ifind(fip, ino))
307: continue;
308: if (ino > ROOTINO)
309: fp->s_inode[fp->s_ninode++] = ino;
310: if (fp->s_ninode >= NICINOD)
311: break;
312: }
313: brelse(bp);
314: if (fp->s_ninode >= NICINOD)
315: break;
316: }
317: /*
318: * If the search didn't net a full superblock of inodes,
319: * then try it again from the beginning of the ilist.
320: */
321: if (fp->s_ninode < NICINOD && first)
322: goto fromtop;
323: fp->s_lasti = inobas;
324: fp->s_ilock = 0;
325: wakeup((caddr_t)&fp->s_ilock);
326: if (fp->s_ninode > 0)
327: goto loop;
328: fserr(fp, "out of inodes");
329: uprintf("\n%s: create failed, no inodes free\n", fp->s_fsmnt);
330: u.u_error = ENOSPC;
331: return (NULL);
332: }
333:
334: /*
335: * Free the specified inode on the specified device.
336: * The algorithm stores up to NICINOD inodes in the super
337: * block and throws away any more. It keeps track of the
338: * number of inodes thrown away which preceded the current
339: * search point in the file system. This lets us rescan
340: * for more inodes from the beginning only when there
341: * are a reasonable number of inodes back there to reallocate.
342: */
343:
344: ifree(fip, ino)
345: struct inode *fip;
346: ino_t ino;
347: {
348: register struct filsys *fp;
349:
350: if(ino <= ROOTINO)
351: return;
352: fp = getfs(fip);
353: fp->s_tinode++;
354: if (fp->s_ilock)
355: return;
356: if (fp->s_ninode >= NICINOD) {
357: if (fp->s_lasti > ino)
358: fp->s_nbehind++;
359: return;
360: }
361: fp->s_inode[fp->s_ninode++] = ino;
362: fp->s_fmod = 1;
363: }
364:
365: /*
366: * getfs maps an inode into
367: * a pointer to the incore super
368: * block.
369: * A consistency check of the
370: * in core free-block and i-node
371: * counts is performed.
372: *
373: * panic: no fs -- the device is not mounted.
374: * this "cannot happen"
375: */
376: struct filsys *
377: getfs(fip)
378: register struct inode *fip;
379: {
380: register struct filsys *fp;
381:
382: if (fip->i_fstyp != 0 || fip->i_un.i_bufp == NULL)
383: panic("no fs");
384: fp = fip->i_un.i_bufp->b_un.b_filsys;
385: if (fp->s_nfree > NICFREE || fp->s_ninode > NICINOD) {
386: fserr(fp, "bad count");
387: fp->s_nfree = 0;
388: fp->s_ninode = 0;
389: }
390: return(fp);
391: }
392:
393: /*
394: * Fserr prints the name of a file system
395: * with an error diagnostic, in the form
396: * filsys: error message
397: */
398: fserr(fp, cp)
399: struct filsys *fp;
400: char *cp;
401: {
402:
403: printf("%s: %s\n", fp->s_fsmnt, cp);
404: }
405:
406: /*
407: * Getfsx returns the index in the file system
408: * table of the specified device. The swap device
409: * is also assigned a pseudo-index. The index may
410: * be used as a compressed indication of the location
411: * of a block, recording
412: * <getfsx(dev),blkno>
413: * rather than
414: * <dev, blkno>
415: * provided the information need remain valid only
416: * as long as the file system is mounted.
417: *
418: * only the vm code calls this.
419: */
420: getfsx(dev)
421: dev_t dev;
422: {
423: register struct mount *mp;
424:
425: if (dev == swapdev)
426: return (MSWAPX);
427: mp = findmount(0, dev);
428: if (mp == NULL)
429: return (-1);
430: return (mp - &mount[0]);
431: }
432:
433: /*
434: * Update is the internal name of 'sync'. It goes through the disk
435: * queues to initiate sandbagged IO; goes through the inodes to write
436: * modified nodes; and it goes through the mount table to initiate modified
437: * super blocks.
438: */
439: update()
440: {
441: register struct inode *ip;
442:
443: if (updlock)
444: return;
445: updlock++;
446: /*
447: * Write back each (modified) inode.
448: */
449: for (ip = inode; ip < inodeNINODE; ip++)
450: if((ip->i_flag&ILOCK)==0 && ip->i_count) {
451: ip->i_flag |= ILOCK;
452: ip->i_count++;
453: iupdat(ip, &time, &time, 0);
454: iput(ip);
455: }
456: updlock = 0;
457: /*
458: * Force stale buffer cache information to be flushed,
459: * for all devices.
460: */
461: trace(TR_BFIN, updlock, 0);
462: bflush(NODEV);
463: trace(TR_BFOUT, updlock, 0);
464: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.