Bell 32V development
[unix-history] / usr / src / sys / sys / alloc.c
CommitLineData
848f4c12
TL
1#include "../h/param.h"
2#include "../h/systm.h"
3#include "../h/mount.h"
4#include "../h/filsys.h"
5#include "../h/fblk.h"
6#include "../h/conf.h"
7#include "../h/buf.h"
8#include "../h/inode.h"
9#include "../h/ino.h"
10#include "../h/dir.h"
11#include "../h/user.h"
12typedef struct fblk *FBLKP;
13
14/*
15 * alloc will obtain the next available
16 * free disk block from the free list of
17 * the specified device.
18 * The super block has up to NICFREE remembered
19 * free blocks; the last of these is read to
20 * obtain NICFREE more . . .
21 *
22 * no space on dev x/y -- when
23 * the free list is exhausted.
24 */
25struct buf *
26alloc(dev)
27dev_t dev;
28{
29 daddr_t bno;
30 register struct filsys *fp;
31 register struct buf *bp;
32
33 fp = getfs(dev);
34 while(fp->s_flock)
35 sleep((caddr_t)&fp->s_flock, PINOD);
36 do {
37 if(fp->s_nfree <= 0)
38 goto nospace;
39 if (fp->s_nfree > NICFREE) {
40 prdev("Bad free count", dev);
41 goto nospace;
42 }
43 bno = fp->s_free[--fp->s_nfree];
44 if(bno == 0)
45 goto nospace;
46 } while (badblock(fp, bno, dev));
47 if(fp->s_nfree <= 0) {
48 fp->s_flock++;
49 bp = bread(dev, bno);
50 if ((bp->b_flags&B_ERROR) == 0) {
51 fp->s_nfree = ((FBLKP)(bp->b_un.b_addr))->df_nfree;
52 bcopy((caddr_t)((FBLKP)(bp->b_un.b_addr))->df_free,
53 (caddr_t)fp->s_free, sizeof(fp->s_free));
54 }
55 brelse(bp);
56 fp->s_flock = 0;
57 wakeup((caddr_t)&fp->s_flock);
58 if (fp->s_nfree <=0)
59 goto nospace;
60 }
61 bp = getblk(dev, bno);
62 clrbuf(bp);
63 fp->s_fmod = 1;
64 return(bp);
65
66nospace:
67 fp->s_nfree = 0;
68 prdev("no space", dev);
69 u.u_error = ENOSPC;
70 return(NULL);
71}
72
73/*
74 * place the specified disk block
75 * back on the free list of the
76 * specified device.
77 */
78free(dev, bno)
79dev_t dev;
80daddr_t bno;
81{
82 register struct filsys *fp;
83 register struct buf *bp;
84
85 fp = getfs(dev);
86 fp->s_fmod = 1;
87 while(fp->s_flock)
88 sleep((caddr_t)&fp->s_flock, PINOD);
89 if (badblock(fp, bno, dev))
90 return;
91 if(fp->s_nfree <= 0) {
92 fp->s_nfree = 1;
93 fp->s_free[0] = 0;
94 }
95 if(fp->s_nfree >= NICFREE) {
96 fp->s_flock++;
97 bp = getblk(dev, bno);
98 ((FBLKP)(bp->b_un.b_addr))->df_nfree = fp->s_nfree;
99 bcopy((caddr_t)fp->s_free,
100 (caddr_t)((FBLKP)(bp->b_un.b_addr))->df_free,
101 sizeof(fp->s_free));
102 fp->s_nfree = 0;
103 bwrite(bp);
104 fp->s_flock = 0;
105 wakeup((caddr_t)&fp->s_flock);
106 }
107 fp->s_free[fp->s_nfree++] = bno;
108 fp->s_fmod = 1;
109}
110
111/*
112 * Check that a block number is in the
113 * range between the I list and the size
114 * of the device.
115 * This is used mainly to check that a
116 * garbage file system has not been mounted.
117 *
118 * bad block on dev x/y -- not in range
119 */
120badblock(fp, bn, dev)
121register struct filsys *fp;
122daddr_t bn;
123dev_t dev;
124{
125
126 if (bn < fp->s_isize || bn >= fp->s_fsize) {
127 prdev("bad block", dev);
128 return(1);
129 }
130 return(0);
131}
132
133/*
134 * Allocate an unused I node
135 * on the specified device.
136 * Used with file creation.
137 * The algorithm keeps up to
138 * NICINOD spare I nodes in the
139 * super block. When this runs out,
140 * a linear search through the
141 * I list is instituted to pick
142 * up NICINOD more.
143 */
144struct inode *
145ialloc(dev)
146dev_t dev;
147{
148 register struct filsys *fp;
149 register struct buf *bp;
150 register struct inode *ip;
151 int i;
152 struct dinode *dp;
153 ino_t ino;
154 daddr_t adr;
155
156 fp = getfs(dev);
157 while(fp->s_ilock)
158 sleep((caddr_t)&fp->s_ilock, PINOD);
159loop:
160 if(fp->s_ninode > 0) {
161 ino = fp->s_inode[--fp->s_ninode];
162 ip = iget(dev, ino);
163 if(ip == NULL)
164 return(NULL);
165 if(ip->i_mode == 0) {
166 for (i=0; i<NADDR; i++)
167 ip->i_un.i_addr[i] = 0;
168 fp->s_fmod = 1;
169 return(ip);
170 }
171 /*
172 * Inode was allocated after all.
173 * Look some more.
174 */
175 iput(ip);
176 goto loop;
177 }
178 fp->s_ilock++;
179 ino = 1;
180 for(adr = SUPERB+1; adr < fp->s_isize; adr++) {
181 bp = bread(dev, adr);
182 if (bp->b_flags & B_ERROR) {
183 brelse(bp);
184 ino += INOPB;
185 continue;
186 }
187 dp = bp->b_un.b_dino;
188 for(i=0; i<INOPB; i++) {
189 if(dp->di_mode != 0)
190 goto cont;
191 for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
192 if(dev==ip->i_dev && ino==ip->i_number)
193 goto cont;
194 fp->s_inode[fp->s_ninode++] = ino;
195 if(fp->s_ninode >= NICINOD)
196 break;
197 cont:
198 ino++;
199 dp++;
200 }
201 brelse(bp);
202 if(fp->s_ninode >= NICINOD)
203 break;
204 }
205 fp->s_ilock = 0;
206 wakeup((caddr_t)&fp->s_ilock);
207 if(fp->s_ninode > 0)
208 goto loop;
209 prdev("Out of inodes", dev);
210 u.u_error = ENOSPC;
211 return(NULL);
212}
213
214/*
215 * Free the specified I node
216 * on the specified device.
217 * The algorithm stores up
218 * to NICINOD I nodes in the super
219 * block and throws away any more.
220 */
221ifree(dev, ino)
222dev_t dev;
223ino_t ino;
224{
225 register struct filsys *fp;
226
227 fp = getfs(dev);
228 if(fp->s_ilock)
229 return;
230 if(fp->s_ninode >= NICINOD)
231 return;
232 fp->s_inode[fp->s_ninode++] = ino;
233 fp->s_fmod = 1;
234}
235
236/*
237 * getfs maps a device number into
238 * a pointer to the incore super
239 * block.
240 * The algorithm is a linear
241 * search through the mount table.
242 * A consistency check of the
243 * in core free-block and i-node
244 * counts.
245 *
246 * bad count on dev x/y -- the count
247 * check failed. At this point, all
248 * the counts are zeroed which will
249 * almost certainly lead to "no space"
250 * diagnostic
251 * panic: no fs -- the device is not mounted.
252 * this "cannot happen"
253 */
254struct filsys *
255getfs(dev)
256dev_t dev;
257{
258 register struct mount *mp;
259 register struct filsys *fp;
260
261 for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
262 if(mp->m_bufp != NULL && mp->m_dev == dev) {
263 fp = mp->m_bufp->b_un.b_filsys;
264 if(fp->s_nfree > NICFREE || fp->s_ninode > NICINOD) {
265 prdev("bad count", dev);
266 fp->s_nfree = 0;
267 fp->s_ninode = 0;
268 }
269 return(fp);
270 }
271 panic("no fs");
272 return(NULL);
273}
274
275/*
276 * update is the internal name of
277 * 'sync'. It goes through the disk
278 * queues to initiate sandbagged IO;
279 * goes through the I nodes to write
280 * modified nodes; and it goes through
281 * the mount table to initiate modified
282 * super blocks.
283 */
284update()
285{
286 register struct inode *ip;
287 register struct mount *mp;
288 register struct buf *bp;
289 struct filsys *fp;
290
291 if(updlock)
292 return;
293 updlock++;
294 for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
295 if(mp->m_bufp != NULL) {
296 fp = mp->m_bufp->b_un.b_filsys;
297 if(fp->s_fmod==0 || fp->s_ilock!=0 ||
298 fp->s_flock!=0 || fp->s_ronly!=0)
299 continue;
300 bp = getblk(mp->m_dev, SUPERB);
301 if (bp->b_flags & B_ERROR)
302 continue;
303 fp->s_fmod = 0;
304 fp->s_time = time;
305 bcopy((caddr_t)fp, bp->b_un.b_addr, BSIZE);
306 bwrite(bp);
307 }
308 for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
309 if((ip->i_flag&ILOCK)==0 && ip->i_count) {
310 ip->i_flag |= ILOCK;
311 ip->i_count++;
312 iupdat(ip, &time, &time);
313 iput(ip);
314 }
315 updlock = 0;
316 bflush(NODEV);
317}