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