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