Commit | Line | Data |
---|---|---|
6459ebe0 KM |
1 | /* ffs_inode.c 4.10 82/04/19 */ |
2 | ||
3 | /* merged into kernel: @(#)iget.c 2.2 4/8/82 */ | |
5d5124a1 BJ |
4 | |
5 | #include "../h/param.h" | |
6 | #include "../h/systm.h" | |
7 | #include "../h/mount.h" | |
8 | #include "../h/dir.h" | |
9 | #include "../h/user.h" | |
10 | #include "../h/inode.h" | |
6459ebe0 | 11 | #include "../h/fs.h" |
5d5124a1 BJ |
12 | #include "../h/conf.h" |
13 | #include "../h/buf.h" | |
14 | #include "../h/inline.h" | |
15 | ||
16 | #define INOHSZ 63 | |
17 | #define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ) | |
18 | short inohash[INOHSZ]; | |
19 | short ifreel; | |
20 | ||
21 | /* | |
22 | * Initialize hash links for inodes | |
23 | * and build inode free list. | |
24 | */ | |
25 | ihinit() | |
26 | { | |
27 | register int i; | |
75105cf0 | 28 | register struct inode *ip = inode; |
5d5124a1 BJ |
29 | |
30 | ifreel = 0; | |
75105cf0 BJ |
31 | for (i = 0; i < ninode-1; i++, ip++) |
32 | ip->i_hlink = i+1; | |
33 | ip->i_hlink = -1; | |
5d5124a1 BJ |
34 | for (i = 0; i < INOHSZ; i++) |
35 | inohash[i] = -1; | |
36 | } | |
37 | ||
5d5124a1 BJ |
38 | /* |
39 | * Look up an inode by device,inumber. | |
40 | * If it is in core (in the inode structure), | |
41 | * honor the locking protocol. | |
42 | * If it is not in core, read it in from the | |
43 | * specified device. | |
44 | * If the inode is mounted on, perform | |
45 | * the indicated indirection. | |
46 | * In all cases, a pointer to a locked | |
47 | * inode structure is returned. | |
48 | * | |
5d5124a1 BJ |
49 | * panic: no imt -- if the mounted file |
50 | * system is not in the mount table. | |
51 | * "cannot happen" | |
52 | */ | |
53 | struct inode * | |
6459ebe0 | 54 | iget(dev, fs, ino) |
7494ef16 | 55 | dev_t dev; |
6459ebe0 | 56 | register struct fs *fs; |
7494ef16 | 57 | ino_t ino; |
5d5124a1 BJ |
58 | { |
59 | register struct inode *ip; | |
60 | register struct mount *mp; | |
61 | register struct buf *bp; | |
62 | register struct dinode *dp; | |
63 | register int slot; | |
64 | ||
65 | loop: | |
6459ebe0 KM |
66 | if (getfs(dev) != fs) |
67 | panic("iget: bad fs"); | |
5d5124a1 BJ |
68 | slot = INOHASH(dev, ino); |
69 | ip = &inode[inohash[slot]]; | |
70 | while (ip != &inode[-1]) { | |
7494ef16 BJ |
71 | if (ino == ip->i_number && dev == ip->i_dev) { |
72 | if ((ip->i_flag&ILOCK) != 0) { | |
5d5124a1 BJ |
73 | ip->i_flag |= IWANT; |
74 | sleep((caddr_t)ip, PINOD); | |
75 | goto loop; | |
76 | } | |
7494ef16 | 77 | if ((ip->i_flag&IMOUNT) != 0) { |
6459ebe0 | 78 | for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) |
7494ef16 | 79 | if (mp->m_inodp == ip) { |
5d5124a1 | 80 | dev = mp->m_dev; |
6459ebe0 | 81 | fs = mp->m_bufp->b_un.b_fs; |
5d5124a1 BJ |
82 | ino = ROOTINO; |
83 | goto loop; | |
84 | } | |
85 | panic("no imt"); | |
86 | } | |
87 | ip->i_count++; | |
88 | ip->i_flag |= ILOCK; | |
89 | return(ip); | |
90 | } | |
91 | ip = &inode[ip->i_hlink]; | |
92 | } | |
7494ef16 | 93 | if (ifreel < 0) { |
945fbb1b | 94 | tablefull("inode"); |
5d5124a1 BJ |
95 | u.u_error = ENFILE; |
96 | return(NULL); | |
97 | } | |
98 | ip = &inode[ifreel]; | |
99 | ifreel = ip->i_hlink; | |
100 | ip->i_hlink = inohash[slot]; | |
101 | inohash[slot] = ip - inode; | |
102 | ip->i_dev = dev; | |
6459ebe0 | 103 | ip->i_fs = fs; |
5d5124a1 BJ |
104 | ip->i_number = ino; |
105 | ip->i_flag = ILOCK; | |
106 | ip->i_count++; | |
6459ebe0 KM |
107 | ip->i_lastr = 0; |
108 | bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize); | |
5d5124a1 BJ |
109 | /* |
110 | * Check I/O errors | |
111 | */ | |
7494ef16 | 112 | if ((bp->b_flags&B_ERROR) != 0) { |
5d5124a1 BJ |
113 | brelse(bp); |
114 | iput(ip); | |
115 | return(NULL); | |
116 | } | |
117 | dp = bp->b_un.b_dino; | |
6459ebe0 KM |
118 | dp += itoo(fs, ino); |
119 | ip->i_ic = dp->di_ic; | |
5d5124a1 | 120 | brelse(bp); |
6459ebe0 | 121 | return (ip); |
5d5124a1 BJ |
122 | } |
123 | ||
124 | /* | |
125 | * Decrement reference count of | |
126 | * an inode structure. | |
127 | * On the last reference, | |
128 | * write the inode out and if necessary, | |
129 | * truncate and deallocate the file. | |
130 | */ | |
131 | iput(ip) | |
7494ef16 | 132 | register struct inode *ip; |
5d5124a1 BJ |
133 | { |
134 | register int i, x; | |
135 | register struct inode *jp; | |
6459ebe0 | 136 | int mode; |
5d5124a1 | 137 | |
7494ef16 | 138 | if (ip->i_count == 1) { |
5d5124a1 | 139 | ip->i_flag |= ILOCK; |
7494ef16 | 140 | if (ip->i_nlink <= 0) { |
5d5124a1 | 141 | itrunc(ip); |
6459ebe0 | 142 | mode = ip->i_mode; |
5d5124a1 BJ |
143 | ip->i_mode = 0; |
144 | ip->i_flag |= IUPD|ICHG; | |
6459ebe0 | 145 | ifree(ip, ip->i_number, mode); |
5d5124a1 | 146 | } |
c0bb1685 | 147 | IUPDAT(ip, &time, &time, 0); |
7494ef16 | 148 | irele(ip); |
5d5124a1 BJ |
149 | i = INOHASH(ip->i_dev, ip->i_number); |
150 | x = ip - inode; | |
151 | if (inohash[i] == x) { | |
152 | inohash[i] = ip->i_hlink; | |
153 | } else { | |
154 | for (jp = &inode[inohash[i]]; jp != &inode[-1]; | |
155 | jp = &inode[jp->i_hlink]) | |
156 | if (jp->i_hlink == x) { | |
157 | jp->i_hlink = ip->i_hlink; | |
158 | goto done; | |
159 | } | |
160 | panic("iput"); | |
161 | } | |
162 | done: | |
163 | ip->i_hlink = ifreel; | |
164 | ifreel = x; | |
165 | ip->i_flag = 0; | |
166 | ip->i_number = 0; | |
167 | } else | |
7494ef16 | 168 | irele(ip); |
5d5124a1 BJ |
169 | ip->i_count--; |
170 | } | |
171 | ||
172 | /* | |
173 | * Check accessed and update flags on | |
174 | * an inode structure. | |
175 | * If any is on, update the inode | |
176 | * with the current time. | |
c0bb1685 BJ |
177 | * If waitfor is given, then must insure |
178 | * i/o order so wait for write to complete. | |
5d5124a1 | 179 | */ |
c0bb1685 | 180 | iupdat(ip, ta, tm, waitfor) |
7494ef16 BJ |
181 | register struct inode *ip; |
182 | time_t *ta, *tm; | |
183 | int waitfor; | |
5d5124a1 BJ |
184 | { |
185 | register struct buf *bp; | |
186 | struct dinode *dp; | |
6459ebe0 | 187 | register struct fs *fp; |
5d5124a1 | 188 | |
6459ebe0 KM |
189 | fp = ip->i_fs; |
190 | if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { | |
191 | if (fp->fs_ronly) | |
5d5124a1 | 192 | return; |
6459ebe0 KM |
193 | bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), |
194 | fp->fs_bsize); | |
5d5124a1 BJ |
195 | if (bp->b_flags & B_ERROR) { |
196 | brelse(bp); | |
197 | return; | |
198 | } | |
7494ef16 | 199 | if (ip->i_flag&IACC) |
6459ebe0 | 200 | ip->i_atime = *ta; |
7494ef16 | 201 | if (ip->i_flag&IUPD) |
6459ebe0 | 202 | ip->i_mtime = *tm; |
7494ef16 | 203 | if (ip->i_flag&ICHG) |
6459ebe0 | 204 | ip->i_ctime = time; |
5d5124a1 | 205 | ip->i_flag &= ~(IUPD|IACC|ICHG); |
6459ebe0 KM |
206 | dp = bp->b_un.b_dino + itoo(fp, ip->i_number); |
207 | dp->di_ic = ip->i_ic; | |
c0bb1685 BJ |
208 | if (waitfor) |
209 | bwrite(bp); | |
210 | else | |
211 | bdwrite(bp); | |
5d5124a1 BJ |
212 | } |
213 | } | |
214 | ||
215 | /* | |
216 | * Free all the disk blocks associated | |
217 | * with the specified inode structure. | |
218 | * The blocks of the file are removed | |
219 | * in reverse order. This FILO | |
220 | * algorithm will tend to maintain | |
221 | * a contiguous free list much longer | |
222 | * than FIFO. | |
223 | */ | |
224 | itrunc(ip) | |
7494ef16 | 225 | register struct inode *ip; |
5d5124a1 BJ |
226 | { |
227 | register i; | |
228 | dev_t dev; | |
229 | daddr_t bn; | |
c0bb1685 | 230 | struct inode itmp; |
6459ebe0 | 231 | register struct fs *fs; |
5d5124a1 | 232 | |
5d5124a1 | 233 | i = ip->i_mode & IFMT; |
6459ebe0 | 234 | if (i != IFREG && i != IFDIR && i != IFLNK) |
5d5124a1 | 235 | return; |
c0bb1685 BJ |
236 | /* |
237 | * Clean inode on disk before freeing blocks | |
238 | * to insure no duplicates if system crashes. | |
239 | */ | |
240 | itmp = *ip; | |
241 | itmp.i_size = 0; | |
6459ebe0 KM |
242 | for (i = 0; i < NDADDR; i++) |
243 | itmp.i_db[i] = 0; | |
244 | for (i = 0; i < NIADDR; i++) | |
245 | itmp.i_ib[i] = 0; | |
c0bb1685 BJ |
246 | itmp.i_flag |= ICHG|IUPD; |
247 | iupdat(&itmp, &time, &time, 1); | |
248 | ip->i_flag &= ~(IUPD|IACC|ICHG); | |
249 | ||
250 | /* | |
251 | * Now return blocks to free list... if machine | |
252 | * crashes, they will be harmless MISSING blocks. | |
253 | */ | |
5d5124a1 | 254 | dev = ip->i_dev; |
6459ebe0 KM |
255 | fs = ip->i_fs; |
256 | /* | |
257 | * release double indirect block first | |
258 | */ | |
259 | bn = ip->i_ib[NIADDR-1]; | |
260 | if (bn != (daddr_t)0) { | |
261 | ip->i_ib[NIADDR - 1] = (daddr_t)0; | |
262 | tloop(ip, bn, 1); | |
263 | } | |
264 | /* | |
265 | * release single indirect blocks second | |
266 | */ | |
267 | for (i = NIADDR - 2; i >= 0; i--) { | |
268 | bn = ip->i_ib[i]; | |
269 | if (bn != (daddr_t)0) { | |
270 | ip->i_ib[i] = (daddr_t)0; | |
271 | tloop(ip, bn, 0); | |
272 | } | |
273 | } | |
274 | /* | |
275 | * finally release direct blocks | |
276 | */ | |
277 | for (i = NDADDR - 1; i>=0; i--) { | |
278 | bn = ip->i_db[i]; | |
7494ef16 | 279 | if (bn == (daddr_t)0) |
5d5124a1 | 280 | continue; |
6459ebe0 KM |
281 | ip->i_db[i] = (daddr_t)0; |
282 | fre(ip, bn, (off_t)blksize(fs, ip, i)); | |
5d5124a1 BJ |
283 | } |
284 | ip->i_size = 0; | |
c0bb1685 BJ |
285 | /* |
286 | * Inode was written and flags updated above. | |
287 | * No need to modify flags here. | |
288 | */ | |
5d5124a1 BJ |
289 | } |
290 | ||
6459ebe0 KM |
291 | tloop(ip, bn, indflg) |
292 | register struct inode *ip; | |
293 | daddr_t bn; | |
294 | int indflg; | |
5d5124a1 BJ |
295 | { |
296 | register i; | |
297 | register struct buf *bp; | |
298 | register daddr_t *bap; | |
6459ebe0 | 299 | register struct fs *fs; |
5d5124a1 BJ |
300 | daddr_t nb; |
301 | ||
302 | bp = NULL; | |
6459ebe0 KM |
303 | fs = ip->i_fs; |
304 | for (i = NINDIR(fs) - 1; i >= 0; i--) { | |
7494ef16 | 305 | if (bp == NULL) { |
6459ebe0 | 306 | bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize); |
5d5124a1 BJ |
307 | if (bp->b_flags & B_ERROR) { |
308 | brelse(bp); | |
309 | return; | |
310 | } | |
311 | bap = bp->b_un.b_daddr; | |
312 | } | |
313 | nb = bap[i]; | |
7494ef16 | 314 | if (nb == (daddr_t)0) |
5d5124a1 | 315 | continue; |
6459ebe0 KM |
316 | if (indflg) |
317 | tloop(ip, nb, 0); | |
318 | else | |
319 | fre(ip, nb, fs->fs_bsize); | |
5d5124a1 | 320 | } |
7494ef16 | 321 | if (bp != NULL) |
5d5124a1 | 322 | brelse(bp); |
6459ebe0 | 323 | fre(ip, bn, fs->fs_bsize); |
5d5124a1 BJ |
324 | } |
325 | ||
326 | /* | |
327 | * Make a new file. | |
328 | */ | |
329 | struct inode * | |
330 | maknode(mode) | |
6459ebe0 | 331 | int mode; |
5d5124a1 BJ |
332 | { |
333 | register struct inode *ip; | |
6459ebe0 | 334 | ino_t ipref; |
5d5124a1 | 335 | |
6459ebe0 KM |
336 | if ((mode & IFMT) == IFDIR) |
337 | ipref = dirpref(u.u_pdir->i_fs); | |
338 | else | |
339 | ipref = u.u_pdir->i_number; | |
340 | ip = ialloc(u.u_pdir, ipref, mode); | |
7494ef16 | 341 | if (ip == NULL) { |
5d5124a1 BJ |
342 | iput(u.u_pdir); |
343 | return(NULL); | |
344 | } | |
345 | ip->i_flag |= IACC|IUPD|ICHG; | |
6459ebe0 | 346 | if ((mode & IFMT) == 0) |
5d5124a1 BJ |
347 | mode |= IFREG; |
348 | ip->i_mode = mode & ~u.u_cmask; | |
349 | ip->i_nlink = 1; | |
350 | ip->i_uid = u.u_uid; | |
4f4caf05 | 351 | ip->i_gid = u.u_pdir->i_gid; |
c0bb1685 BJ |
352 | |
353 | /* | |
354 | * Make sure inode goes to disk before directory entry. | |
355 | */ | |
356 | iupdat(ip, &time, &time, 1); | |
5d5124a1 | 357 | wdir(ip); |
6459ebe0 KM |
358 | if (u.u_error) { |
359 | /* | |
360 | * write error occurred trying to update directory | |
361 | * so must deallocate the inode | |
362 | */ | |
363 | ip->i_nlink = 0; | |
364 | ip->i_flag |= ICHG; | |
365 | iput(ip); | |
366 | return(NULL); | |
367 | } | |
5d5124a1 BJ |
368 | return(ip); |
369 | } | |
370 | ||
371 | /* | |
372 | * Write a directory entry with | |
373 | * parameters left as side effects | |
374 | * to a call to namei. | |
375 | */ | |
376 | wdir(ip) | |
7494ef16 | 377 | struct inode *ip; |
5d5124a1 | 378 | { |
6459ebe0 KM |
379 | register struct direct *dp, *ndp; |
380 | struct fs *fs; | |
381 | struct buf *bp; | |
382 | int lbn, bn, base; | |
383 | int loc, dsize, spccnt, newsize; | |
384 | char *dirbuf; | |
5d5124a1 BJ |
385 | |
386 | u.u_dent.d_ino = ip->i_number; | |
5d5124a1 | 387 | u.u_segflg = 1; |
6459ebe0 KM |
388 | newsize = DIRSIZ(&u.u_dent); |
389 | /* | |
390 | * if u.u_count == 0, a new directory block must be allocated. | |
391 | */ | |
392 | if (u.u_count == 0) { | |
393 | u.u_dent.d_reclen = DIRBLKSIZ; | |
394 | u.u_count = newsize; | |
395 | u.u_base = (caddr_t)&u.u_dent; | |
396 | writei(u.u_pdir); | |
397 | iput(u.u_pdir); | |
398 | return; | |
399 | } | |
400 | /* | |
401 | * must read in an existing directory block | |
402 | * to prepare to place the new entry into it. | |
403 | */ | |
404 | fs = u.u_pdir->i_fs; | |
405 | lbn = lblkno(fs, u.u_offset); | |
406 | base = blkoff(fs, u.u_offset); | |
407 | bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count)); | |
408 | if (u.u_offset + u.u_count > u.u_pdir->i_size) | |
409 | u.u_pdir->i_size = u.u_offset + u.u_count; | |
410 | bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn)); | |
411 | if (bp->b_flags & B_ERROR) { | |
412 | brelse(bp); | |
413 | return; | |
414 | } | |
415 | dirbuf = bp->b_un.b_addr + base; | |
416 | dp = (struct direct *)dirbuf; | |
417 | dsize = DIRSIZ(dp); | |
418 | spccnt = dp->d_reclen - dsize; | |
419 | /* | |
420 | * if there is insufficient room to make an entry at this point | |
421 | * namei insures that compacting from u.u_offset for u.u_count | |
422 | * bytes will provide the necessary space. | |
423 | */ | |
424 | for (loc = dp->d_reclen; loc < u.u_count; ) { | |
425 | ndp = (struct direct *)(dirbuf + loc); | |
426 | if (dp->d_ino == 0) { | |
427 | spccnt += dsize; | |
428 | } else { | |
429 | dp->d_reclen = dsize; | |
430 | dp = (struct direct *)((char *)dp + dsize); | |
431 | } | |
432 | dsize = DIRSIZ(ndp); | |
433 | spccnt += ndp->d_reclen - dsize; | |
434 | loc += ndp->d_reclen; | |
435 | bcopy(ndp, dp, dsize); | |
436 | } | |
437 | /* | |
438 | * Update the pointer fields in the previous entry (if any), | |
439 | * copy in the new entry, and write out the block. | |
440 | */ | |
441 | if (dp->d_ino == 0) { | |
442 | if (spccnt + dsize < newsize) | |
443 | panic("wdir: compact failed"); | |
444 | u.u_dent.d_reclen = spccnt + dsize; | |
445 | } else { | |
446 | if (spccnt < newsize) | |
447 | panic("wdir: compact failed"); | |
448 | u.u_dent.d_reclen = spccnt; | |
449 | dp->d_reclen = dsize; | |
450 | dp = (struct direct *)((char *)dp + dsize); | |
451 | } | |
452 | bcopy(&u.u_dent, dp, newsize); | |
453 | bwrite(bp); | |
454 | u.u_pdir->i_flag |= IUPD|ICHG; | |
5d5124a1 BJ |
455 | iput(u.u_pdir); |
456 | } | |
d6a210b8 | 457 | |
7494ef16 BJ |
458 | #ifdef ilock |
459 | #undef ilock | |
d6a210b8 | 460 | #endif |
7494ef16 BJ |
461 | #ifdef irele |
462 | #undef irele | |
d6a210b8 BJ |
463 | #endif |
464 | /* | |
7494ef16 | 465 | * Lock an inode. If its already locked, set the WANT bit and sleep. |
d6a210b8 | 466 | */ |
7494ef16 BJ |
467 | ilock(ip) |
468 | register struct inode *ip; | |
d6a210b8 BJ |
469 | { |
470 | ||
7494ef16 | 471 | while (ip->i_flag&ILOCK) { |
d6a210b8 BJ |
472 | ip->i_flag |= IWANT; |
473 | sleep((caddr_t)ip, PINOD); | |
474 | } | |
475 | ip->i_flag |= ILOCK; | |
476 | } | |
477 | ||
478 | /* | |
7494ef16 | 479 | * Unlock an inode. If WANT bit is on, wakeup. |
d6a210b8 | 480 | */ |
7494ef16 BJ |
481 | irele(ip) |
482 | register struct inode *ip; | |
d6a210b8 BJ |
483 | { |
484 | ||
485 | ip->i_flag &= ~ILOCK; | |
7494ef16 | 486 | if (ip->i_flag&IWANT) { |
d6a210b8 BJ |
487 | ip->i_flag &= ~IWANT; |
488 | wakeup((caddr_t)ip); | |
489 | } | |
490 | } |