be more paranoid about checking unallocated blocks in inodes
[unix-history] / usr / src / sys / ufs / ffs / ufs_inode.c
CommitLineData
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)
18short inohash[INOHSZ];
19short ifreel;
20
21/*
22 * Initialize hash links for inodes
23 * and build inode free list.
24 */
25ihinit()
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 */
53struct inode *
6459ebe0 54iget(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
65loop:
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 */
131iput(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
141irele(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 }
174done:
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 191iupdat(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 */
235itrunc(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
302tloop(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 */
340struct inode *
341maknode(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 */
387wdir(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
478ilock(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 492iunlock(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}