Commit | Line | Data |
---|---|---|
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 | */ | |
23 | iinit() | |
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 | */ | |
55 | alloc(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 | ||
85 | nospace: | |
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 | */ | |
97 | free(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 | */ | |
135 | badblock(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 | */ | |
160 | ialloc(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); | |
168 | loop: | |
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 | */ | |
224 | ifree(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 | */ | |
255 | getfs(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 | */ | |
284 | update() | |
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 | } |