Commit | Line | Data |
---|---|---|
ff56f48a | 1 | /* ufs_inode.c 4.11 82/06/07 */ |
6459ebe0 KM |
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 | 133 | { |
ff56f48a KM |
134 | |
135 | if ((ip->i_flag & ILOCK) == 0) | |
136 | panic("iput"); | |
137 | iunlock(ip); | |
138 | irele(ip); | |
139 | } | |
140 | ||
141 | irele(ip) | |
142 | register struct inode *ip; | |
143 | { | |
5d5124a1 BJ |
144 | register int i, x; |
145 | register struct inode *jp; | |
6459ebe0 | 146 | int mode; |
5d5124a1 | 147 | |
ff56f48a KM |
148 | if (ip->i_flag & ILOCK) |
149 | panic("irele"); | |
7494ef16 | 150 | if (ip->i_count == 1) { |
5d5124a1 | 151 | ip->i_flag |= ILOCK; |
7494ef16 | 152 | if (ip->i_nlink <= 0) { |
5d5124a1 | 153 | itrunc(ip); |
6459ebe0 | 154 | mode = ip->i_mode; |
5d5124a1 BJ |
155 | ip->i_mode = 0; |
156 | ip->i_flag |= IUPD|ICHG; | |
6459ebe0 | 157 | ifree(ip, ip->i_number, mode); |
5d5124a1 | 158 | } |
c0bb1685 | 159 | IUPDAT(ip, &time, &time, 0); |
ff56f48a | 160 | iunlock(ip); |
5d5124a1 BJ |
161 | i = INOHASH(ip->i_dev, ip->i_number); |
162 | x = ip - inode; | |
163 | if (inohash[i] == x) { | |
164 | inohash[i] = ip->i_hlink; | |
165 | } else { | |
166 | for (jp = &inode[inohash[i]]; jp != &inode[-1]; | |
167 | jp = &inode[jp->i_hlink]) | |
168 | if (jp->i_hlink == x) { | |
169 | jp->i_hlink = ip->i_hlink; | |
170 | goto done; | |
171 | } | |
172 | panic("iput"); | |
173 | } | |
174 | done: | |
175 | ip->i_hlink = ifreel; | |
176 | ifreel = x; | |
177 | ip->i_flag = 0; | |
178 | ip->i_number = 0; | |
ff56f48a | 179 | } |
5d5124a1 BJ |
180 | ip->i_count--; |
181 | } | |
182 | ||
183 | /* | |
184 | * Check accessed and update flags on | |
185 | * an inode structure. | |
186 | * If any is on, update the inode | |
187 | * with the current time. | |
c0bb1685 BJ |
188 | * If waitfor is given, then must insure |
189 | * i/o order so wait for write to complete. | |
5d5124a1 | 190 | */ |
c0bb1685 | 191 | iupdat(ip, ta, tm, waitfor) |
7494ef16 BJ |
192 | register struct inode *ip; |
193 | time_t *ta, *tm; | |
194 | int waitfor; | |
5d5124a1 BJ |
195 | { |
196 | register struct buf *bp; | |
197 | struct dinode *dp; | |
6459ebe0 | 198 | register struct fs *fp; |
5d5124a1 | 199 | |
6459ebe0 KM |
200 | fp = ip->i_fs; |
201 | if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { | |
202 | if (fp->fs_ronly) | |
5d5124a1 | 203 | return; |
6459ebe0 KM |
204 | bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), |
205 | fp->fs_bsize); | |
5d5124a1 BJ |
206 | if (bp->b_flags & B_ERROR) { |
207 | brelse(bp); | |
208 | return; | |
209 | } | |
7494ef16 | 210 | if (ip->i_flag&IACC) |
6459ebe0 | 211 | ip->i_atime = *ta; |
7494ef16 | 212 | if (ip->i_flag&IUPD) |
6459ebe0 | 213 | ip->i_mtime = *tm; |
7494ef16 | 214 | if (ip->i_flag&ICHG) |
6459ebe0 | 215 | ip->i_ctime = time; |
5d5124a1 | 216 | ip->i_flag &= ~(IUPD|IACC|ICHG); |
6459ebe0 KM |
217 | dp = bp->b_un.b_dino + itoo(fp, ip->i_number); |
218 | dp->di_ic = ip->i_ic; | |
c0bb1685 BJ |
219 | if (waitfor) |
220 | bwrite(bp); | |
221 | else | |
222 | bdwrite(bp); | |
5d5124a1 BJ |
223 | } |
224 | } | |
225 | ||
226 | /* | |
227 | * Free all the disk blocks associated | |
228 | * with the specified inode structure. | |
229 | * The blocks of the file are removed | |
230 | * in reverse order. This FILO | |
231 | * algorithm will tend to maintain | |
232 | * a contiguous free list much longer | |
233 | * than FIFO. | |
234 | */ | |
235 | itrunc(ip) | |
7494ef16 | 236 | register struct inode *ip; |
5d5124a1 BJ |
237 | { |
238 | register i; | |
239 | dev_t dev; | |
240 | daddr_t bn; | |
c0bb1685 | 241 | struct inode itmp; |
6459ebe0 | 242 | register struct fs *fs; |
5d5124a1 | 243 | |
5d5124a1 | 244 | i = ip->i_mode & IFMT; |
6459ebe0 | 245 | if (i != IFREG && i != IFDIR && i != IFLNK) |
5d5124a1 | 246 | return; |
c0bb1685 BJ |
247 | /* |
248 | * Clean inode on disk before freeing blocks | |
249 | * to insure no duplicates if system crashes. | |
250 | */ | |
251 | itmp = *ip; | |
252 | itmp.i_size = 0; | |
6459ebe0 KM |
253 | for (i = 0; i < NDADDR; i++) |
254 | itmp.i_db[i] = 0; | |
255 | for (i = 0; i < NIADDR; i++) | |
256 | itmp.i_ib[i] = 0; | |
c0bb1685 BJ |
257 | itmp.i_flag |= ICHG|IUPD; |
258 | iupdat(&itmp, &time, &time, 1); | |
259 | ip->i_flag &= ~(IUPD|IACC|ICHG); | |
260 | ||
261 | /* | |
262 | * Now return blocks to free list... if machine | |
263 | * crashes, they will be harmless MISSING blocks. | |
264 | */ | |
5d5124a1 | 265 | dev = ip->i_dev; |
6459ebe0 KM |
266 | fs = ip->i_fs; |
267 | /* | |
268 | * release double indirect block first | |
269 | */ | |
270 | bn = ip->i_ib[NIADDR-1]; | |
271 | if (bn != (daddr_t)0) { | |
272 | ip->i_ib[NIADDR - 1] = (daddr_t)0; | |
273 | tloop(ip, bn, 1); | |
274 | } | |
275 | /* | |
276 | * release single indirect blocks second | |
277 | */ | |
278 | for (i = NIADDR - 2; i >= 0; i--) { | |
279 | bn = ip->i_ib[i]; | |
280 | if (bn != (daddr_t)0) { | |
281 | ip->i_ib[i] = (daddr_t)0; | |
282 | tloop(ip, bn, 0); | |
283 | } | |
284 | } | |
285 | /* | |
286 | * finally release direct blocks | |
287 | */ | |
288 | for (i = NDADDR - 1; i>=0; i--) { | |
289 | bn = ip->i_db[i]; | |
7494ef16 | 290 | if (bn == (daddr_t)0) |
5d5124a1 | 291 | continue; |
6459ebe0 KM |
292 | ip->i_db[i] = (daddr_t)0; |
293 | fre(ip, bn, (off_t)blksize(fs, ip, i)); | |
5d5124a1 BJ |
294 | } |
295 | ip->i_size = 0; | |
c0bb1685 BJ |
296 | /* |
297 | * Inode was written and flags updated above. | |
298 | * No need to modify flags here. | |
299 | */ | |
5d5124a1 BJ |
300 | } |
301 | ||
6459ebe0 KM |
302 | tloop(ip, bn, indflg) |
303 | register struct inode *ip; | |
304 | daddr_t bn; | |
305 | int indflg; | |
5d5124a1 BJ |
306 | { |
307 | register i; | |
308 | register struct buf *bp; | |
309 | register daddr_t *bap; | |
6459ebe0 | 310 | register struct fs *fs; |
5d5124a1 BJ |
311 | daddr_t nb; |
312 | ||
313 | bp = NULL; | |
6459ebe0 KM |
314 | fs = ip->i_fs; |
315 | for (i = NINDIR(fs) - 1; i >= 0; i--) { | |
7494ef16 | 316 | if (bp == NULL) { |
6459ebe0 | 317 | bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize); |
5d5124a1 BJ |
318 | if (bp->b_flags & B_ERROR) { |
319 | brelse(bp); | |
320 | return; | |
321 | } | |
322 | bap = bp->b_un.b_daddr; | |
323 | } | |
324 | nb = bap[i]; | |
7494ef16 | 325 | if (nb == (daddr_t)0) |
5d5124a1 | 326 | continue; |
6459ebe0 KM |
327 | if (indflg) |
328 | tloop(ip, nb, 0); | |
329 | else | |
330 | fre(ip, nb, fs->fs_bsize); | |
5d5124a1 | 331 | } |
7494ef16 | 332 | if (bp != NULL) |
5d5124a1 | 333 | brelse(bp); |
6459ebe0 | 334 | fre(ip, bn, fs->fs_bsize); |
5d5124a1 BJ |
335 | } |
336 | ||
337 | /* | |
338 | * Make a new file. | |
339 | */ | |
340 | struct inode * | |
341 | maknode(mode) | |
6459ebe0 | 342 | int mode; |
5d5124a1 BJ |
343 | { |
344 | register struct inode *ip; | |
6459ebe0 | 345 | ino_t ipref; |
5d5124a1 | 346 | |
6459ebe0 KM |
347 | if ((mode & IFMT) == IFDIR) |
348 | ipref = dirpref(u.u_pdir->i_fs); | |
349 | else | |
350 | ipref = u.u_pdir->i_number; | |
351 | ip = ialloc(u.u_pdir, ipref, mode); | |
7494ef16 | 352 | if (ip == NULL) { |
5d5124a1 BJ |
353 | iput(u.u_pdir); |
354 | return(NULL); | |
355 | } | |
356 | ip->i_flag |= IACC|IUPD|ICHG; | |
6459ebe0 | 357 | if ((mode & IFMT) == 0) |
5d5124a1 BJ |
358 | mode |= IFREG; |
359 | ip->i_mode = mode & ~u.u_cmask; | |
360 | ip->i_nlink = 1; | |
361 | ip->i_uid = u.u_uid; | |
4f4caf05 | 362 | ip->i_gid = u.u_pdir->i_gid; |
c0bb1685 BJ |
363 | |
364 | /* | |
365 | * Make sure inode goes to disk before directory entry. | |
366 | */ | |
367 | iupdat(ip, &time, &time, 1); | |
5d5124a1 | 368 | wdir(ip); |
6459ebe0 KM |
369 | if (u.u_error) { |
370 | /* | |
371 | * write error occurred trying to update directory | |
372 | * so must deallocate the inode | |
373 | */ | |
374 | ip->i_nlink = 0; | |
375 | ip->i_flag |= ICHG; | |
376 | iput(ip); | |
377 | return(NULL); | |
378 | } | |
5d5124a1 BJ |
379 | return(ip); |
380 | } | |
381 | ||
382 | /* | |
383 | * Write a directory entry with | |
384 | * parameters left as side effects | |
385 | * to a call to namei. | |
386 | */ | |
387 | wdir(ip) | |
7494ef16 | 388 | struct inode *ip; |
5d5124a1 | 389 | { |
6459ebe0 KM |
390 | register struct direct *dp, *ndp; |
391 | struct fs *fs; | |
392 | struct buf *bp; | |
393 | int lbn, bn, base; | |
394 | int loc, dsize, spccnt, newsize; | |
395 | char *dirbuf; | |
5d5124a1 BJ |
396 | |
397 | u.u_dent.d_ino = ip->i_number; | |
5d5124a1 | 398 | u.u_segflg = 1; |
6459ebe0 KM |
399 | newsize = DIRSIZ(&u.u_dent); |
400 | /* | |
401 | * if u.u_count == 0, a new directory block must be allocated. | |
402 | */ | |
403 | if (u.u_count == 0) { | |
404 | u.u_dent.d_reclen = DIRBLKSIZ; | |
405 | u.u_count = newsize; | |
406 | u.u_base = (caddr_t)&u.u_dent; | |
407 | writei(u.u_pdir); | |
408 | iput(u.u_pdir); | |
409 | return; | |
410 | } | |
411 | /* | |
412 | * must read in an existing directory block | |
413 | * to prepare to place the new entry into it. | |
414 | */ | |
415 | fs = u.u_pdir->i_fs; | |
416 | lbn = lblkno(fs, u.u_offset); | |
417 | base = blkoff(fs, u.u_offset); | |
418 | bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count)); | |
419 | if (u.u_offset + u.u_count > u.u_pdir->i_size) | |
420 | u.u_pdir->i_size = u.u_offset + u.u_count; | |
421 | bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn)); | |
422 | if (bp->b_flags & B_ERROR) { | |
423 | brelse(bp); | |
424 | return; | |
425 | } | |
426 | dirbuf = bp->b_un.b_addr + base; | |
427 | dp = (struct direct *)dirbuf; | |
428 | dsize = DIRSIZ(dp); | |
429 | spccnt = dp->d_reclen - dsize; | |
430 | /* | |
431 | * if there is insufficient room to make an entry at this point | |
432 | * namei insures that compacting from u.u_offset for u.u_count | |
433 | * bytes will provide the necessary space. | |
434 | */ | |
435 | for (loc = dp->d_reclen; loc < u.u_count; ) { | |
436 | ndp = (struct direct *)(dirbuf + loc); | |
437 | if (dp->d_ino == 0) { | |
438 | spccnt += dsize; | |
439 | } else { | |
440 | dp->d_reclen = dsize; | |
441 | dp = (struct direct *)((char *)dp + dsize); | |
442 | } | |
443 | dsize = DIRSIZ(ndp); | |
444 | spccnt += ndp->d_reclen - dsize; | |
445 | loc += ndp->d_reclen; | |
446 | bcopy(ndp, dp, dsize); | |
447 | } | |
448 | /* | |
449 | * Update the pointer fields in the previous entry (if any), | |
450 | * copy in the new entry, and write out the block. | |
451 | */ | |
452 | if (dp->d_ino == 0) { | |
453 | if (spccnt + dsize < newsize) | |
454 | panic("wdir: compact failed"); | |
455 | u.u_dent.d_reclen = spccnt + dsize; | |
456 | } else { | |
457 | if (spccnt < newsize) | |
458 | panic("wdir: compact failed"); | |
459 | u.u_dent.d_reclen = spccnt; | |
460 | dp->d_reclen = dsize; | |
461 | dp = (struct direct *)((char *)dp + dsize); | |
462 | } | |
463 | bcopy(&u.u_dent, dp, newsize); | |
464 | bwrite(bp); | |
465 | u.u_pdir->i_flag |= IUPD|ICHG; | |
5d5124a1 BJ |
466 | iput(u.u_pdir); |
467 | } | |
d6a210b8 | 468 | |
7494ef16 BJ |
469 | #ifdef ilock |
470 | #undef ilock | |
d6a210b8 | 471 | #endif |
ff56f48a KM |
472 | #ifdef iunlock |
473 | #undef iunlock | |
d6a210b8 BJ |
474 | #endif |
475 | /* | |
7494ef16 | 476 | * Lock an inode. If its already locked, set the WANT bit and sleep. |
d6a210b8 | 477 | */ |
7494ef16 BJ |
478 | ilock(ip) |
479 | register struct inode *ip; | |
d6a210b8 BJ |
480 | { |
481 | ||
7494ef16 | 482 | while (ip->i_flag&ILOCK) { |
d6a210b8 BJ |
483 | ip->i_flag |= IWANT; |
484 | sleep((caddr_t)ip, PINOD); | |
485 | } | |
486 | ip->i_flag |= ILOCK; | |
487 | } | |
488 | ||
489 | /* | |
7494ef16 | 490 | * Unlock an inode. If WANT bit is on, wakeup. |
d6a210b8 | 491 | */ |
ff56f48a | 492 | iunlock(ip) |
7494ef16 | 493 | register struct inode *ip; |
d6a210b8 BJ |
494 | { |
495 | ||
496 | ip->i_flag &= ~ILOCK; | |
7494ef16 | 497 | if (ip->i_flag&IWANT) { |
d6a210b8 BJ |
498 | ip->i_flag &= ~IWANT; |
499 | wakeup((caddr_t)ip); | |
500 | } | |
501 | } |